Embed Checkout
Embed DonutMe checkout directly into your website using an iframe — no SDK installation required.
Quick Start
Add this snippet anywhere in your HTML to embed a checkout session:
HTML
<iframe
src=<span class="text-lime-400">"https:<span class="span>text-neutral-500<span class="text-lime-400">">//donutme.xyz/en/pay/PLAN_ID/checkout"span>span>
width=<span class="text-lime-400">"100%"span>
height=<span class="text-lime-400">"700"span>
style=<span class="text-lime-400">"border: none; border-radius: 12px"span>
allow=<span class="text-lime-400">"payment; clipboard-write"span>
></iframe>Replace PLAN_ID with your actual payment plan ID from the dashboard.
Listening for Events
The checkout iframe communicates with the parent page via postMessage. Subscribe to these events to react to payment status changes:
JavaScript
class="text-sky-400">window.addEventListener(class="text-pink-400">class="text-lime-400">"message", (event) => {
class="text-pink-400">class=class="text-pink-400">class="text-lime-400">"text-neutral-500">// Always verify the origin in production
class="text-pink-400">if (event.origin !== class="text-pink-400">class="text-lime-400">"https:class="text-pink-400">class="text-neutral-500class="text-pink-400">class="text-lime-400">">//donutme.xyz") class="text-pink-400">return;
switch (event.data?.class="text-pink-400">type) {
case class="text-pink-400">class="text-lime-400">"donutme:payment-completed":
class="text-sky-400">console.log(class="text-pink-400">class="text-lime-400">"Payment successful:", event.data.payload);
class="text-pink-400">class=class="text-pink-400">class="text-lime-400">"text-neutral-500">// { transactionId, amount, token, chain }
break;
case class="text-pink-400">class="text-lime-400">"donutme:checkout-session-updated":
class="text-sky-400">console.log(class="text-pink-400">class="text-lime-400">"Session changed:", event.data.payload);
class="text-pink-400">class=class="text-pink-400">class="text-lime-400">"text-neutral-500">// { status, selectedOption }
break;
case class="text-pink-400">class="text-lime-400">"donutme:checkout-session-terminated":
class="text-sky-400">console.log(class="text-pink-400">class="text-lime-400">"Session ended:", event.data.payload);
class="text-pink-400">class=class="text-pink-400">class="text-lime-400">"text-neutral-500">// { reason: class="text-pink-400">class="text-lime-400">"expired" | class="text-pink-400">class="text-lime-400">"cancelled" }
break;
}
});Event Reference
| Event | Payload | Description |
|---|---|---|
donutme:payment-completed | { transactionId, amount, token, chain } | Payment confirmed on-chain |
donutme:checkout-session-updated | { status, selectedOption } | Customer changed payment option or wallet |
donutme:checkout-session-terminated | { reason } | Session expired or was cancelled |
Framework Examples
React
TSX
class="text-pink-400">import { useEffect } class="text-pink-400">from class="text-pink-400">class="text-lime-400">"react";
class="text-pink-400">export class="text-pink-400">function DonutMeCheckout() {
useEffect(() => {
class="text-pink-400">function handler(event: MessageEvent) {
class="text-pink-400">if (event.origin !== class="text-pink-400">class="text-lime-400">"https:class="text-pink-400">class="text-neutral-500class="text-pink-400">class="text-lime-400">">//donutme.xyz") class="text-pink-400">return;
class="text-pink-400">if (event.data?.class="text-pink-400">type === class="text-pink-400">class="text-lime-400">"donutme:payment-completed") {
class="text-sky-400">console.log(class="text-pink-400">class="text-lime-400">"Paid:", event.data.payload);
}
}
class="text-sky-400">window.addEventListener(class="text-pink-400">class="text-lime-400">"message", handler);
class="text-pink-400">return () => class="text-sky-400">window.removeEventListener(class="text-pink-400">class="text-lime-400">"message", handler);
}, []);
class="text-pink-400">return (
<class="text-sky-400">iframe
src=class="text-pink-400">class="text-lime-400">"https:class="text-pink-400">class="text-neutral-500class="text-pink-400">class="text-lime-400">">//donutme.xyz/en/pay/PLAN_ID/checkout"
width=class="text-pink-400">class="text-lime-400">"100%"
height={700}
style={{ border: class="text-pink-400">class="text-lime-400">"none", borderRadius: 12 }}
allow=class="text-pink-400">class="text-lime-400">"payment; clipboard-write"
/>
);
}Vue
Vue
<class="text-sky-400">script setup lang=class="text-pink-400">class="text-lime-400">"ts">
class="text-pink-400">import { onMounted, onUnmounted } class="text-pink-400">from class="text-pink-400">class="text-lime-400">"vue";
class="text-pink-400">function handler(event: MessageEvent) {
class="text-pink-400">if (event.origin !== class="text-pink-400">class="text-lime-400">"https:class="text-pink-400">class="text-neutral-500class="text-pink-400">class="text-lime-400">">//donutme.xyz") class="text-pink-400">return;
class="text-pink-400">if (event.data?.class="text-pink-400">type === class="text-pink-400">class="text-lime-400">"donutme:payment-completed") {
class="text-sky-400">console.log(class="text-pink-400">class="text-lime-400">"Paid:", event.data.payload);
}
}
onMounted(() => class="text-sky-400">window.addEventListener(class="text-pink-400">class="text-lime-400">"message", handler));
onUnmounted(() => class="text-sky-400">window.removeEventListener(class="text-pink-400">class="text-lime-400">"message", handler));
</class="text-sky-400">script>
<class="text-sky-400">template>
<class="text-sky-400">iframe
src=class="text-pink-400">class="text-lime-400">"https:class="text-pink-400">class="text-neutral-500class="text-pink-400">class="text-lime-400">">//donutme.xyz/en/pay/PLAN_ID/checkout"
width=class="text-pink-400">class="text-lime-400">"100%"
height=class="text-pink-400">class="text-lime-400">"700"
style=class="text-pink-400">class="text-lime-400">"border: none; border-radius: 12px"
allow=class="text-pink-400">class="text-lime-400">"payment; clipboard-write"
/>
</class="text-sky-400">template>Customization
The embedded checkout automatically inherits the checkout appearance settings from your project (banner, cover, accent color). Configure these in:
Dashboard → Project Settings → Checkout AppearanceSecurity Notes
- Always validate
event.originagainsthttps://donutme.xyzbefore processing messages - Never trust the iframe
postMessagedata for server-side fulfillment — always verify via the Webhooks callback - The
allow="payment; clipboard-write"attribute enables wallet interactions within the iframe