PaymonetraDocs

Errors

No `success` flag: the HTTP status is the answer, and the body names the field where there is one.

#The shape

A developer reads an error to find out what to change, so it names the field where there is one. There is no success flag: the HTTP status is the answer.

JSON
{
  "error": {
    "type": "invalid_request",
    "message": "customer_reference is required. It is your own id for this customer and we hand it back on every payment.",
    "field": "customer_reference"
  }
}

type is one of unauthorized, account_inactive, not_verified, invalid_request, not_found, conflict, provider_error, not_test_mode, validation.

not_test_mode is returned 403 by the sandbox routes when a live key is used. It is the one guard between simulated money and real money, so it refuses loudly rather than doing nothing.

#The types

type is what you branch on:

typeusually means
unauthorizedNo key, the wrong kind of key, or a key that is not valid
account_inactiveThe merchant account cannot transact right now
not_verifiedLive mode needs an approved business. Test mode keeps working
invalid_requestA field is missing or not allowed. field names it
not_foundNo such reference, or it does not belong to your merchant and mode
conflictThe same thing is already being created. Wait, do not retry immediately
provider_errorSomething upstream failed. Nothing was charged
not_test_modeA test-only endpoint was called with a live key
validationA field is missing or not on the allowed list. message says which

#Every code

Some responses carry a code naming the exact refusal. This table covers the whole merchant surface, so a code your operations team sees in the dashboard is here too.

codehttpwhat to show
merchant_suspended / merchant_closed403show message, point at support. Suspension also revokes the dashboard token, so in practice this arrives from auth/merchant-login and an in-flight session gets 401 unauthorized instead
kyb_required403the verification gate; message says what is blocked and that test mode still works
wallet_not_allowed422a registered business tried to settle to a personal wallet. message explains it and names the business; render it rather than writing your own
bank_account_required422settlement pointed at a bank with no account recorded
validation422a field is missing or not on the allowed list; message says which
insufficient_ready422more than is available to pay out; ready and clearing are on the error
below_minimum422under NGN 100 to a wallet or NGN 500 to a bank
name_unconfirmed422the receiving bank would not confirm the account name. Nothing was sent
account_not_found422the bank cannot find that account number
payout_failed422a refusal we could read. The money is back in Ready
issue_in_progress409an account for that customer is already being created; wait, do not retry
insufficient_collected422a refund or settlement larger than the Collected balance; nothing was written
provider_error / mail_failed502the code could not be sent; offer the other channel

#Two that look like bugs and are not

  • A 401 on an unknown, revoked or rotated key is one message for all three. Deliberately: otherwise the endpoint could be used to tell a real key from a guess.
  • amount_over_limit on POST /payments is us refusing early rather than your customer watching a transfer bounce at their bank.