Skip to main content

Redirect vs. embed

After you create a checkout session, the response includes a hosted url. You can present it two ways:
  • Redirect — send the customer to url (window.location.href = url). Simplest to integrate; the customer leaves your page and comes back via return_url. See the Quickstart.
  • Embed — load url in an <iframe> so checkout renders in context, without a full-page navigation. This page covers embedding.
Both use the exact same server-side session creation — embedding changes only how the returned url is presented on your frontend.
Soap checkout is cookieless: the session’s client_secret travels as a query parameter on every request, so cross-origin embedding does not depend on third-party cookies and needs no special browser configuration.

Before you start: register your embedding domain

Two things are tied to the domain of the page that hosts the iframe (your site’s top-level domain). Share your production and staging origins with Soap once, during onboarding:
  1. Framing allowlist — Soap’s checkout only allows itself to be framed by approved origins (CSP frame-ancestors). Until your origin is allowlisted, the iframe will render blank.
  2. Apple Pay domain registration — Apple validates Apple Pay against the top-level page, so your domain must be registered for Apple Pay web merchant validation. As part of registration, Soap sends you a domain verification file to host at:
    Keep the file in place permanently — registrations are re-verified periodically and lapse if the file disappears. Cards and Google Pay work without any of this.

1. Create the session on your backend

Almost unchanged from the redirect flow — create the checkout server-side (so your API key stays private), pass a return_url, and set experience: "iframe". That flag tells Soap the checkout will be framed: Soap redirects the customer to return_url inside the iframe on completion, and Apple Pay validates against your embedding domain instead of Soap’s hosted one.
Without experience: "iframe" the checkout still renders inside your frame, but Apple Pay will fail: sessions are validated against Soap’s hosted domain, which won’t match your top-level page.

2. Embed the checkout URL in an iframe

Load the returned url into an <iframe>. The allow="payment" attribute is required for Apple Pay, Google Pay, and other Payment Request wallets to work inside the frame.
Without allow="payment" the checkout still renders and cards work, but Apple Pay / Google Pay buttons will not appear or will fail to open. The other permissions (camera, microphone, geolocation, clipboard-write) support identity verification, geo-checks, and copy actions used by some flows.

3. Know when checkout completes

Use two signals, in order of authority:

Webhooks (source of truth)

Payment state is confirmed server-side. Always reconcile off webhooks — never treat a client-side event as proof of payment.

return_url + postMessage (UX hint)

On completion the checkout redirects within the iframe to your return_url. Because that page loads inside the frame, it can notify your top-level page with postMessage:
Listen for it on the embedding page to update your UI (close the frame, show a receipt, etc.):
The completion message is sent by your own return_url page (it loads inside the iframe after the checkout redirects to it), so event.origin is your site’s origin — not the Soap wallet domain. Validate it against your own origin as shown above, and treat the message as a UX hint only: confirm the payment via webhooks.

Caveats

Apple validates Apple Pay against the top-level page domain — the site hosting the iframe, not the checkout iframe itself. To offer Apple Pay in-frame you need both pieces from this guide: your embedding domain registered with Soap for Apple Pay web merchant validation (see Before you start), and the session created with experience: "iframe". At payment time the checkout detects your top-level domain automatically — the only ongoing requirement is keeping the verification file from Before you start hosted.
Sandbox checkout URLs are on wallet-sandbox.paywithsoap.com; production on wallet.paywithsoap.com. The url in the API response already points at the right one for the key you used.