Skip to main content
Use this page when you are moving from a demo integration to a production-safe checkout.

Production-safe flow

  1. Disable duplicate submits in the browser.
  2. Call elements.submit(...) once per checkout attempt.
  3. Let your backend create the transaction.
  4. Let elements.submit(...) complete card authentication when the payment requires it.
  5. Resume the transaction if the buyer is interrupted mid-payment.
  6. Fulfill only from webhook or reconciliation state.

Frontend submit pattern

elements.submit(...) drives the whole attempt. It creates an Element session if needed, asks the hosted card field to tokenize, calls your createTransaction callback with the token payload, then completes any card authentication the payment requires before resolving. Authentication needs no extra input from your checkout form. It uses the buyer and products your backend already sends when it creates the transaction. See 3D Secure.

Resume an interrupted payment

If the buyer reloads or navigates away mid-payment, resume the same transaction instead of starting a new attempt:
Persist the transaction id as soon as your backend returns it.
resume() cannot recover a payment that was waiting on card authentication. It returns failed — start a new payment attempt. See 3D Secure.

Token payload

Your createTransaction callback receives non-sensitive card metadata with the token:
Send tokenData.token to your backend to create the transaction. Use brand, last4, exp_month, and exp_year only for provisional checkout UI or your own backend bookkeeping; final payment state still comes from the transaction response, webhook, or reconciliation.

Backend request example

Backend response example

Return this payload to the browser unchanged. next_action is opaque — elements.submit(...) reads it and completes card authentication for you.

Common error

Fix: do not create the transaction until the browser has a token from Payment Element. If a challenge flow was interrupted, reconcile the transaction before letting the customer retry.

Invalid state handling

Keep the submit button disabled until the card field reports a valid state:
If elements.submit(...) returns { "status": "error" }, do not call your backend again with a missing or stale token. Show the returned error, let the buyer correct the card details, then run a new checkout attempt.

Final-state rule

A browser success message is not enough to fulfill an order. Final fulfillment belongs to webhook-confirmed or reconciled payment state.