Errors
Every failed /v1 request returns the same JSON shape, whether the failure came from validation,
authentication, a provider, or Nuansis itself.
{ "error": { "code": "invalid_request", "message": "Exceeds balance: 1200 NGN" }, "request_id": "5f2d8a41-3c6b-4c19-9f0e-7a8b9c0d1e2f"}| Field | Type | Notes |
|---|---|---|
error.code |
string | Machine-readable, stable. Branch on this, not on message. |
error.message |
string | Human-readable explanation. May change. |
error.details |
object | Present only when the error carries structured extras (scopes, rate-limit hints). |
request_id |
string | Same value as the X-Request-Id response header. Include it in support requests. |
Successful responses use the sibling envelope { data, meta: { request_id } }; they never include
an error key.
| Code | HTTP status | Raised when |
|---|---|---|
invalid_request |
400, 405, 422 |
Validation failed, a field is unsupported, the balance is insufficient, or the route/method does not accept the request |
unauthorized |
401 |
No key presented (missing_api_key) or the key is malformed, unknown, or revoked (invalid_api_key) |
forbidden |
403 |
The caller is authenticated but not allowed to perform the action |
insufficient_scope |
403 |
The key lacks one or more scopes the endpoint requires |
not_found |
404 |
The resource does not exist in this workspace |
conflict |
409 |
Generic state conflict |
idempotency_conflict |
409 |
An Idempotency-Key was reused with a different request body, path, or method |
rate_limited |
429 |
The per-key request budget, or a verification-specific limit, was exceeded |
provider_error |
502, 503, 504 |
The upstream bank, collection, or messaging provider failed or timed out |
coming_soon |
501 |
The endpoint exists but the capability is not available yet |
internal_error |
500 |
An unexpected server failure |
The code is taken from an explicit code in the exception when it is part of this vocabulary;
otherwise it is derived from the HTTP status. That is why 405 Method Not Allowed and
422 Unprocessable Entity both surface as invalid_request, and why 502/503/504 all surface
as provider_error.
Details
Section titled “Details”Some errors add details:
{ "error": { "code": "insufficient_scope", "message": "This API key is missing the required scope(s)", "details": { "required": ["collections:write"], "granted": ["read"], "missing": ["collections:write"] } }, "request_id": "5f2d8a41-3c6b-4c19-9f0e-7a8b9c0d1e2f"}{ "error": { "code": "rate_limited", "message": "Rate limit exceeded", "details": { "limit": 120, "retry_after_seconds": 17 } }, "request_id": "5f2d8a41-3c6b-4c19-9f0e-7a8b9c0d1e2f"}Validation failures
Section titled “Validation failures”The API validates request bodies with a global pipe. When several fields fail, the individual
messages are joined into one message string with , :
{ "error": { "code": "invalid_request", "message": "amount must be a number conforming to the specified constraints, currency must be one of the following values: NGN" }, "request_id": "5f2d8a41-3c6b-4c19-9f0e-7a8b9c0d1e2f"}Field names in messages are the JSON field names you sent, so they map directly to the request body.
Retrying safely
Section titled “Retrying safely”| Status | Retry? | How |
|---|---|---|
400, 401, 403, 404, 405, 422 |
No | Fix the request or the key |
409 idempotency_conflict |
No | Use a new key or send the original body |
429 |
Yes | Wait details.retry_after_seconds, then retry |
500, 502, 503, 504 |
Yes | Retry with backoff, and reuse the same Idempotency-Key |
Any POST that creates money movement should be retried with the same Idempotency-Key so a
successful-but-unseen first attempt cannot be applied twice. See Idempotency.
HTTP status summary
Section titled “HTTP status summary”| Status | Meaning on /v1 |
|---|---|
200 |
Success (reads, bank resolve, verification check) |
201 |
Created (collections, reserved accounts, transfers, withdrawals, beneficiaries, deposits, verifications) |
400 |
Invalid request or business rule failure |
401 |
Missing or invalid API key |
403 |
Forbidden or insufficient scope |
404 |
Resource not found |
409 |
Conflict or idempotency conflict |
429 |
Rate limited |
500 |
Internal error |
501 |
Capability not available yet |
502 / 503 / 504 |
Upstream provider failure |