Documentation Index
Fetch the complete documentation index at: https://yanhgming.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
This page walks through each integration pattern for @marlin/checkout in full detail. Choose the tab that matches your environment.
The data-attribute pattern requires no build step. Add the CDN script to your page, mark any button or link with data-marlin-checkout, and the SDK auto-binds click handlers on DOMContentLoaded.Add the script
Paste the CDN script tag before the closing </body> tag of your page.<script src="https://unpkg.com/@marlin/checkout/dist/checkout.js"></script>
Mark your trigger element
Add data-marlin-checkout to any clickable element. Include either data-invoice-id for a one-time payment or data-plan-slug for a subscription.<!-- One-time payment -->
<button data-marlin-checkout data-invoice-id="inv_abc123">
Pay $25.00
</button>
<!-- Subscription -->
<button data-marlin-checkout data-plan-slug="pro-monthly" data-theme="dark">
Subscribe
</button>
Supported data-* attributes:| Attribute | Required | Description |
|---|
data-marlin-checkout | Yes | Marks the element as a checkout trigger. The SDK binds a click handler automatically. |
data-invoice-id | One of these | Invoice ID for a one-time payment. |
data-plan-slug | One of these | Plan slug for a subscription. |
data-theme | No | Widget color theme: light, dark, or auto (default). |
You must provide either data-invoice-id or data-plan-slug. Omitting both causes the SDK to throw when the element is clicked.
Use MarlinCheckout.open() for full programmatic control. This pattern works in vanilla JavaScript and in any framework that doesn’t need React-specific state management.Install or import
npm install @marlin/checkout
Or load from CDN:<script src="https://unpkg.com/@marlin/checkout/dist/checkout.js"></script>
Open the widget
Call MarlinCheckout.open() with an options object. It returns a CheckoutHandle you can use to close the widget programmatically.import { MarlinCheckout } from "@marlin/checkout";
const handle = MarlinCheckout.open({
invoiceId: "inv_abc123",
theme: "dark",
onSuccess: ({ invoiceId, txHash }) => {
console.log("Payment successful!", { invoiceId, txHash });
window.location.href = "/thank-you";
},
onError: ({ code, message }) => {
console.error("Payment failed:", code, message);
},
onClose: () => {
console.log("Widget closed");
},
});
Close programmatically (optional)
Store the handle and call handle.close() whenever you need to dismiss the overlay from outside the widget — for example, after a timeout or a navigation event.// Close the widget after 10 minutes
setTimeout(() => handle.close(), 10 * 60 * 1000);
OpenOptions reference:Invoice ID for a one-time payment. Mutually exclusive with planSlug. One of these two is required.
Subscription plan slug. Mutually exclusive with invoiceId. One of these two is required.
theme
"light" | "dark" | "auto"
default:"\"auto\""
Visual theme passed to the hosted iframe. "auto" follows the user’s system preference.
onSuccess
(data: { invoiceId?: string; txHash?: string }) => void
Called after a successful payment. Receives the invoice ID and the Solana transaction hash.
onError
(error: { code: string; message: string }) => void
Called when the widget encounters an error. The code field is a machine-readable error identifier.
Called whenever the widget closes — whether from a successful payment, an error, the Escape key, a backdrop click, or handle.close().
@marlin/checkout/react exports MarlinCheckoutButton and useMarlinCheckout. Both are self-contained — they do not require a context provider.Install
@marlin/checkout includes the React bindings.npm install @marlin/checkout
Use the pre-built button
MarlinCheckoutButton renders a <button> that opens the widget on click. Pass invoiceId or planSlug plus your callbacks.import { MarlinCheckoutButton } from "@marlin/checkout/react";
function CheckoutPage() {
return (
<MarlinCheckoutButton
invoiceId="inv_abc123"
theme="light"
onSuccess={({ txHash }) => console.log("Paid!", txHash)}
onError={({ message }) => alert(message)}
className="btn btn-primary"
>
Pay with Crypto
</MarlinCheckoutButton>
);
}
The children prop sets the button label (default: "Pay with Marlin").Or use the hook for custom UI
useMarlinCheckout gives you open and loading when you need to trigger checkout from non-button UI.import { useMarlinCheckout } from "@marlin/checkout/react";
function CustomButton({ invoiceId }: { invoiceId: string }) {
const { open, loading } = useMarlinCheckout();
return (
<button onClick={() => open(invoiceId)} disabled={loading}>
{loading ? "Processing..." : "Checkout"}
</button>
);
}
The hook also accepts a full OpenOptions object:open({
invoiceId: "inv_abc123",
theme: "dark",
onSuccess: (data) => router.push("/success"),
});
MarlinCheckoutButton props:Invoice ID for a one-time payment. Provide invoiceId or planSlug.
Subscription plan slug. Provide invoiceId or planSlug.
theme
"light" | "dark" | "auto"
Widget color theme.
onSuccess
(data: { invoiceId?: string; txHash?: string }) => void
Called after a successful payment.
onError
(error: { code: string; message: string }) => void
Called when the widget encounters an error.
Called when the widget closes for any reason.
children
ReactNode
default:"\"Pay with Marlin\""
Content rendered inside the button.
CSS class name to apply to the button element.
Disables the button. The widget will not open while disabled is true.
Staging override
To point the widget at a staging environment, set globalThis.MARLIN_WIDGET_URL before any MarlinCheckout calls. The SDK reads this value at open-time.
// Set this before importing or calling MarlinCheckout
globalThis.MARLIN_WIDGET_URL = "https://staging-widget.marlin.fi";
The widget closes automatically when the user presses the Escape key or clicks the dark backdrop outside the iframe. Your onClose callback fires in both cases.
| Action | Result |
|---|
| Escape key | Overlay fades out, onClose fires |
| Backdrop click (outside iframe) | Overlay fades out, onClose fires |
handle.close() | Overlay fades out, onClose fires |
| Successful payment | onSuccess fires, then onClose fires |
| Widget error | onError fires, then onClose fires |