Checkout
Embedded checkout
Show TuCapi Business checkout inside your site, in an iframe, with events for your UI.
2Paste the code
The dashboard gives you this code, ready, for the link you choose:
data-tucapi-checkoutstringRequiredThe link slug, or the fullembedUrlof an API charge.data-localees | enOptionalLanguage. Without it, your customer's browser language.data-themelight | darkOptionalTheme. Without it, your customer's system theme.data-checkout-originstringOptionalOnly if you use your own checkout domain, e.g.https://pay.yourstore.com.
The frame adjusts its height on its own as the content changes.
index.html
HTML
<div data-tucapi-checkout="LINK_SLUG" data-locale="en" data-theme="light"></div><script src="https://pay.tucapi.com/embed.js" async></script>3With an API charge
POST /v1/charges returns embedUrl alongside checkoutUrl.
Pass it as is to your frontend, in data-tucapi-checkout.
index.html
HTML
<div data-tucapi-checkout="https://pay.tucapi.com/embed/k7x2m9qz"></div><script src="https://pay.tucapi.com/embed.js" async></script>POST /v1/charges
{ "checkoutUrl": "https://pay.tucapi.com/k7x2m9qz", "embedUrl": "https://pay.tucapi.com/embed/k7x2m9qz"}4Mount it from JavaScript
If you'd rather control mounting, use TucapiCheckout.mount(container, options).
slugstringOptionalThe link slug. Useslugorurl.urlstringOptionalA charge'sembedUrl.localees | enOptionalCheckout language.themelight | darkOptionalCheckout theme.onEventfunctionOptionalGets every event:{ type, slug, data }.checkoutOriginstringOptionalYour own checkout domain, if you have one.titlestringOptionalAccessible iframe title. Defaults toCheckout.minHeightnumberOptionalInitial height in pixels. Defaults to 520.
mount returns an object with destroy() to remove the checkout.
checkout.js
JavaScript
const checkout = TucapiCheckout.mount("#checkout", { slug: "k7x2m9qz", // or url: charge.embedUrl locale: "en", theme: "light", onEvent: (e) => console.log(e.type, e.data),});// To remove itcheckout.destroy();5Listen to events
Events reach onEvent and fire as a CustomEvent on the container, prefixed with tucapi:.
| Event | When | data |
|---|---|---|
ready | Checkout loaded. | {} |
resize | The height changed. embed.js already resizes the iframe. | { height } |
order.created | Your customer picked a method and an order was created. | { orderId, paymentMethod } |
payment.processing | The payment is being verified. | { orderId } |
payment.succeeded | The payment was confirmed. | { orderId } |
payment.failed | It failed, expired, was canceled or was rejected. | { orderId, reason } |
reason is failed, expired, cancelled or rejected. In order.created, paymentMethod is uppercase (PAYPAL, STRIPE…).
Events don't confirm the payment
Any script on your page can fake an event. Before delivering a product, confirm with the
order.paid webhook or with GET /v1/charges/{id} from your server.checkout.js
JavaScript
document .querySelector("#checkout") .addEventListener("tucapi:payment.succeeded", (e) => { // UI hint only. Confirm the payment on your server. showThankYou(e.detail.data.orderId); });How each method behaves
- Card. Paid inside the frame. If the bank asks for 3-D Secure, its window opens on top, without leaving your page. Apple Pay and Google Pay aren't offered inside the iframe.
- PayPal. PayPal can't open inside an iframe, so it opens in a separate window. The frame shows “Confirming your payment” and moves on by itself. If the browser blocks the window, checkout offers to open PayPal in a tab.
- Zelle. Same as the regular checkout, inside the frame.
Security
- Only the origins on your list can embed your checkout. The regular checkout can't be embedded anywhere.
- The list is per merchant. Your site can't embed another merchant's links, or the other way around.
- Events are sent with
postMessageonly to your site's exact origin, never to*. - Your page never sees card, PayPal or bank account data.
Troubleshooting
| Symptom | Cause |
|---|---|
| The frame is empty or shows a broken page. | Your origin isn't on the list. Check www, the scheme and the port. The console shows a frame-ancestors error. |
| No events arrive. | The page origin doesn't match the list, or the code sits inside another iframe. |
| The link shows as unavailable. | It's paused, expired or already paid. |
| The PayPal window doesn't open. | A popup blocker. Checkout shows a button to open it in a tab. |