Pesatrotal
Karibu
Merchant APIOpenAPI 0.6.0

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.

Testing

https://sandbox.thetrotal.com

  • Token: POST /oauth/token
  • Collect: POST /v1/collections
  • Credentials: console → Applications → Sandbox (cid_test_…)
Production

https://pesa.thetrotal.com

  • Token: POST /oauth/token
  • Collect: POST /v1/collections
  • Credentials: console → Applications → Production (cid_live_…)

01. Start here

Getting started

  1. Register on me.thetrotal.com and complete KYC (multiple documents supported).
  2. After KYC is APPROVED, open Applications and create an app (or use the default app).
  3. For testing: open the Sandbox tab, issue credentials, copy the one-time client_secret.
  4. Call POST https://sandbox.thetrotal.com/oauth/token, then POST https://sandbox.thetrotal.com/v1/collections.
  5. For production: use the Production tab credentials against https://pesa.thetrotal.com only.

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.

WhatTesting (sandbox)Production
Base URLhttps://sandbox.thetrotal.comhttps://pesa.thetrotal.com
OAuth tokenPOST /oauth/tokenPOST /oauth/token
Create collectionPOST /v1/collectionsPOST /v1/collections
Get collectionGET /v1/collections/{id}GET /v1/collections/{id}
BalancesGET /v1/balancesGET /v1/balances
Client ID prefixcid_test_…cid_live_…
Console tabApplications → SandboxApplications → Production
Do not mix environments. A sandbox token on pesa.thetrotal.com (or a live token on sandbox.thetrotal.com) is rejected.

All hosts

HostUse
https://sandbox.thetrotal.comTesting / sandbox API + OAuth token
https://pesa.thetrotal.comProduction API + OAuth token + provider callbacks
https://payments.thetrotal.comLegacy alias of production
https://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.

POST/oauth/token
Testing: sandbox.thetrotal.com
curl -s https://sandbox.thetrotal.com/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=cid_test_… \
  -d client_secret=cs_…
Production: pesa.thetrotal.com
curl -s https://pesa.thetrotal.com/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=cid_live_… \
  -d client_secret=cs_…
Token response
{
  "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 apps
POST /v1/applicationsCreate app (KYC approved)
GET /v1/applications/{id}Environments, products, credentials
PUT …/environments/{env}/callbackCallback URL and signing secret
POST …/credentialsIssue, rotate, or revoke credentials
Capability labels in the console: Available, Sandbox only, Certification required, Disabled. Nonfunctional controls are never shown as active.
POST/v1/collections

Create 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.

M-Pesa (Vodacom) USSD: select 1 to proceed → enter PIN → select 1 to confirm. Entering PIN immediately returns USSDCallbackCancel-Failed. See provider-callback-failure-mpesa.json.
cURL request
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

202 Accepted / processing
{
  "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

GET/v1/balances?currency=TZS
Balance response
{
  "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.

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.

Expect 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_changed
  • disbursement.status_changed
  • bill.status_changed
Signed delivery headers
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.

StatusMeaning
400Invalid request / validation
401Missing or invalid session, OAuth token, or API key
403Merchant not ACTIVE, impersonation read-only, missing scope, or feature gate
402Insufficient available balance (disbursements)
404Resource not found
409Idempotency conflict or checkout already in progress
410Payment link expired or used
429Rate limited
502Provider rejected initiation