The ScayPay API provides three core capabilities for moving money: collect it from customers (Payment), send it out to recipients (Disbursement), and move it from one party to another in one atomic operation (Transfer).
https://api.scaypay.com/v1TZS onlyTZS 500TZS 10,000,000All requests require your API key in the Authorization header:
Authorization: Bearer sk_live_your_api_key_here
Get your live API key from your ScayPay Dashboard after application approval. Use sk_test_ prefix for sandbox testing. Keep your key secret โ never expose it in client-side code.
ScayPay charges transparent, per-transaction fees with no monthly minimums.
| Operation | Amount | Fee | You Receive / Pay |
|---|---|---|---|
| Payment collection | TZS 50,000 | TZS 250 | TZS 49,750 net |
| Payment collection | TZS 500,000 | TZS 250 | TZS 499,750 net |
| Disbursement | TZS 200,000 | TZS 2,500 | TZS 202,500 deducted |
| Disbursement | TZS 1,500,000 | TZS 7,500 (0.5%) | TZS 1,507,500 deducted |
| Transfer | TZS 800,000 | TZS 2,500 | Sender pays TZS 800,000 |
| Transfer | TZS 2,000,000 | TZS 10,000 (0.5%) | Sender pays TZS 2,000,000 |
Fees are deducted from your collected balance for payments, and added on top of the amount for disbursements and transfers. All fees are in TZS.
curl -X POST https://api.scaypay.com/v1/payments/collect \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-znz-001" \
-d '{
"payment_type": "mobile",
"amount": 50000,
"currency": "TZS",
"phone": "+255758243132",
"customer": { "name": "Amani Juma", "email": "amani@example.co.tz" },
"reference": "ORD-ZNZ-001",
"webhook_url": "https://yourapp.co.tz/webhooks/scaypay"
}'
POST/v1/payments/collect
Customer receives a push notification on their phone and enters their PIN to authorize. Supported: M-Pesa (Vodacom TZ), Airtel Money, Mixx By Yas (Mixx by Yas), Halotel.
| Field | Type | Description | |
|---|---|---|---|
payment_type | string | Required | Must be "mobile" |
amount | integer | Required | Amount in TZS. Min: 500 ยท Max: 10,000,000 |
currency | string | Required | Must be "TZS" |
phone | string | Required | E.164 format e.g. +255758243132 |
customer.name | string | Required | Customer full name |
customer.email | string | Required | Customer email address |
reference | string | Required | Your order/reference ID (max 30 chars) |
webhook_url | string | Optional | HTTPS URL for status updates |
description | string | Optional | Shown to customer (max 100 chars) |
{ "id":"pay_9f3a2bc7", "status":"pending", "amount":{"value":50000,"currency":"TZS"},
"phone":"+255758243132", "network":"Vodacom TZ",
"fee": {"value":250,"currency":"TZS"},
"expires_at":"2026-05-05T18:00:00Z" }POST/v1/payments/collect with "payment_type": "card"
For card payments, ScayPay returns a checkout_url โ you must redirect your customer there to complete payment on the secure hosted checkout page. Supported: Visa, Mastercard, local debit cards.
curl -X POST https://api.scaypay.com/v1/payments/collect \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"payment_type": "card",
"amount": 150000,
"currency": "TZS",
"phone": "+255758243132",
"customer": {
"name": "Amani Juma", "email": "amani@example.co.tz",
"address": "Chikai House, M/kwerekwe",
"city": "Zanzibar", "state": "ZNZ",
"postcode": "71000", "country": "TZ"
},
"redirect_url": "https://yourapp.co.tz/payment/success",
"cancel_url": "https://yourapp.co.tz/payment/cancel",
"reference": "ORD-ZNZ-002",
"webhook_url": "https://yourapp.co.tz/webhooks/scaypay"
}'{ "id":"pay_2e0bcc5f", "status":"pending",
"checkout_url": "https://checkout.scaypay.com/pay/W0SzdUSHQm",
"payment_type": "card",
"amount":{"value":150000,"currency":"TZS"},
"fee":{"value":250,"currency":"TZS"},
"expires_at":"2026-05-05T18:00:00Z" }Important: After receiving the response, immediately redirect your customer to checkout_url. The payment expires if not completed within 4 hours. After payment, the customer is redirected to your redirect_url (success) or cancel_url (cancelled).
<?php
$response = json_decode($apiResponse, true);
if ($response['status'] === 'success' && isset($response['data']['checkout_url'])) {
header('Location: ' . $response['data']['checkout_url']);
exit;
}POST/v1/payments/collect with "payment_type": "dynamic-qr"
Returns a QR code string for the customer to scan with their mobile money app. Ideal for in-person and POS payments. Only amount and currency are required.
{ "id":"pay_6a490816", "status":"pending",
"payment_qr_code": "000201010212041552...",
"checkout_url": "https://checkout.scaypay.com/qr/Ax7kM2",
"amount":{"value":25000,"currency":"TZS"},
"fee":{"value":250,"currency":"TZS"} }GET/v1/payments/{id} โ get a single payment by ID
GET/v1/payments โ list payments with optional filters:
| Query Param | Description |
|---|---|
status | Filter: pending, completed, failed |
from | Start date: YYYY-MM-DD |
to | End date: YYYY-MM-DD |
limit | Results per page (max 100, default 20) |
page | Page number (default 1) |
Payment status values: pending ยท completed ยท failed ยท voided ยท expired
GET/v1/payments/balance
{ "available":{"currency":"TZS","value":1500000}, "balance":{"currency":"TZS","value":1500000} }Disbursements send money out from your ScayPay balance to a recipient. The total (amount + fee) is deducted immediately. If the payout fails, funds are automatically returned.
POST/v1/disbursements/send
| Field | Description | |
|---|---|---|
amount | Required | TZS amount to send. Min: 5,000 |
channel | Required | "mobile" for mobile money |
recipient_phone | Required | Recipient phone (+255XXXXXXXXX). Network auto-detected. |
recipient_name | Required | Recipient full name |
narration | Optional | Payment reason (shown on statement) |
webhook_url | Optional | HTTPS URL for status notifications |
metadata | Optional | Key-value object (returned in webhook) |
curl -X POST https://api.scaypay.com/v1/disbursements/send \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout-may2025-emp001" \
-d '{
"amount": 250000,
"channel": "mobile",
"recipient_phone": "+255758243132",
"recipient_name": "Amani Juma",
"narration": "Salary May 2026",
"webhook_url": "https://yourapp.co.tz/webhooks/scaypay"
}'{ "id":"dib_667c9279", "status":"pending",
"amount":{"value":250000,"currency":"TZS"},
"fee":{"value":2500,"currency":"TZS"},
"total_deducted":{"value":252500,"currency":"TZS"},
"recipient":{"name":"Amani Juma","phone":"+255758243132"},
"network":"Vodacom TZ" }POST/v1/disbursements/send with "channel": "bank"
| Field | Description | |
|---|---|---|
amount | Required | TZS amount. Min: 5,000 |
channel | Required | Must be "bank" |
recipient_bank | Required | Bank code from the list below |
recipient_account | Required | Bank account number |
recipient_name | Required | Account holder name |
narration | Optional | Payment reference |
-d '{ "amount":500000, "channel":"bank",
"recipient_bank":"NMB", "recipient_account":"21000012345678",
"recipient_name":"Fatuma Hassan", "narration":"Invoice INV-2026-ZNZ-001" }'Use the Code value as the recipient_bank field for bank disbursements and transfer profiles.
GET/v1/disbursements/fee?amount=500000
Always calculate the fee before sending to ensure sufficient balance.
{ "amount":500000, "fee_amount":2500, "total_amount":502500, "currency":"TZS",
"fee_breakdown": "Flat rate TZS 2,500 (amount โค 1,000,000)" }A Transfer collects money from a sender and immediately disburses it to a pre-configured destination โ all in one API call. No funds are held in your balance. โ ๏ธ A Transfer Profile must exist before initiating any transfer.
POST/v1/transfers/profiles โ create a destination profile (required before transfers)
-d '{ "name":"Zanzibar Store", "channel":"mobile",
"recipient_name":"Fatuma Hassan", "recipient_phone":"+255710578275" }'-d '{ "name":"Company Bank", "channel":"bank",
"recipient_name":"Fatuma Hassan", "recipient_bank":"NMB",
"recipient_account":"21000012345678" }'{ "profile_id":"tpf_8a3b2c1d", "name":"Zanzibar Store",
"channel":"mobile", "recipient":{"name":"Fatuma Hassan","phone":"+255710578275"} }GET/v1/transfers/profiles โ list all profiles.
POST/v1/transfers/initiate
| Field | Description | |
|---|---|---|
profile_id | Required | ID from a Transfer Profile |
amount | Required | TZS amount. Min 5,000 ยท Max 10,000,000 |
sender_phone | Required | Phone to collect from |
sender_name | Required | Sender's full name |
reference | Required | Your reference ID (max 30 chars) |
curl -X POST https://api.scaypay.com/v1/transfers/initiate \
-H "Authorization: Bearer sk_live_your_key" \
-H "Idempotency-Key: txf-znz-001" \
-d '{ "profile_id":"tpf_8a3b2c1d", "amount":150000,
"sender_phone":"+255758243132", "sender_name":"Amani Juma",
"reference":"TXF-ZNZ-001" }'Transfer status flow: collecting โ disbursing โ completed ยท or failed
ScayPay sends HTTP POST to your webhook_url for every status change. Respond with HTTP 200 within 30 seconds.
| Event | Description |
|---|---|
payment.completed | Payment collected successfully |
payment.failed | Payment failed or rejected by customer |
payment.expired | Payment expired (4-hour window) |
disbursement.completed | Cashout delivered to recipient |
disbursement.failed | Cashout failed โ balance restored |
disbursement.reversed | Cashout reversed after completion |
transfer.completed | Collected + disbursed successfully |
transfer.failed | Failed at collection or disbursement |
daily_limit.warning | 80% of daily collection limit reached |
{ "id":"evt_a1b2c3d4", "type":"payment.completed", "api_version":"2026-01",
"created_at":"2026-05-05T14:32:18Z",
"data":{ "id":"pay_9f3a2bc7", "status":"completed",
"amount":{"value":50000,"currency":"TZS"},
"fee":{"value":250,"currency":"TZS"},
"net":{"value":49750,"currency":"TZS"},
"reference":"ORD-ZNZ-001", "phone":"+255758243132" } }Each webhook includes X-ScayPay-Signature. Verify in production to prevent spoofing.
<?php
$payload = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_SCAYPAY_TIMESTAMP'];
$signature = $_SERVER['HTTP_X_SCAYPAY_SIGNATURE'];
$secret = 'your_webhook_signing_secret';
if (abs(time() - (int)$timestamp) > 300) { http_response_code(400); exit; } // replay protection
$expected = hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
if (!hash_equals($expected, $signature)) { http_response_code(401); exit; }
$event = json_decode($payload, true);
http_response_code(200); echo 'OK';| HTTP | error_code | Description |
|---|---|---|
| 400 | validation_error | Invalid or missing field |
| 401 | unauthorized | Invalid or missing API key |
| 403 | insufficient_scope | Key lacks required permission |
| 404 | not_found | Resource doesn't exist |
| 422 | idempotency_conflict | Key reused with different body |
| 429 | rate_limit_exceeded | 60 req/min exceeded |
| 500 | payment_failed | Upstream failure (retry with backoff) |
60 requests/minute. Response headers: X-Ratelimit-Limit, X-Ratelimit-Remaining, X-Ratelimit-Reset.
| Plan | Access Fee | Max Daily Collection | Max / Transaction |
|---|---|---|---|
| Student | TZS 1,000,000 | TZS 1,000,000 | |
| Basic | TZS 10,000,000 | TZS 10,000,000 | |
| Business | TZS 100,000,000 | TZS 10,000,000 | |
| Enterprise | TZS 500,000,000 | TZS 10,000,000 |
Include Idempotency-Key on all POST requests to prevent duplicates on retry. Keys must be โค 30 chars, valid for 24 hours.
Idempotency-Key: order-znz-001-attempt-1
๐ง support@scaypay.com ยท
๐ +255 710 578 275 ยท
๐ฌ +255 758 243 132 (WhatsApp)
Chikai House, M/kwerekwe, Zanzibar, Tanzania