Moja SwitchDocs Sandbox live

Guide

Errors

One error envelope, stable codes to branch on, and what to do about each class of error.

Errors share one JSON shape:

json
{
  "error": {
    "code": "validation_error",
    "message": "Human-readable summary",
    "request_id": "req_74447c85dfc22dec",
    "details": [
      { "field": "payout.beneficiary.phone", "message": "must be E.164" }
    ]
  }
}
  • Branch on error.code. It is stable. message is for humans and can change.
  • request_id (also the X-Request-Id header) identifies the request. Quote it to support.
  • details[] names each offending field on validation errors and on refusals about a field.
  • payment_id is present when the error concerns one payment.
  • Every operation in the API reference lists the responses it can return.

Two responses that are not errors

A compliance refusal is a 201. Screening runs after a payment is persisted. A block returns 201 with status: FAILED and failure.code: compliance_blocked. Never show failure.message or failure.stage to an end user; they are for your systems.

A 500 on POST /payments can carry the Payment. If processing failed after the payment was persisted, the body is the payment (it has id and status), not an envelope (which has error). Retry with the same Idempotency-Key to read it back; you will never get a second payment.

What to do, by status

HTTP Meaning What to do
400 Malformed request: bad JSON, an unknown field, a missing or non-UUID Idempotency-Key Fix the request. Do not retry it unchanged.
401 Missing, unknown or revoked API key Check the key and that it matches the environment.
403 Not allowed: scope, entitlement, account or product state Do not retry. Fix the key's scopes, or ask Moja Switch to enable you.
404 Not found, or not yours. The two are deliberately indistinguishable. Check the id.
409 Conflict: idempotency key reuse, duplicate reference, or a state that forbids the action Read the resource, then decide.
422 A business rule refused the request. Nothing was created. Fix the named fields or the cause.
429 Rate limited Wait Retry-After seconds, then retry.
500, 502 Unexpected or upstream failure Retry money calls only with the same Idempotency-Key.
503 A dependency the request needs is unavailable; the request failed closed Retry later. For quotes, show "no price available".

Codes you will meet first

Code HTTP Meaning
invalid_request 400 Body unreadable, unknown field, or Idempotency-Key missing or not a UUID
unauthorized 401 Missing or invalid API key
forbidden 403 Partner account disabled
insufficient_scope 403 The key lacks the route's scope
corridor_not_entitled 403 You are not entitled to that corridor
tenant_not_activated 403 Moja Switch has not enabled your tenant for this flow in this environment
product_not_available 403 The product (for example collections) is not offered in this environment
validation_error 422 A field failed validation; see details[]
fx_required, fx_inconsistent, fx_not_accepted 422 FX instruction problems; see FX
quote_required, quote_invalid, quote_expired 422 Quote problems on a Moja Switch FX payment
idempotency_key_conflict 409 Key reused with a different body
duplicate_reference 409 reference already used
cancel_not_allowed 409 The payment is past its cancellable state
payment_not_found 404 Unknown payment, or another partner's
rate_limit_exceeded 429 Over the rate limit
entitlement_unavailable 503 Entitlement could not be checked; nothing was forwarded
fx_unavailable 503 No valid, fresh reference rate
upstream_unavailable 502 A Moja Switch service was briefly unreachable; retry with the same Idempotency-Key
internal_error 500 Unexpected failure before anything was persisted

Treat an unknown code by its HTTP status, using the table above.

Payment failures

A payment that fails after it was created is not an HTTP error: it is a payment with status: FAILED and a failure object. Branch on failure.code. Use funds_taken (on Interac-funded transfers) to tell a customer whether their money left their account, and a generic "did not complete" message otherwise.