All posts
Guides··8 min read

Stripe payment says 'Incomplete'? What it means, why customers drop at 3D Secure, and the fix

A Stripe payment marked 'Incomplete' is not a failed charge. It means the PaymentIntent is stuck at requires_payment_method, requires_confirmation or requires_action, often with a note like 'The customer has not entered their payment method' or an abandoned 3D Secure check. Here is how to read each one, when to ignore it, and what actually reduces it.

Founder, OneSol

A customer paying by card at a checkout counter

You open the 'Payments' page in Stripe and find a row of payments marked 'Incomplete'. Some carry a note saying the customer has not entered their payment method. Others say the payment requires action. A few belong to customers who swear they paid. It looks like money is slipping through your fingers.

Usually it isn't. Every Stripe payment is tracked by a PaymentIntent, and Stripe starts tracking it before the customer has done anything. 'Incomplete' is Stripe's summary for a PaymentIntent that started and never reached the end. No charge was made on any of them. The useful question is not 'why did it fail' but 'where did it stop', and Stripe tells you exactly that if you know where to look.

What 'Incomplete' actually covers

Stripe's payment status documentation maps three PaymentIntent statuses to the single Dashboard label 'Incomplete'. Each one stops at a different step, and each has a different fix.

  • requires_payment_method: no card or other payment method was ever attached, or an attempt failed and the PaymentIntent went back to the start. Stripe says that after a decline, the status 'returns to requires_payment_method so that the payment can be retried'. This is where 'The customer has not entered their payment method' payments sit.
  • requires_confirmation: the customer provided payment details but the payment was not confirmed. Stripe notes that most integrations skip this state entirely, so seeing many of these usually points at the checkout code, not the customer.
  • requires_action: the payment needs another step from the customer, most often authenticating with 3D Secure. Stripe's own table of client outcomes lists requires_action as the status you get when 'the customer didn't complete the checkout'.
  • Not part of Incomplete: processing shows as 'Pending', requires_capture as 'Uncaptured', canceled as 'Canceled' and succeeded as 'Succeeded'. Stripe also says that under some error conditions a payment can show as 'Failed' instead of 'Incomplete'.
Sell from your OneSol page with your own Stripe, PayPal, Razorpay or Square account, so one processor's hold doesn't stop every sale. Payments come with Pro.Start free →

How to see where a payment stopped

The Dashboard label is a summary. Stripe's documentation says it 'doesn't include the additional details provided by the PaymentIntent status', and recommends checking the exact value before you act on it.

  • Open the 'Payments' page and click the incomplete payment. The payment's detail page shows its timeline, so you can see whether any attempt was made at all or whether it stopped at an authentication step.
  • To see the exact status, open Workbench: press the tilde key (~) anywhere in the Dashboard, or choose 'Workbench' from the 'Developers' menu. On the payment's page, click the 'Inspector' icon. The 'Overview' tab shows the PaymentIntent as JSON. Search it for status.
  • If the status is requires_action, look at next_action. A value of redirect_to_url means the customer was sent to their bank to authenticate.
  • If an attempt failed, look at last_payment_error. Stripe's docs point to this property for the reason, such as a decline, and the 'Events' and 'Logs' tabs in the Inspector show each attempt.
  • On card payments that reached authentication, the Charge's payment_method_details.card.three_d_secure.result shows the outcome. Stripe only fills this in when the customer attempted to authenticate.

Cause 1: The checkout was opened and abandoned

This is the largest group by a distance. Stripe tells developers to 'create the PaymentIntent as soon as you know the amount to charge so Stripe can record all attempted payments'. Its newer payment forms need a PaymentIntent before they can even be shown; Stripe's support page about this says the initial PaymentIntent 'has an Incomplete status when it is created'. So every visitor who reaches your payment page, looks at the price and closes the tab leaves an Incomplete payment with no payment method. That is the payment carrying 'The customer has not entered their payment method'.

