Tanzania payments API for collections, links, and webhooks.
This documentation matches the live gateway. Create an application in the console, exchange OAuth client credentials for a short-lived token on the matching host, then collect. HTTP 202 means accepted for processing. Terminal status arrives on your webhook.
Testing vs production hosts
Same API paths. Different base URL and credentials. Do not mix them.
https://sandbox.thetrotal.com
- Token:
POST /oauth/token - Collect:
POST /v1/collections - Credentials: console → Applications → Sandbox (
cid_test_…)
https://pesa.thetrotal.com
- Token:
POST /oauth/token - Collect:
POST /v1/collections - Credentials: console → Applications → Production (
cid_live_…)
01. Start here
Getting started
- Register on
me.thetrotal.comand complete KYC (multiple documents supported). - After KYC is APPROVED, open Applications and create an app (or use the default app).
- For testing: open the Sandbox tab, issue credentials, copy the one-time
client_secret. - Call
POST https://sandbox.thetrotal.com/oauth/token, thenPOST https://sandbox.thetrotal.com/v1/collections. - For production: use the Production tab credentials against
https://pesa.thetrotal.comonly.
Download JSON samples
Ready-to-use request and response bodies. Download a file or open it and copy the JSON.
- .json
All API samples (bundle)
OAuth, collections, webhooks, provider callbacks
- .json
Collection request
POST /v1/collections body
- .json
Collection response (processing)
202 Accepted after USSD prompt sent
- .json
Collection response (succeeded)
Terminal success after provider callback
- .json
OAuth token response
POST /oauth/token
- .json
Merchant webhook
payment.status_changed to your callback URL
- .json
Provider callback (success)
Inbound settlement notice (HaloPesa example)
- .json
Provider callback (M-Pesa failure)
Cancelled-at-handset example
- .json
Postman collection
Import into Postman or Insomnia
- .json
Postman environment
Local sandbox variables
Machine auth is OAuth
Prefer application client_id / client_secret. Legacy API keys still work with product scopes; Link Key is limited to payment links.
Environment isolation
Sandbox credentials never work on production and vice versa. The API host selects the environment.
02. Hosts
Testing vs production endpoints
Paths are identical. Only the base URL and credentials change. Always pair sandbox credentials with the sandbox host, and production credentials with the production host.
https://sandbox.thetrotal.comhttps://pesa.thetrotal.comPOST /oauth/tokenPOST /oauth/tokenPOST /v1/collectionsPOST /v1/collectionsGET /v1/collections/{id}GET /v1/collections/{id}GET /v1/balancesGET /v1/balancescid_test_…cid_live_…Applications → SandboxApplications → Productionpesa.thetrotal.com (or a live token on sandbox.thetrotal.com) is rejected.All hosts
https://sandbox.thetrotal.comTesting / sandbox API + OAuth tokenhttps://pesa.thetrotal.comProduction API + OAuth token + provider callbackshttps://payments.thetrotal.comLegacy alias of productionhttps://me.thetrotal.comMerchant console (human sessions, Applications, Team)https://pay-by-link.thetrotal.comCustomer checkout at /p/{slug}. No merchant cookies.03. Security
Authentication
Server integrations use OAuth 2.0 client_credentials. Console login uses httpOnly cookies on me.thetrotal.com only. Never put secrets in a browser or on Pay by Link.
/oauth/tokencurl -s https://sandbox.thetrotal.com/oauth/token \
-d grant_type=client_credentials \
-d client_id=cid_test_… \
-d client_secret=cs_…curl -s https://pesa.thetrotal.com/oauth/token \
-d grant_type=client_credentials \
-d client_id=cid_live_… \
-d client_secret=cs_…{
"access_token": "eyJ…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "collections payment_links balances bills",
"environment": "sandbox",
"application_id": "…"
}Use the access token as Authorization: Bearer … on the same host you used for the token. Scopes map to products. Production disbursements remain feature-gated until certification.
04. Apps
Applications
KYC stays at the organization. One approved merchant can create many applications. Each app has sandbox and production environments with separate credentials, callbacks, and product grants.
GET /v1/applicationsList appsPOST /v1/applicationsCreate app (KYC approved)GET /v1/applications/{id}Environments, products, credentialsPUT …/environments/{env}/callbackCallback URL and signing secretPOST …/credentialsIssue, rotate, or revoke credentials/v1/collectionsCreate a collection
Examples below use the testing host sandbox.thetrotal.com. For live money, swap the base URL to https://pesa.thetrotal.com and use production credentials.
Amount is TZS major units. Always send Idempotency-Key. Networks: MPESA_TZ, AIRTEL_MONEY_TZ, MIXX_BY_YAS_TZ, HALOPESA_TZ, AZAMPESA_TZ.
USSDCallbackCancel-Failed. See provider-callback-failure-mpesa.json.curl https://sandbox.thetrotal.com/v1/collections \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: inv_48291" \
-H "Content-Type: application/json" \
-d '{
"amount": 137000,
"currency": "TZS",
"msisdn": "255712345678",
"network": "MPESA_TZ",
"merchant_reference": "inv_48291",
"description": "Invoice 48291"
}'Download the same body as JSON: collection-create-request.json
{
"id": "a1b2c3d4-…",
"merchant_reference": "inv_48291",
"amount": 137000,
"currency": "TZS",
"msisdn": "255712345678",
"network": "MPESA_TZ",
"status": "PROCESSING",
"attempt_id": "…",
"external_id": "…",
"created_at": "2026-08-15T21:00:00Z"
}Statuses: CREATED, REQUIRES_ACTION, PROCESSING, SUCCEEDED, FAILED, UNKNOWN, CANCELLED, EXPIRED. Poll GET /v1/collections/{id} or wait for webhooks.
List/filter: GET /v1/collections?status=&from=&to=&q=&page=&limit=. Export: GET /v1/collections/export.csv.
05. Money
Balances & statements
/v1/balances?currency=TZS{
"object": "balance",
"balances": [{
"account_code": "merchant.payable.…",
"currency": "TZS",
"ledger_balance": 1200000,
"reserved": 0,
"available": 1200000
}]
}Ledger statements: GET /v1/statements and GET /v1/statements/export.csv with opening/closing balance and running entries.
06. Checkout
Pay by Link
Create links from the console (POST /v1/payment-links). Customers open https://pay-by-link.thetrotal.com/p/{slug}. That host never sets merchant cookies. Default expiry 24h; one payment per link by default.
POST https://pesa.thetrotal.com/v1/public/payment-links/{slug}/pay
Content-Type: application/json
{
"msisdn": "255712345678",
"network": "MPESA_TZ"
}07. Payouts
Disbursements & bills
POST /v1/disbursements and POST /v1/bills exist. Production disbursements and auto-settlement are disabled behind audited feature gates until provider certification, fee/reservation correctness, reconciliation, and maker-checker are complete. Sandbox may allow disbursements when the gate is on.
403 feature_disabled with reason Unavailable: payout certification required on production payouts until gates flip.08. Events
Webhooks
Provider callbacks land on pesa.thetrotal.com (ingress). Your merchant destination is the application environment callback URL (preferred) or the legacy merchant webhook URL. Events delivered today:
payment.status_changeddisbursement.status_changedbill.status_changed
POST https://your-server.example/hooks/pesatrotal
Content-Type: application/json
X-Pesatrotal-Signature: sha256=…
X-Pesatrotal-Event: payment.status_changed
{
"id": "outbox-uuid",
"type": "payment.status_changed",
"created_at": "2026-08-15T21:01:00Z",
"data": {
"payment_id": "…",
"merchant_id": "…",
"status": "SUCCEEDED",
"amount": 137000,
"currency": "TZS",
}
}Verify HMAC-SHA256 of the raw body with your webhook secret. Delivery attempts are logged; inspect via GET /v1/applications/{id}/environments/{env}/webhooks/deliveries.
09. Settlement
Settlement accounts
Merchants register bank or mobile-money destinations with POST /v1/settlement-accounts. Responses mask account numbers. Ops verify via the admin console. Auto-settlement execution is not available until payout certification completes.
10. Reliability
Errors
Errors return JSON { code, message } with stable codes.
400Invalid request / validation401Missing or invalid session, OAuth token, or API key403Merchant not ACTIVE, impersonation read-only, missing scope, or feature gate402Insufficient available balance (disbursements)404Resource not found409Idempotency conflict or checkout already in progress410Payment link expired or used429Rate limited502Provider rejected initiation