Gozem Developer DocsDocs

This page lists the error codes specific to the Money API. Authentication and the shared platform codes (such as unauthenticated, forbidden, validation_failed, and rate_limit_exceeded) are documented in Authentication and API Basics. The codes below are in addition to those.

Error envelope

The transaction details and account endpoints use the same { "success", "message", "error_code" } envelope, but with lowercase snake-case codes — their codes are listed in their own table below.

The charge and payout endpoints still return failures with the legacy machine-readable error_code:

{
  "error_code": "INSUFFICIENT_FUNDS",
  "message": "Payout amount exceeds the available balance.",
  "details": {}
}

Charge and payout failures carry no success flag — branch on the HTTP status and error_code. Only transaction details and account include one.

Some errors carry extra fields alongside details: INSUFFICIENT_FUNDS includes available_balance, and LIMIT_EXCEEDED includes the relevant limit fields (min_amount, max_amount, daily_cap, monthly_cap, velocity_limit, …).

Branch on error_code, not on message. details is optional and carries validation or contextual data when present.

Charge and payout error codes

These are part of the public contract: new codes may be added over time, but existing rows never change meaning. Handle a code you do not recognize gracefully rather than failing hard.

Code HTTP When it occurs
VALIDATION_ERROR 400 A business rule rejected the request, for example a PSP channel with a gm_account identifier. details is an array of messages.
validation_failed 400 The body or query failed schema validation before the handler ran — a missing or malformed field. details is an array of {field, message}. Lower case, because it comes from the platform layer rather than the Money handlers.
CHANNEL_NOT_SUPPORTED 400 The channel value is not in the supported list.
PAYER_NOT_ELIGIBLE 400 The payer exists but cannot be charged (charge).
BENEFICIARY_NOT_ELIGIBLE 400 The beneficiary exists but cannot receive funds (payout).
INSUFFICIENT_FUNDS 402 The payout amount exceeds the available balance.
LIMIT_EXCEEDED 403 A payout limit was breached: min/max amount, daily or monthly cap, or velocity (20 payouts per 5 minutes).
PAYER_NOT_FOUND 404 The payer could not be resolved (charge).
BENEFICIARY_NOT_FOUND 404 The beneficiary could not be resolved (payout).
CHARGE_NOT_FOUND 404 The charge is unknown, or not owned by this client.
PAYOUT_NOT_FOUND 404 The payout is unknown, or not owned by this client.
IDEMPOTENCY_CONFLICT 409 The same idempotency-key was reused with a different body (see Authentication).
DUPLICATE_REQUEST 409 An identical payout — same beneficiary and amount — was already submitted within the last five minutes, so no new payout was created. details.reference is the existing payout. Vary the amount or wait out the window.
PROVIDER_UNAVAILABLE 503 The PSP provider is temporarily unavailable. Safe to retry with backoff.

A plain 401 surfaces for a missing or invalid JWT, HMAC signature, or timestamp, and 500 INTERNAL_ERROR for unexpected failures.

Transaction details and account error codes

GET /money/v1/transaction-details/:id and GET /money/v1/account return the standard failure envelope — branch on error_code:

{
  "success": false,
  "message": "No transaction details found for this API client.",
  "error_code": "transaction_not_found"
}

Authentication and routing failures on these endpoints use the same shape with platform codes: 401 unauthenticated (missing or invalid token, bad signature, or a timestamp outside the 300-second window), 403 forbidden (the client is not entitled to the route’s slug), 404 not_found (no such route), 429 rate_limit_exceeded, and 500 internal_error.

Validation failures

A request that fails schema validation returns 400 validation_failed with a details array naming each offending field — the same shape the Courier API uses:

{
  "success": false,
  "message": "querystring/limit must be integer",
  "error_code": "validation_failed",
  "details": [
    { "field": "limit", "message": "must be integer" }
  ]
}

field is the path of the offending value, dotted for nested objects (payer_identifier.type). details is present only on validation failures; every other error carries success, message and error_code alone.

Code HTTP When it occurs
validation_failed 400 The request body or parameters failed validation. details names the fields.
merchant_account_not_configured 400 The merchant has no primary Gozem Money wallet configured.
merchant_profile_incomplete 400 Required merchant fields (unique_id, wallet number) are missing.
merchant_not_linked 403 The client is not linked to a merchant account.
merchant_not_resolved 403 The merchant profile could not be loaded for this client.
transaction_not_found 404 The transaction was not found, or your client is neither payer nor payee.
account_not_found 404 Wallet details could not be retrieved for this merchant.
service_unavailable 502 Gozem could not load the data upstream. Safe to retry with backoff.

Retrying

Treat 4xx as a problem with the request — fix the payload, payer, account, or idempotency condition named by the code rather than resending. The retryable cases are PROVIDER_UNAVAILABLE (503), service_unavailable (502, transaction details and account), and rate_limit_exceeded (429, see API Basics); retry those with exponential backoff rather than immediately.

A note on the bank error shapes

The Bank API (distributor balance, fund creation, and fund destruction) uses the same { success, message, error_code } failure envelope, with lowercase snake-case codes such as request_not_found and request_state_conflict. Validation failures there carry the same details array described above. Its approve and cancel acknowledgements add a request_id, and carry error_code only when success is false. This page covers the merchant-facing Money endpoints only.