There is nothing to fix on the payment itself. Nobody was charged and nothing needs refunding. If you want to win some of those people back and you use Stripe Checkout, Stripe has a built-in recovery flow:

  • Stripe says Checkout Sessions expire 24 hours after they are created by default. You can shorten that with expires_at, to a minimum of 30 minutes, if you want to hear about abandonment sooner.
  • When a session expires, Stripe sends the checkout.session.expired event. If you created the session with after_expiration.recovery enabled, the event includes a recovery URL that opens a copy of the original checkout.
  • That recovery URL works for 30 days. Stripe classes cart-abandonment emails as promotional, so the customer has to have agreed to promotional emails before you send one; Checkout can collect that consent with consent_collection[promotions].

Cause 2: The customer was sent to 3D Secure and never finished

3D Secure is the extra check from the customer's bank: a one-time code by text, a prompt in their banking app, or a fingerprint. Stripe says it triggers 3DS automatically when regulations require it, such as Strong Customer Authentication in Europe and the UK, when an issuer asks for it with a soft decline, or when certain Stripe optimisations apply. Your Radar rules can request it too. Stripe also points out that while it starts the request, the requirement comes from the card issuer.

While the bank's check is on screen, the PaymentIntent sits at requires_action. If the customer closes the window, can't find their phone, or the code never arrives, it simply stays there and the payment shows 'Incomplete'. Stripe only attempts the charge after authentication, so no money moved. If the bank rejects the authentication instead, Stripe says the PaymentIntent goes back to requires_payment_method so the customer can retry or use another method.

One warning before you chase anyone: Stripe's guidance says to make sure the customer is not still authenticating an on-session payment before you treat it as abandoned. A payment that is two minutes old may still be in progress.

  • Open Stripe's 'Authentication' analytics page to see how big the problem is. Its 'Failed 3DS challenge' outcome counts payments where 'the customer abandoned the authentication flow or the payment was rejected by the customer's bank'.
  • The same page has '3DS not actioned', which Stripe describes as the customer not entering the 3DS flow 'or there was an issue with your integration'. A high number here is worth taking to whoever built your checkout.
  • The 'request reasons' chart shows whether 3DS came from an API request, a Radar request, a Stripe request or a Bank request, which tells you which ones you have any control over.

Cause 3: An invoice or subscription is still waiting to be paid

If you use Stripe Billing, some Incomplete payments are simply unpaid bills. Stripe's support article on invoices says a PaymentIntent is created when an emailed invoice is finalized, and 'these PaymentIntents will be labeled as incomplete in your Dashboard until your customer attempts to pay their invoice'. Voiding the invoice or marking it as paid cancels the PaymentIntent automatically.

New subscriptions work the same way. When a subscription needs an immediate first payment, Stripe creates it as incomplete and gives the customer 23 hours to pay. If the first payment needs authentication, the PaymentIntent is requires_action and Stripe sends invoice.payment_action_required so you can bring the customer back to finish it. After 23 hours with no successful payment, the subscription becomes incomplete_expired and its invoice is voided. Stripe says these subscriptions don't bill the customer; to reactivate them, you create a new subscription.

When it is safe to ignore, and when it isn't

Use the exact status, not the label, to decide.

  • Ignore: requires_payment_method payments with no attempts on them. These are visitors who looked and left.
  • Ignore: a decline followed by a successful payment from the same customer a minute later. The first PaymentIntent went back to requires_payment_method and the retry worked.
  • Look closer: a sudden rise in requires_action payments, or a high 'Failed 3DS challenge' share on the 'Authentication' page. Customers are getting stuck at their bank.
  • Look closer: many requires_confirmation payments. Stripe says most integrations skip this state, so this usually means the checkout never sends the final confirmation.
  • Act: a customer says they paid but the payment is Incomplete. They were not charged. Do not fulfil the order; send them back to pay, or a fresh payment link.
  • Never fulfil on anything but a succeeded payment. Stripe recommends using the payment_intent.succeeded webhook for fulfilment rather than the checkout page, because customers can leave the page after paying.

How to reduce incomplete payments

