1Pay API Documentation
Accept payments from anywhere in Africa. Mobile money, cards, bank transfers, and crypto — all through one API.
https://your-domain.com/api/v1All requests must be made over HTTPS. Calls over plain HTTP will be rejected.
Quick Start
Get your first payment in 3 steps:
-
Get your API key
Sign up at 1pay.app, then go to Settings → API Keys and create a key. Keep it secret.
-
Create a payment
Send a POST request to create a payment session:
bashcurl -X POST https://1pay.s.co.tz/api/v1/payments \ -H "Authorization: Bearer sk_live_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "amount": 50000, "currency": "TZS", "method": "mobile_money", "customer_phone": "+255712345678", "customer_name": "John Doe", "description": "Order #1234" }' -
Handle the response
You'll get back a payment object with a status. For mobile money, the customer receives an STK push on their phone.
json{ "success": true, "data": { "id": 1, "reference": "PAY-2026-XXXXX", "amount": 50000, "currency": "TZS", "status": "pending", "payment_type": "mobile", "provider": "daraja" } }
Authentication
Authenticate with your API key via the Authorization header:
Authorization: Bearer sk_live_your_api_key
API keys come in two types:
| Key Prefix | Environment | Description |
|---|---|---|
sk_live_ | Production | Processes real payments with real money |
sk_test_ | Sandbox | Test mode — no real money moves |
Environments
| Environment | Base URL | Description |
|---|---|---|
| Sandbox | https://1pay.s.co.tz/api/v1 | Test with dummy credentials |
| Production | https://1pay.s.co.tz/api/v1 | Live with real provider keys |
Switch environments by using sk_test_ or sk_live_ API keys. The base URL stays the same.
Create Payment
Creates a new payment. The customer will be prompted to complete payment via the selected method.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in smallest currency unit (e.g., cents). 50000 = TSh 50,000 |
currency | string | No | ISO 4217 currency code. Default: TZS |
method | string | No | mobile_money, card, crypto, or dynamic_qr |
customer_phone | string | Conditional | Required for mobile money. E.164 format |
customer_name | string | No | Customer's full name |
customer_email | string | No | Customer's email |
description | string | No | Payment description shown to customer |
reference | string | No | Your unique reference. Auto-generated if not provided |
webhook_url | string | No | Override webhook URL for this payment |
redirect_url | string | No | URL to redirect after payment |
metadata | object | No | Arbitrary JSON data stored with the payment |
Example
<?php
$response = file_get_contents('https://your-domain.com/api/v1/payments', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Authorization: Bearer sk_live_your_key\r\nContent-Type: application/json",
'content' => json_encode([
'amount' => 50000,
'currency' => 'TZS',
'method' => 'mobile_money',
'customer_phone' => '+255712345678',
'customer_name' => 'John Doe',
]),
],
]));
$data = json_decode($response, true);
echo $data['data']['reference'];
Get Payment
Retrieve the details and current status of a payment.
Response
{
"success": true,
"data": {
"id": 1,
"reference": "PAY-2026-XXXXX",
"amount": 50000,
"net_amount": 47500,
"fees": 2500,
"currency": "TZS",
"status": "completed",
"payment_type": "mobile",
"channel_provider": "daraja",
"customer_name": "John Doe",
"customer_phone": "+255712345678",
"created_at": "2026-07-18T10:30:00Z"
}
}
List Payments
List all payments with optional filters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: pending, completed, failed |
payment_type | string | Filter by type: mobile, card, crypto, dynamic-qr |
from | string | Start date (YYYY-MM-DD) |
to | string | End date (YYYY-MM-DD) |
page | integer | Page number (default: 1) |
per_page | integer | Results per page (default: 25, max: 100) |
Create Payout
Send money to a mobile money account or bank. Requires sufficient balance in your merchant account.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount to send |
currency | string | No | Default: TZS |
recipient_phone | string | Yes | Recipient phone (E.164) |
recipient_name | string | No | Recipient name |
reference | string | No | Your unique reference |
narration | string | No | Payment description |
Get Payout
Retrieve payout details and status.
List Payouts
List all payouts with optional filters (same as payments list).
Mobile Money
Accept mobile money payments via M-Pesa, Airtel Money, Tigo Pesa, and Halotel across East Africa.
How it works
- Customer enters their phone number on the checkout page
- An STK push (prompt) is sent to their phone
- Customer enters their PIN to confirm
- Payment is confirmed via webhook
Card Payments
Accept Visa and Mastercard payments from anywhere in the world.
Flow
- Customer enters card details on the secure checkout page
- For 3D Secure cards, customer is redirected to their bank's verification page
- After verification, payment is processed and confirmed
payment_url in the response handles this redirect automatically.
Cryptocurrency
Accept Bitcoin, Ethereum, USDT, Litecoin, and Dogecoin payments with automatic conversion.
Supported Coins
| Coin | Network | Confirmations |
|---|---|---|
| BTC | Bitcoin | 2 |
| ETH | Ethereum (ERC-20) | 12 |
| USDT | TRC-20 / ERC-20 | 1 |
| LTC | Litecoin | 3 |
| DOGE | Dogecoin | 3 |
Flow
- Customer selects cryptocurrency and coin type
- A unique wallet address and amount are generated via NOWPayments
- Customer sends the exact amount to the address
- Blockchain monitoring detects the transaction and confirms after required block confirmations
QR Code Payments
Generate dynamic QR codes that customers can scan with any mobile wallet.
QR payments work with any mobile wallet that supports QR scanning (M-Pesa, Airtel Money, etc.).
Webhooks
1Pay sends webhooks to notify your server when payment events occur.
Webhook Payload
{
"event": "payment.completed",
"data": {
"id": 1,
"reference": "PAY-2026-XXXXX",
"amount": 50000,
"net_amount": 47500,
"fee": 2500,
"currency": "TZS",
"status": "completed",
"payment_type": "mobile",
"customer_name": "John Doe",
"customer_phone": "+255712345678",
"session_token": "abc123...",
"created_at": "2026-07-18T10:30:00Z"
}
}
Verifying Webhooks
Every webhook includes an X-Webhook-Signature header. Verify it using HMAC-SHA256:
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $payload, $webhook_secret);
if (!hash_equals($expected, $signature)) {
// Invalid signature — reject
http_response_code(403);
exit;
}
$event = json_decode($payload, true);
// Process event...
Events
| Event | Description |
|---|---|
payment.completed | Payment was successfully completed |
payment.failed | Payment attempt failed |
payout.completed | Payout was sent successfully |
payout.failed | Payout attempt failed |
Error Handling
1Pay uses standard HTTP status codes. Errors return a JSON body:
{
"success": false,
"error": "Invalid API key"
}
| Status | Meaning |
|---|---|
200 | Success |
400 | Bad request — missing or invalid parameters |
401 | Unauthorized — invalid or missing API key |
403 | Forbidden — CSRF or IP restriction |
404 | Not found — resource doesn't exist |
429 | Rate limited — too many requests |
500 | Server error — retry later |
SDKs & Libraries
Official client libraries coming soon. For now, use any HTTP client:
const response = await fetch('https://your-domain.com/api/v1/payments', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 50000,
currency: 'TZS',
method: 'mobile_money',
customer_phone: '+255712345678',
}),
});
const data = await response.json();
console.log(data);
Rate Limits
API requests are limited to prevent abuse:
| Endpoint | Limit | Window |
|---|---|---|
| Payment creation | 10 requests | Per token per 5 minutes |
| General API | 100 requests | Per minute per API key |
| Webhook delivery | 5 retries | Exponential backoff |
X-RateLimit-Remaining,
X-RateLimit-Limit,
X-RateLimit-Reset.
Questions? Contact us at support@1pay.app or visit 1pay.app