Requests and responses
Format
- HTTPS only. Send JSON with
Content-Type: application/json; responses are always JSON. - Times are ISO 8601 in UTC. IDs are opaque strings with a prefix (msg_, cmp_, otp_).
- Money is an object with an exact decimal string:
{ "amount": "0.0350", "currency": "GHS" }. Never parse it as a float. - New fields may be added to responses at any time; ignore ones you don’t know.
Status codes
| HTTP | Meaning |
|---|---|
| 200 | OK (or an idempotent replay of an earlier request). |
| 202 | Accepted for sending — work continues in the background. |
| 400 / 422 | The request was invalid or the code was wrong. See code and fields. |
| 401 | Missing or invalid API key. |
| 402 | Not enough funds in the wallet. |
| 403 | Not allowed (scope, project state, spending cap). |
| 404 | Not found in this project and environment. |
| 409 / 410 | Conflicts with the current state (already verified, expired…). |
| 429 | Rate limit or cooldown — honour Retry-After. |
| 5xx | Nopexo error — retry with the same Idempotency-Key. |
Idempotency
POST /v1/sms/send, POST /v1/sms/bulk and POST /v1/otp/send accept an Idempotency-Key header (8–100 letters, numbers, - or _). The first request with a key does the work; later requests with the same key in the same project return the original result with status 200 and send nothing. Generate a new key for each logical action, e.g. a UUID.
Pagination
Lists return items and nextCursor. Pass cursor=nextCursor to get the next page; null means you’ve reached the end.
Tracing
Every response has an X-Request-Id header (req_…), repeated as traceId in errors and listed in the dashboard’s Usage page. Nopexo logs the endpoint, status and timing of each request — never bodies, phone numbers or keys.
Versioning
The version is in the path (/v1). Additive changes ship without a new version; breaking changes would ship as /v2, with notice.