Loading fonts…

Payment failure UX for timeouts, declines and retries

Guide · 6 min read · By Utkarsh Dhairya Panwar · Updated

Give each payment failure state its own advice: a timeout means the outcome isn't known yet, a decline means the bank said no, and a retry must say what happens this time. At FamPay I redesigned these states, cutting failure-related drop-off by 20% and repeated mistakes by 25%.

Why payment errors deserve their own design pass

In 2023 I spent four months as a UX design intern at FamPay (YC S19), a payments app for teenagers in India. Part of my work was the iOS payment flows, and in particular what happens when a payment doesn't go through: timeouts, bank declines and retries.

Happy paths get reviewed in every design crit. Failure states usually get one generic screen, written late in the sprint. Yet a failed payment is when someone is most anxious about their money, and for a teenager it may be their own savings. A vague "something went wrong" at that moment costs a lot of trust.

A timeout, a decline and a retry are three different problems

The most common mistake in payment error UX is treating every failure as the same failure. Each means something different to the user and needs a different next step.

StateWhat the user needs to knowWhat not to do
TimeoutThe result isn't known yet. Whether money left the account, and when they'll find out.Push an instant retry that could charge them twice.
Bank declineThe bank refused it; the app didn't fail. Whether trying again makes sense or another method is better.Blame the user or show a raw bank error code.
RetryWhat will happen this time, and that the earlier attempt won't also go through.Hide the retry button, or make it look identical to the first attempt.

That table is general practice; FamPay's screens looked different. The redesign I worked on used the same separation, though: timeout, decline and retry each got a distinct state instead of sharing one failure message.

What to write in each state

Each message needs three things: what happened, whether money moved, and what to do now. The example copy below is written for this guide rather than taken from any app, so adjust the details to what your payment provider tells you.

StateHeadlineBodyMain action
TimeoutChecking with your bankIf money left your account, it will either complete or come back on its own. This screen updates as soon as your bank replies.Check status (no retry yet)
Bank declineYour bank declined this paymentYou haven't been charged. Banks decline for limits or security checks. Another method usually works.Pay another way
Network lostPayment didn't startYour connection dropped before the payment was sent. Nothing was charged.Try again
Cancelled authenticationPayment cancelledYou closed the bank's verification step, so nothing was charged.Try again
Success after a retryPaidThis went through, and the earlier attempt didn't charge you.Done

The timeout row is the hardest to get right. The user may already have a debit message from their bank while the app still has no answer, so the screen has to admit what it doesn't know and promise when it will. Offering "Try again" there is how people end up paying twice.

Test the failures as well as the flow

The team ran usability tests across 15+ screens. Most of the findings came from the gaps around the payment form: points where a retry wasn't clearly available, and moments where the app said too little about what was happening to the payment.

Failure states are awkward to test because you have to stage them. Build a prototype path for each failure type and ask people to complete a payment you know will fail. Watch what they tap next, and listen to what they think happened to their money.

  • Do they know whether they were charged?
  • Do they find the retry, and do they believe it's safe?
  • Do they repeat the same action when a different one was needed?
  • Do they leave the app to check their bank, and do they come back?

One error pattern, used everywhere

The other half of the work was consistency. I introduced one error pattern across the payment flows, so every failure followed the same structure. Users learned once where to find what happened and what to do next, and that habit carried over to the next error.

Repeated user mistakes fell by 25%, and more people completed a retry. When errors look different in every corner of an app, people can't build a habit for recovering, so they repeat whatever they did last time.

  • 20% Less failure-related drop-off
  • 25% Fewer repeated user mistakes
  • 15+ Screens validated in usability tests

A checklist for payment failure states

  1. List every way a payment can fail: Timeouts, declines, network loss, cancelled authentication, limits. Each one needs its own designed state.
  2. Write the three answers for each: What happened, whether money moved, and what to do now.
  3. Make retry explicit and safe: Say what the retry does, and lock the button after the first tap so a nervous double tap can't cause a double charge.
  4. Use one pattern for all of them: Keep the layout, the position of the next action and the tone the same. Every variation is one more thing people have to relearn.
  5. Stage the failures in testing: Prototype each failure and watch what people do next. That's where the gaps show.
  6. Track recovery as well as failure: Count how many failed payments end in a successful retry, alongside how many failed in the first place.

Everything before the pay button (the total, the rules, the button label) is covered in my checkout UX guide. If your product has payment flows that need this kind of attention, it's part of my SaaS product design work.

FamPay case study: My other FamPay project, the Cashback Store voucher flow, written up in full.

Questions people ask

What should a payment error message include?

What happened, whether money left the account, and the next action. A timeout, a bank decline and a retry each need a different version of that message.

Should the app retry a failed payment automatically?

Not after a timeout, because the first attempt may still complete. After a clear decline, let the user choose: try again or switch method. Silent automatic retries make it hard for people to know what they paid.

Is the FamPay payment errors work a case study on your site?

The FamPay case study covers the Cashback Store voucher flow. The payment error work is from the same internship and is written up here.

Sources

  1. Declines, Stripe Documentation
  2. Idempotent requests, Stripe API Reference
  3. Error-Message Guidelines, Nielsen Norman Group

Working on this?

Tell me what you're building and where it's stuck: book a 30-minute call, email work@utkarshdesign.com or send a brief.

Related