Handling declines
How kepa classifies declines, what it retries automatically, and what needs the customer.
Most card-not-present declines are recoverable: the funds land a day later, or a retry through a different acquirer clears. How you handle one depends on how it’s classified.
Decline classification
Every result carries a category — a normalized reason, stable across card networks — and a retryClass indicating whether the payment is worth attempting again, rather than a raw network code.
{
"outcome": "DECLINED",
"category": "INSUFFICIENT_FUNDS_OR_LIMIT",
"retryClass": "SCHEDULED_RETRY",
"customerMessage": "The card has insufficient funds or has exceeded a limit."
}INSUFFICIENT_FUNDS_OR_LIMIT51 · 61 · 65Funds or a velocity limit — usually temporary.SCHEDULED_RETRYISSUER_OR_NETWORK_UNAVAILABLE91 · 96The issuer or network didn't answer.IMMEDIATE_CASCADEEXPIRED_CARD54The card is past its expiry.CUSTOMER_ACTION_REQUIREDAUTHENTICATION_FAILED55 · 75Wrong PIN or failed authentication.CUSTOMER_ACTION_REQUIREDDO_NOT_HONOR05 · 57 · 62 · 63A generic issuer refusal — restricted or suspected fraud.NEVERPICKUP_CARD04 · 07 · 41 · 43The issuer wants the card retained — often lost or stolen.NEVERRetry classes
Two of the four retry classes recover the payment for you, and they work differently:
IMMEDIATE_CASCADE— the issuer or network didn’t answer, so kepa reroutes the same payment to another acquirer right away. Nothing was wrong with the card.SCHEDULED_RETRY— a temporary decline like insufficient funds. kepa reattempts on a schedule (by default the next day, then a day later, then once more) — the funds often land in between.
Either way you do nothing; a later attempt clears and you get a webhook when it does, or the payment is dead-lettered once the policy’s attempts run out so it can’t retry forever.
The other two are terminal. NEVER— do-not-honor, restricted, pickup — will not clear on a retry, and reattempting it counts against you with the issuer; kepa doesn’t retry these, and neither should you. CUSTOMER_ACTION_REQUIRED — an expired card or a failed authentication — needs the customer, not another attempt.
Retry policy
The retry schedule, the number of attempts, the cascade order across acquirers, and the final action when attempts run out — a payment that never clears is dead-lettered so it can’t retry forever — are all governed by a retry policy. There is a sensible default; the knobs exist for when you need them. None of it requires a line of code on your side.
What needs the customer
The CUSTOMER_ACTION_REQUIRED and NEVER classes are about the customer, not the code:
EXPIRED_CARD— ask for a new card. For a subscription, this is the moment to send the customer to the billing portal.DO_NOT_HONOR— show the neutralcustomerMessagekepa returns (“The card was declined. Use another payment method.”). Never surface the raw network code; issuers keep the real reason vague to the merchant on purpose.
Retry safely
When you do reattempt a payment yourself, send a fresh Idempotency-Key per attempt — reusing one returns the original decline instead of trying again. A retry is a new attempt; give it a new key.