Errors
A request that fails returns an HTTP error status and one envelope. Branch on error.code, never
on message.
{
"error": {
"code": "validation_failed",
"message": "payer.email is required",
"details": [{ "field": "payer.email", "message": "is required" }]
}
}
| Field | Type | Always set | Meaning |
|---|---|---|---|
error.code |
string | yes | The cause — see Codes. Stable: branch on it |
error.message |
string | yes | Human-readable. Not stable — do not parse |
error.details[] |
array | for validation_failed |
One item per field: field — its path, message — what is wrong |
Codes
| HTTP | code |
When | Retry |
|---|---|---|---|
| 400 | validation_failed |
A field is missing or malformed; details[] names it. Includes an amount with more than two decimals and a currency other than the shop currency |
No. Fix the request |
| 401 | authentication_failed |
The key is missing, malformed or revoked, or sent to the other environment's host | No |
| 403 | method_not_enabled |
The method is not enabled for the shop, or the key is of the other shop type — a payin shop on a payout endpoint, or the reverse | No. Use the key of the right shop, or ask Mercuryo to enable the method |
| 404 | resource_not_found |
No such transaction in this shop | No |
| 409 | merchant_reference_conflict |
The merchant_reference is used with a different body |
No. Resend the original body, or use a new reference |
| 409 | action_not_allowed |
The action is not available for this method or status: capture on a payin that is not authorized, a refund above the remainder |
No |
| 429 | rate_limited |
Too many requests | Yes, after Retry-After seconds |
| 500 | internal_error |
Failure on our side | Yes, the identical request |
| 501 | not_supported_yet |
In the contract, not working yet | No |
Nothing is created on any of them. An unknown code: act on its HTTP status — retry 429 and 500
with the identical request, fix the request on any other.
A decline is a status, not an error
When the bank, the provider or antifraud declines a transaction after it was created, the request
still succeeds. The transaction ends failed, and the reason is in status_details.code:
status_details.code |
Meaning |
|---|---|
card_not_supported |
The card is not accepted: type, country or issuer |
invalid_payment_token |
The Apple Pay or Google Pay token could not be decrypted |
method_unavailable |
The method is not available for this transaction right now |
risk_rejected |
Rejected by antifraud |
limit_exceeded |
A per-transaction, daily or monthly limit |
provider_declined |
The provider or the bank declined |
invalid_recipient_details |
The recipient's bank rejected the payout details |
insufficient_funds |
The shop balance did not cover the payout |
canceled_by_payer |
The payer rejected the payment |
canceled_by_merchant |
You voided the hold |
internal_error |
Failure on our side; the transaction did not complete |
Which codes a method can return is listed on its page: Card,
Apple Pay, Google Pay,
BLIK, Card payout.
An unknown code is a decline: handle it like provider_declined.
A decline is final. Repeating the request returns the same failed transaction; a new attempt is a
new transaction with a new merchant_reference.
Next: Webhooks