Skip to main content
Use this page to understand how card payments through Payment Element get authenticated.

What you have to do

Nothing extra. elements.submit(...) completes card authentication for you when a payment requires it. You do not collect anything additional in your checkout form, and you do not orchestrate the authentication yourself.
Authentication uses the buyer and purchase details your server already sends when it creates the transaction — the buyer and products you pass to POST /v2/transactions. Keep those complete and accurate and authentication has what it needs.
Send a complete buyer record: buyer.email, buyer.name, a buyer.phone that includes its country code, and every field of buyer.address:country, state, city, zipCode, street, number and neighborhood. Only complement is optional.

What you get back

submit(...) resolves once the payment has reached an outcome, whether or not authentication was involved. Read status on the result:
  • succeeded — the payment was approved.
  • processing — the payment is still resolving. Wait for a webhook.
  • failed, refused, canceled, timed_out — the attempt did not go through. Show the buyer the returned message and let them try again.
See the SDK reference for the full status list.

If the buyer is interrupted

A buyer can reload the page or navigate away mid-payment. Resume the same transaction instead of starting a new checkout attempt:
Persist the transaction id as soon as your backend returns it, so you still have it after a reload.

Card authentication after a reload

A payment waiting on card authentication (pre-charge 3DS) was tied to the element session that captured the card, and a reload starts a new session. resume() self-heals this for you: mount a CardElement and call resume(). The SDK asks the buyer to re-enter the card in the mounted element, re-tokenizes it, proves it is the same card, supersedes the stale challenge, and completes authentication — resolving to a terminal result. No new checkout attempt or new transaction id, and no extra branching in your code.
The re-entered card must be the same card as the original attempt — a different card is rejected.
If no card element is mounted, or the buyer does not re-enter within the timeout, resume() resolves to a clear terminal result telling the buyer to start a new payment attempt — it never loops or hangs.
Advanced integrators who want their own re-collect UX can pass manualReentry: true to get status: "requires_reentry" back instead of auto-healing, then call resume() again after re-collecting the card. See the SDK reference.

Final state

A buyer may finish authenticating after your first browser callback resolves. Do not fulfill an order from the browser result alone — webhook delivery or server-side reconciliation is the final source of truth for payment state.