vermilion
guides

Errors

Every error uses one envelope, with normalized codes shared across all PSPs:

{ "error": { "code": "no_eligible_psp", "message": "…" } }

HTTP status mapping

statusmeaningtypical codes
400invalid requestinvalid_request, unsupported_payment_method, unsupported_currency
401 / 403authenticationunauthorized, forbidden
404unknown resourcenot_found
409conflictidempotency_conflict, invalid_state_transition
422routingno_eligible_psp
502PSP technical failurepsp_error, psp_timeout, psp_unavailable

Declines are not HTTP errors

A refused card is a business outcome, not a request failure: the payment returns 201 with status: "failed" and a normalized code in last_error.code.

decline codemeaning
insufficient_fundsnot enough balance
card_declinedgeneric refusal
expired_cardcard expiry passed
incorrect_cvcCVC check failed
do_not_honorissuer refused without detail
authentication_requiredSCA / 3DS required
fraud_suspectedblocked by risk checks

The exact PSP-side reason stays visible on the attempt in the dashboard timeline — the normalized code is what your integration should branch on.