Errors
Every GW-xxx code, what triggers it, and the HTTP status it comes back with.
Every error response shares one envelope:
{
"success": false,
"code": "GW-403-FORBIDDEN",
"message": "This service is not enabled for your account.",
"errors": null,
"requestId": "0HNA1B2C3D4E5:00000001"
}errorsis present (a list of field-level messages) only onGW-400-BAD-REQUESTvalidation failures. It'snullotherwise.requestIdcorrelates the error with the gateway's own server-side logs — useful when asking support to look into something. The gateway never returns a stack trace or other internal detail in an error body, by design, even for aGW-500.- An upstream provider/backend failure is never echoed back verbatim — you'll see a generic
GW-500-SERVER-ERRORwith arequestId, not the provider's own error text.
Transaction lifecycle codes
A status field on a transaction or a webhook delivery is always one of these — never a raw
internal status string:
| Code | Meaning |
|---|---|
GW-00-PENDING | Still in progress. Also the default when an upstream status can't be confidently mapped — the gateway never guesses Success/Failed when unsure. |
GW-01-SUCCESS | Completed successfully. |
GW-02-FAILED | Failed. |
GW-03-EXPIRED | Expired before it could complete. |
GW-04-CANCELLED | Cancelled. |
Request/response error codes
| Code | HTTP status | When you'll see it |
|---|---|---|
GW-400-BAD-REQUEST | 400 | A field failed validation (see errors[]); a money-out request exceeds your configured amount/daily limit; a money-out request would take your ledger balance below zero; a Sandbox credential used a number that is not a test number. |
GW-401-UNAUTHORIZED | 401 | Wrong AppId/AppKey (both fail identically); a missing/invalid/stale request signature on a signed action; too many failed login attempts (dashboard accounts). |
GW-403-FORBIDDEN | 403 | Your partner is suspended; your IP isn't on the whitelist; the service isn't enabled for your account; a Sandbox-only action was called with a Live credential; a dashboard session tried to read/act on another partner's data. |
GW-404-NOT-FOUND | 404 | The transaction/resource you asked for doesn't exist (or doesn't belong to you — see below). |
GW-409-CONFLICT | 409 | You tried to create something that already exists (e.g. a duplicate service code). |
GW-429-RATE-LIMIT | 429 | You've exceeded your per-service rate limit. Back off and retry. |
GW-503-SERVICE-UNAVAILABLE | 503 | The service is currently in maintenance mode. |
GW-500-SERVER-ERROR | 500 | An unexpected internal error, or an upstream provider failure. Check requestId against the gateway's logs if this persists. |
A note on 403 vs. 404 for "does this exist": when you ask for a resource that genuinely
belongs to a different partner (a transaction id, a whitelist entry id, a callback delivery id),
the gateway returns 403, not 404. A 404 would confirm the id exists but isn't yours — a
403 reveals nothing about whether it exists at all. Don't treat a 403 on a "not found"-shaped
request as proof the resource exists; it may not.
