Errors
All API errors use the same envelope structure. Thecode field is machine-readable
and stable — use it to drive error handling logic in your application.
requestId — it is required when contacting support.
HTTP status codes
| Status | Meaning |
|---|---|
200 | Success |
204 | Success (no body) |
400 | Validation error — fix the request |
401 | Authentication failed |
402 | Insufficient balance |
403 | Permission denied |
404 | Resource not found |
409 | Conflict — resource state prevents the action |
422 | Unprocessable entity |
429 | Rate limit or abuse protection triggered |
500 | Internal server error — contact support |
Error codes
Authentication
| Code | HTTP | Description |
|---|---|---|
INVALID_API_KEY | 401 | API key not found, revoked, or header malformed |
TENANT_INACTIVE | 401 | Account associated with the key is suspended |
Rate limiting
| Code | HTTP | Description |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | 60 requests/minute limit exceeded for this API key |
STK_TEMP_BANNED | 429 | STK Push temporarily disabled due to suspected abuse |
STK_TEMP_BANNED is returned, the details object includes:
Payments
| Code | HTTP | Description |
|---|---|---|
INSUFFICIENT_SERVICE_BALANCE | 402 | Service wallet balance too low to cover the fee |
INVALID_PHONE | 400 | Phone number format is invalid |
CREDENTIAL_NOT_FOUND | 404 | Specified credentialId does not exist |
CREDENTIAL_INACTIVE | 409 | Specified credential is disabled |
CHANNEL_NOT_FOUND | 400 | Specified channelId does not exist |
B2C payouts
| Code | HTTP | Description |
|---|---|---|
ACCOUNT_INACTIVE | 403 | Account is not active |
KYC_NOT_VERIFIED | 403 | KYC approval required before making payouts |
INSUFFICIENT_FUNDS | 409 | B2C wallet balance too low for this payout |
WALLET_INACTIVE | 409 | B2C wallet is not active |
UNSUPPORTED_CURRENCY | 400 | Only KES is supported |
Transactions
| Code | HTTP | Description |
|---|---|---|
TRANSACTION_NOT_FOUND | 404 | No transaction with that ID for your account |
Channels
| Code | HTTP | Description |
|---|---|---|
CHANNEL_IN_USE | 409 | Channel has linked transactions and cannot be deleted |
Handling errors in your integration
Authentication errors (401) — Check your API key is correct and not revoked. Never retry 401 errors automatically — fix the credential first. Balance errors (402) — Top up your service wallet before retrying. Subscribe to low-balance notifications or poll your balance proactively. Validation errors (400) — Fix the request before retrying. These are deterministic — retrying the same request without changes always returns the same error. Rate limit errors (429) — Implement exponential backoff. ReadRetry-After from the
response headers and wait that many seconds before the next request.
Server errors (500) — These are transient. Retry with exponential backoff (1s, 2s, 4s,
8s…). If the issue persists, contact support with your requestId.
Retry guidance
| Status | Retry? | Notes |
|---|---|---|
400 | No | Fix the request first |
401 | No | Fix credentials first |
402 | No | Top up wallet first |
403 | No | Resolve account/KYC issue first |
404 | No | Resource does not exist |
409 | No | Resolve conflict state first |
429 | Yes | Wait for Retry-After seconds |
500 | Yes | Exponential backoff |
| Network timeout | Yes | Exponential backoff |