The embed
public/sdk.js mounts an iframe pointing at the hosted checkout. The merchant pins their settlement anchor in the init call on their own site:
The SRI pin
Any edit to
public/sdk.js MUST regenerate SDK_SRI in src/lib/sdk/embedSnippet.ts. A stale pin makes browsers refuse to execute the SDK entirely — every embed on every merchant site stops working.Three failures that made the embed DOA
Found in the 2026-07-28 audit. All fixed, all worth understanding because each was invisible in normal testing.Sandbox without allow-same-origin
Sandbox without allow-same-origin
The iframe was sandboxed without
allow-same-origin, so the app crashed at boot the moment it touched localStorage. The embed had never worked.Published snippet used the apex domain
Published snippet used the apex domain
The apex 307-redirects to
www, and the redirect broke the origin check. The snippet must use the canonical www host.The SDK targeted the wrong checkout
The SDK targeted the wrong checkout
CHECKOUT_PATH was hardcoded to /checkout — the legacy atomic widget — rather than /pool-checkout. That silently dropped the pinned anchor, which meant the verification the anchor exists for never ran.Bundle budget
Now route-aware and lazy viaconfig/walletRoutes.ts and contexts/WalletBootContext.tsx: 923 KB, 188 ms.
scripts/check-bundle-budget.mjs fails CI if wallet-vendor becomes statically reachable from the entry again.
Do not “fix” a build error by re-adding a static import of
@/config/appkit. That is the exact regression the budget check exists to catch.Content Security Policy
Origins that have broken production before and will again:
Third-party FX APIs —
frankfurter.app, exchangerate.host, open.er-api.com — are deliberately not allowlisted. EUR/USD comes from an on-chain Uniswap V3 pool, never a third-party API.
The SPA rewrite trap
Checkout states
The widget has explicit states for every failure mode rather than a generic error:
Two resilience behaviours worth knowing:
- Quote auto-refresh. A silent re-quote 30 seconds before expiry plus a 3-second “rate updated” pill, so a customer is never surprised by a number that moved while they were about to pay.
- Closed-tab recovery. The active payment intent is stamped into local storage on broadcast. On the next mount the widget calls
payment-status: confirmed goes straight to success, failed clears the key, still-confirming leaves it for the next mount.