kepa

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."
}
CategoryCodesMeansretryClass
INSUFFICIENT_FUNDS_OR_LIMIT51 · 61 · 65Funds or a velocity limit — usually temporary.SCHEDULED_RETRY
ISSUER_OR_NETWORK_UNAVAILABLE91 · 96The issuer or network didn't answer.IMMEDIATE_CASCADE
EXPIRED_CARD54The card is past its expiry.CUSTOMER_ACTION_REQUIRED
AUTHENTICATION_FAILED55 · 75Wrong PIN or failed authentication.CUSTOMER_ACTION_REQUIRED
DO_NOT_HONOR05 · 57 · 62 · 63A generic issuer refusal — restricted or suspected fraud.NEVER
PICKUP_CARD04 · 07 · 41 · 43The issuer wants the card retained — often lost or stolen.NEVER

Retry 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.

!Don't retry hard declines
Networks track reattempts on declined credentials. Hammering a do-not-honor decline earns fees and, eventually, fines. Retry only what’s classified retryable — which is exactly what the orchestration does on your behalf.

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 neutral customerMessage kepa 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.