You can't remove 3D Secure where the law or the bank requires it. Stripe says plainly that you can't use its APIs to turn 3DS off manually, and that disabling Radar doesn't stop 3DS from being triggered when it is necessary. What you can control is the friction you add on top.

  • Check your own Radar rules. Stripe warns that 'indiscriminate use of 3DS might lower conversion rates'. In 'Radar' > 'Rules', look at any rule that requests 3D Secure. Stripe's advice is that if a 3DS rule has a high completion rate but few disputes or early fraud warnings, removing it may reduce friction for your customers.
  • Only request 3DS manually if you have a reason to. Setting request_three_d_secure to any asks for a frictionless flow where possible, but Stripe notes the issuer decides the final flow, and a manual request overrides Radar's dynamic 3DS rules.
  • Offer wallets. Stripe's authentication analytics exclude Apple Pay and Google Pay because they use device-based authentication such as biometrics instead of 3DS.
  • Make the authentication step hard to lose. Stripe notes that the bank controls the look of the 3DS screen, but you choose where it appears. Stripe says most businesses show it in a modal over their payment page. Tell customers before they pay that their bank may ask them to confirm.
  • Follow up when Stripe tells you to. For subscriptions, act on invoice.payment_action_required and send the customer back to authenticate within the 23-hour window. For Checkout, use the recovery URL from checkout.session.expired with customers who agreed to hear from you.
  • Test it yourself in a sandbox. Stripe's test card 4000000000003220 always requires 3DS2, and the mock authentication page has a 'Failure' button, so you can see exactly what an abandoned or failed check looks like in your Dashboard.

Where OneSol fits

OneSol's checkout on Pro runs on your own Stripe (or PayPal, Razorpay, Square) account, so these statuses appear in your own Stripe dashboard exactly as described above.

Want a second way to get paid?Sell from your OneSol page with your own Stripe, PayPal, Razorpay or Square account, so one processor's hold doesn't stop every sale. Payments come with Pro.Start free →

Still stuck? More fixes

Frequently asked questions

What does 'Incomplete' mean on a Stripe payment?

It means the payment was started but never finished. In Stripe's own status mapping, a PaymentIntent with the status requires_payment_method, requires_confirmation or requires_action shows as 'Incomplete' on the Payments page. In plain terms: no card was ever submitted, the card was submitted but not confirmed, or the customer was asked to do something extra, usually a 3D Secure check with their bank, and never finished it. An Incomplete payment is not a successful charge, so there is nothing to fulfil.

Why does Stripe say 'The customer has not entered their payment method'?

That note appears on payments that are sitting at requires_payment_method. Stripe's documentation says a PaymentIntent has this status from the moment it is created until a payment method is attached, and that many checkouts create the PaymentIntent as soon as the payment form loads. So a visitor who opened your checkout and left without typing a card leaves exactly this behind. It is the most common Incomplete payment and, on its own, it is not an error.

Are incomplete payments in Stripe safe to ignore?

Mostly, yes. Stripe's support pages describe Incomplete PaymentIntents from abandoned checkouts and unpaid invoices as expected behaviour, and a declined attempt also returns the PaymentIntent to requires_payment_method so it can be retried. They are worth a closer look when they suddenly rise, when many of them stop at requires_action, or when a customer tells you they paid. A customer who says they paid but whose payment shows Incomplete has not been charged.

What happens if a customer abandons 3D Secure on Stripe?

The PaymentIntent stays at requires_action, which the Dashboard shows as 'Incomplete', and no charge is made, because Stripe only attempts the charge after authentication. If the bank rejects the authentication, Stripe says the PaymentIntent moves back to requires_payment_method so the customer can try again or use another payment method. On Stripe's 'Authentication' analytics page, abandoned and rejected checks are both counted under 'Failed 3DS challenge'.

Why is my Stripe subscription 'incomplete'?

When a subscription needs an immediate first payment, Stripe creates it with the status incomplete and the customer has 23 hours to pay. Stripe's docs say it stays incomplete if the first payment fails because of a card error (requires_payment_method) or because the customer still needs to authenticate (requires_action). If nobody pays within 23 hours, the subscription becomes incomplete_expired, the invoice is voided and the customer is not billed. To bring them back, create a new subscription.

Written by

Founder, OneSol · Karachi, Pakistan

Hasnain Saleem is the founder of OneSol. He is a full-stack developer based in Karachi, Pakistan, and runs the web studio Web Newbiz, where he has spent more than four years building websites, online stores and booking systems for small businesses — more than twenty client sites in Laravel, WordPress and WooCommerce.

Run all of this from one link.

Free to start — no card required.