1Pay API Documentation

Accept payments from anywhere in Africa. Mobile money, cards, bank transfers, and crypto — all through one API.

Base URL: https://your-domain.com/api/v1
All requests must be made over HTTPS. Calls over plain HTTP will be rejected.

Quick Start

Get your first payment in 3 steps:

  1. Get your API key

    Sign up at 1pay.app, then go to Settings → API Keys and create a key. Keep it secret.

  2. Create a payment

    Send a POST request to create a payment session:

    bash
    curl -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"
      }'
  3. 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:

http
Authorization: Bearer sk_live_your_api_key

API keys come in two types:

Key PrefixEnvironmentDescription
sk_live_ProductionProcesses real payments with real money
sk_test_SandboxTest mode — no real money moves
Keep your keys secret. Never expose them in client-side code, public repos, or logs. If compromised, revoke immediately from your dashboard.

Environments

EnvironmentBase URLDescription
Sandboxhttps://1pay.s.co.tz/api/v1Test with dummy credentials
Productionhttps://1pay.s.co.tz/api/v1Live with real provider keys

Switch environments by using sk_test_ or sk_live_ API keys. The base URL stays the same.

Create Payment

POST /api/v1/payments

Creates a new payment. The customer will be prompted to complete payment via the selected method.

Request Body

ParameterTypeRequiredDescription
amountintegerYesAmount in smallest currency unit (e.g., cents). 50000 = TSh 50,000
currencystringNoISO 4217 currency code. Default: TZS
methodstringNomobile_money, card, crypto, or dynamic_qr
customer_phonestringConditionalRequired for mobile money. E.164 format
customer_namestringNoCustomer's full name
customer_emailstringNoCustomer's email
descriptionstringNoPayment description shown to customer
referencestringNoYour unique reference. Auto-generated if not provided
webhook_urlstringNoOverride webhook URL for this payment
redirect_urlstringNoURL to redirect after payment
metadataobjectNoArbitrary JSON data stored with the payment

Example

php
<?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

GET /api/v1/payments/{id}

Retrieve the details and current status of a payment.

Response

json
{
  "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

GET /api/v1/payments

List all payments with optional filters.

Query Parameters

ParameterTypeDescription
statusstringFilter by status: pending, completed, failed
payment_typestringFilter by type: mobile, card, crypto, dynamic-qr
fromstringStart date (YYYY-MM-DD)
tostringEnd date (YYYY-MM-DD)
pageintegerPage number (default: 1)
per_pageintegerResults per page (default: 25, max: 100)

Create Payout

POST /api/v1/payouts

Send money to a mobile money account or bank. Requires sufficient balance in your merchant account.

Request Body

ParameterTypeRequiredDescription
amountintegerYesAmount to send
currencystringNoDefault: TZS
recipient_phonestringYesRecipient phone (E.164)
recipient_namestringNoRecipient name
referencestringNoYour unique reference
narrationstringNoPayment description

Get Payout

GET /api/v1/payouts/{id}

Retrieve payout details and status.

List Payouts

GET /api/v1/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

  1. Customer enters their phone number on the checkout page
  2. An STK push (prompt) is sent to their phone
  3. Customer enters their PIN to confirm
  4. Payment is confirmed via webhook
Supported providers: Daraja (M-Pesa), Flutterwave, Selcom, DPO. The platform automatically routes to the best available provider based on your merchant settings.

Card Payments

Accept Visa and Mastercard payments from anywhere in the world.

Flow

  1. Customer enters card details on the secure checkout page
  2. For 3D Secure cards, customer is redirected to their bank's verification page
  3. After verification, payment is processed and confirmed
3D Secure: Some cards require additional verification. The payment_url in the response handles this redirect automatically.

Cryptocurrency

Accept Bitcoin, Ethereum, USDT, Litecoin, and Dogecoin payments with automatic conversion.

Supported Coins

CoinNetworkConfirmations
BTCBitcoin2
ETHEthereum (ERC-20)12
USDTTRC-20 / ERC-201
LTCLitecoin3
DOGEDogecoin3

Flow

  1. Customer selects cryptocurrency and coin type
  2. A unique wallet address and amount are generated via NOWPayments
  3. Customer sends the exact amount to the address
  4. 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

json
{
  "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
<?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

EventDescription
payment.completedPayment was successfully completed
payment.failedPayment attempt failed
payout.completedPayout was sent successfully
payout.failedPayout attempt failed

Error Handling

1Pay uses standard HTTP status codes. Errors return a JSON body:

json
{
  "success": false,
  "error": "Invalid API key"
}
StatusMeaning
200Success
400Bad request — missing or invalid parameters
401Unauthorized — invalid or missing API key
403Forbidden — CSRF or IP restriction
404Not found — resource doesn't exist
429Rate limited — too many requests
500Server error — retry later

SDKs & Libraries

Official client libraries coming soon. For now, use any HTTP client:

javascript
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:

EndpointLimitWindow
Payment creation10 requestsPer token per 5 minutes
General API100 requestsPer minute per API key
Webhook delivery5 retriesExponential backoff
Rate limit headers are included in responses: X-RateLimit-Remaining, X-RateLimit-Limit, X-RateLimit-Reset.

Questions? Contact us at support@1pay.app or visit 1pay.app