Reference
Errors & Response Envelope
Every MailAfrica endpoint wraps responses in a standard envelope. Understand success and error shapes, pagination, and the full error-code catalog.
Every endpoint returns a JSON envelope. Errors never leak internals — just a stable code, a message, and your request id.
Success envelope
json
{
"success": true,
"message": "balance retrieved",
"data": { "balance_tzs": 45000 },
"pagination": null,
"request_id": "req_01",
"timestamp": "2026-08-15T00:00:00Z"
}Error envelope
json
{
"success": false,
"message": "insufficient balance",
"errors": [
{
"field": "amount_tzs",
"code": "INSUFFICIENT_BALANCE",
"message": "wallet balance is too low"
}
],
"request_id": "req_02",
"timestamp": "2026-08-15T00:00:00Z"
}errors[] entries carry an optional field, a stable code, and a human message. List endpoints return pagination with page, per_page, total, total_pages.
HTTP status codes
| Status | Meaning |
|---|---|
| 200 | OK |
| 201 | Created (e.g. address, key, webhook, message sent) |
| 400 | Bad request — validation or rule violation |
| 401 | Missing or invalid credentials |
| 402 | Payment required — INSUFFICIENT_BALANCE |
| 403 | Forbidden — not yours, account disabled, or identity unverified |
| 404 | Not found |
| 409 | Conflict — duplicate, limit reached, or state conflict |
| 429 | Rate limited |
| 5xx | Server / upstream provider error — retry with backoff |
Error codes
| Status | Code | Meaning | How to fix |
|---|---|---|---|
| Client error401 | UNAUTHORIZED | Missing, malformed, or expired credentials. | Send a valid X-API-Key or JWT. Refresh expired JWTs. |
| Client error400 | VALIDATION_ERROR | The request body or query failed validation. | Read the field in the error and correct it. |
| Client error403 | ACCOUNT_DISABLED | The account is disabled. | Contact support; existing keys stop working immediately. |
| Client error403 | FORBIDDEN | The resource isn't yours, or identity isn't verified. | Verify email/phone; only use your own resource ids. |
| Client error404 | NOT_FOUND | Resource doesn't exist. | Check the id/url you passed. |
| Client error409 | CONFLICT | Duplicate or conflicting state. | Check for existing resources; resolve the conflict first. |
| Client error409 | LIMIT_REACHED | You hit a per-account cap (e.g. 100 addresses). | Delete unused resources or contact support. |
| Client error402 | INSUFFICIENT_BALANCE | Wallet can't cover the operation. | Top up and retry. |
| Client error429 | RATE_LIMITED | Too many requests. | Back off and respect the rate limit. |
| Server error503 | NOT_CONFIGURED | A provider integration isn't configured server-side. | This is a platform-side gap; retry later. |
| Server error502 | PROVIDER_ERROR | Upstream provider failure. | Retry; outbound balance is refunded on failure. |
| Client error200 | PENDING | DNS verification not yet propagated. | Wait and re-verify — not a real failure. |
Retry guidance
- Retry
429,502,503, and timeout errors with exponential backoff and jitter. - Do not blindly retry
400,401,403,404,409— fix the request first. - Sends and webhook deliveries are already idempotent from the platform side; repeated
POSTcalls are safe to retry.