Prerequisites
- An authenticated customer, either connected through the connect flow or logged in through the Auth frame on the Customer API path.
- A UI surface where you can render frames (WebView on mobile, iframe on web).
When challenges appear
Challenges are extra steps a customer must complete before MoonPay can continue an action. Common reasons include:- Strong Customer Authentication (SCA), for example 3D Secure
- Identity verification (KYC)
- Card-specific checks such as CVC re-entry or micro-authorization
challenge event that points to the
Challenge frame. The Customer API returns a
kyc.challenge URL when verification needs a hosted step.
Where challenges are emitted
Each emitting surface hands you a fully-formed URL that you load into the dedicated Challenge frame:- The Apple Pay frame emits
challengefor Apple Pay transactions. - The Google Pay frame emits
challengefor Google Pay transactions. - The buy frame emits
challengefor card transactions (see Pay with card). - The Customer API returns
kyc.challenge({ url, expiresAt }) onPATCH /customers/{id}/kycwhen verification needs a hosted step, and on subsequentGET /customers/{id}responses while the challenge is outstanding. Render theurlin the Challenge frame the same way you render a frame-emitted challenge URL. See Handle the hosted challenge.
challenge event uses the same envelope across all of the frames:
Example challenge event
How to handle a challenge
- Listen for the
challengeevent on the frame. Treat the action as blocked until the challenge resolves. - Mount the Challenge frame at the URL from the event payload. Pass the URL through as-is — do not construct or modify it. See the Challenge frame reference for the frame URL, parameters, and events.
- Handle the Challenge frame events:
ready— the challenge UI is rendered and visible.complete— verification resolved. The Challenge frame reports any downstream artifacts (for example, the transactionidandstatusfor the buy flow).cancelled— the customer dismissed the challenge. Offer a retry path.error— the challenge failed. Log thecodeandmessage(both are developer-facing and not intended for end-user UI) and show the customer a generic next step, such as retrying or choosing a different payment method.
- Tear down the originating frame after
complete,cancelled, orerror. For the buy frame, callbuyResult.value.dispose().
Implementation tips
- Use a full-screen surface on mobile: challenge flows often involve authentication or verification, so treat them like a separate screen or full sheet.
- Validate
postMessageevents: if you integrate frames manually, validate origin and message shape. The frames protocol documents the shared envelope format. - Handle cancellation and timeouts: if the customer closes the challenge or it fails, show a clear next step (retry, choose a different payment method, or exit the flow).