Skip to main content
Use this guide to execute a card transaction after you have a connected customer. You will list stored cards, add new ones through a MoonPay-hosted frame, get a quote, and execute the transaction — with MoonPay handling PCI-compliant card collection, payment orchestration, and all verification challenges inside hosted frames. See the Going Live section for requirements you must meet before taking this integration to production.

Prerequisites

  • A MoonPay account with card payments enabled. Contact your MoonPay account team to enable it.
  • A connected customer (via client.getConnection() or client.connect()).
  • A UI surface where you can render MoonPay frames (iframe on web, or WebView on mobile).
  • A destination wallet address for the purchased crypto.

Flow overview

1

List payment methods

Fetch the customer’s available payment method types and stored cards.
The result contains two collections:
  • paymentMethodConfigs — available payment method types. Check for type: "card" to confirm card payments are available for this customer.
  • paymentMethods — the customer’s stored cards. Each entry includes brand, last4, expirationMonth, expirationYear, cardType, and availability.
Display active cards in your payment method picker. For inactive cards (availability.active: false), show the reasons value and prompt the user to add a new card.
If paymentMethods is empty and paymentMethodConfigs includes type: "card", use the Add a card flow.
2

Add a card

When the customer needs to add a new card, set up the Add Card frame. The frame collects card details and billing address inside a PCI-compliant MoonPay-hosted UI — card data never touches your domain. For the frame URL, size, and events, see the Add Card frame reference.
Add a card
The complete event returns the new card’s full details including its id. Use this id to get a quote. You do not need to fetch payment methods again.
To send cards from your own PCI-compliant server instead, see Import a card.
3

Get a quote

With a stored card selected, request a quote. Pass the card’s id in paymentMethod so MoonPay can evaluate card-specific requirements.
On the same confirmation view, show the contextual quote summary and fee breakdown before the customer submits the card payment. You remain responsible for this presentation. See Going Live for the canonical requirements and fee behavior for how fees relate to the source amount. Monitor expiresAt and refresh the quote before it expires. If the quote expires after the buy button is loaded, the frame sends an error with code quoteExpired. Call buyResult.value.setQuote(newSignature) with a new quote instead of re-creating the frame.
4

Execute the transaction

Headless buy button

Call client.setupBuyButton() with headless: true when the customer confirms the purchase in your UI. In headless mode the frame renders no visible UI: it starts the purchase as soon as it loads and emits events for you to handle, so you keep full control over your purchase UI. For the frame URL, parameters, and events, see headless mode in the Buy Button frame reference.
setupBuyButton
5

Handle challenges

When the buy button emits a challenge event, the customer must complete one or more verification steps before the transaction can proceed. Set up the challenge frame with the URL from the event payload — do not construct the URL yourself. For the frame URL, parameters, and events, see the Challenge frame reference.The frame is self-driving: after initialization, it sequences through all required verification steps, creates the transaction, and emits complete when the pipeline finishes.
Handle challenges
When you receive complete, cancelled, or error from the challenge frame, call buyResult.value.dispose() to also tear down the buy button.
The frame handles all verification types automatically — KYC, Strong Customer Authentication (SCA), CVC re-entry, wallet ownership, micro-authorization, and 3D Secure (3DS). You never need to distinguish between them.
6

Track the transaction

When the buy button or challenge frame emits complete, the payload includes { transaction: { id, status } }. Unless status is failed, the transaction is created and payment is processing. A failed transaction carries failureCode and failureReason, and has no id when the transaction was never created. See the Buy Button frame reference for the failure codes.
Track the transaction

Transaction statuses

Transactions have the following statuses:
  • Pending: The transaction has been initiated and the payment accepted. The assets are being transferred.
  • Complete: The transaction is finalized. The payment is complete and the assets have been delivered to their destination.
  • Failed: The transaction has failed. The payment was not executed and funds were not transferred.
You can also track transaction status with the existing transaction-updated webhook.
7

Delete a stored card (optional)

Let customers remove stored cards at any time.
Delete a stored card
  • Deleting an already-deleted card returns success (idempotent).
  • Deleting a card with a pending transaction is rejected.
  • Only payment methods with allowsDeletion: true can be deleted.