There are approximately 100 different payment decline codes in the card network specifications. Most of them are designed to communicate between banks — not to be read by humans. "Do Not Honour" (decline code 05) tells a merchant nothing actionable. "Insufficient Funds" is clear, but "Invalid Transaction" or "Refer to Card Issuer" are opaque to the point of absurdity.
The problem we were solving
We analysed 6 months of support tickets from merchants whose customers experienced payment failures. The number-one support category, accounting for 34% of all tickets, was customers asking some variation of "why did my payment fail and what do I do?" The second category, at 22%, was merchants asking us to interpret specific decline codes on behalf of their customers.
Our approach
We built a small inference service that takes as input: the raw decline code, the merchant category, the payment method type, the customer's locale, and any 3DS data available. It outputs a structured JSON object with three fields: a short human-readable reason, a suggested next action, and a confidence score.
We use a fine-tuned version of a smaller language model (not GPT-4 scale — we needed <50ms inference time). The training dataset was built from: the official card network documentation, our internal decline taxonomy developed over four years, and 400 manually written example messages reviewed by our support team leads.
Example transformation: Raw code 05 ("Do Not Honour") for a UK debit card → "Your bank declined this payment. This is sometimes a temporary block — try calling the number on the back of your card or using a different payment method." Locale: en-GB. Confidence: 0.87.
The nuance that matters
The hardest part wasn't writing the messages — it was calibrating specificity. Telling a user "your card is over its limit" is helpful if true, but embarrassing and potentially wrong if the issuer sent that code for a different reason. We always include an uncertainty hedge for low-confidence interpretations and never blame the customer's financial situation if we're not certain.
We also localise for tone, not just language. German users receive more formal, factual messages. Brazilian users get warmer, more conversational copy. These nuances required market-specific review from our localisation team before launch.
Results
After 90 days, support tickets related to decline interpretation dropped 41%. Cart recovery rate — the percentage of customers who successfully retry after a decline — increased by 12%. The improvement was largest for the "Refer to Card Issuer" and "Do Not Honour" codes, where previously our messages were completely opaque. We're now extending this to cover acquirer-side error messages, which are even more cryptic than issuer codes.
Ready to optimise your payment flow?
Join thousands of businesses using Zupay to process payments faster, smarter, and at lower cost.