Skip to main content

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.

@marlin/sdk/react gives you three exports — MarlinProvider, MarlinCheckoutButton, and useMarlinCheckout — that let you open a hosted checkout overlay from React without writing any iframe or postMessage code yourself. The provider holds your publishable key in context; the button and hook consume it to launch and manage the checkout.

Installation

@marlin/sdk/react is included in the main @marlin/sdk package. Import from the /react subpath:
import { MarlinProvider, MarlinCheckoutButton, useMarlinCheckout } from "@marlin/sdk/react";

MarlinProvider

Wrap your application (or the subtree that contains checkout UI) with MarlinProvider. It accepts your publishable key and an optional checkout base URL override.
import { MarlinProvider } from "@marlin/sdk/react";

function App() {
  return (
    <MarlinProvider publishableKey="pk_live_...">
      <YourApp />
    </MarlinProvider>
  );
}
Props:
publishableKey
string
required
Your Marlin publishable key. This key is safe to include in client-side code — it is distinct from your secret API key.
checkoutBaseUrl
string
default:"https://checkout.marlin.dev"
Override the checkout base URL. Use this to point at a staging environment during development.
children
ReactNode
required
The React subtree that can use useMarlinCheckout and MarlinCheckoutButton.

MarlinCheckoutButton

MarlinCheckoutButton renders a <button> that opens the checkout overlay when clicked. Pass the invoice ID and optional callbacks directly as props.
import { MarlinProvider, MarlinCheckoutButton } from "@marlin/sdk/react";

function PaymentPage() {
  return (
    <MarlinProvider publishableKey="pk_live_...">
      <MarlinCheckoutButton
        invoiceId="inv_abc123"
        onSuccess={(result) => console.log("Paid!", result)}
        onCancel={() => console.log("Cancelled")}
        onError={(err) => console.error(err)}
      />
    </MarlinProvider>
  );
}
The button label defaults to "Pay with Marlin". Override it with the label prop. Props:
invoiceId
string
required
The invoice ID to pay. The checkout overlay loads the invoice’s payment page.
onSuccess
(result: CheckoutResult) => void
Called when the user completes payment. Receives a CheckoutResult with invoiceId, transactionSignature, and status: "paid".
onCancel
() => void
Called when the user closes the checkout overlay without paying.
onError
(error: Error) => void
Called when an error occurs during the checkout flow.
theme
"light" | "dark" | "auto"
Visual theme for the checkout overlay. Defaults to "auto", which follows the user’s system preference.
label
string
default:"\"Pay with Marlin\""
Text label rendered inside the button.
All standard <button> HTML attributes (except onClick and onError) are forwarded to the underlying element, so you can add className, disabled, data-* attributes, and so on.

useMarlinCheckout

Use the useMarlinCheckout hook when you need to trigger checkout from custom UI — a link, a card click, or a form submission — rather than a dedicated button. The hook returns { open, isOpen, close }.
import { useMarlinCheckout } from "@marlin/sdk/react";

function CustomPayButton({ invoiceId }: { invoiceId: string }) {
  const { open, isOpen, close } = useMarlinCheckout();

  return (
    <button onClick={() => open({ invoiceId })} disabled={isOpen}>
      {isOpen ? "Processing..." : "Pay now"}
    </button>
  );
}
Return values:
NameTypeDescription
open(opts: CheckoutOptions) => voidOpens the checkout overlay. Accepts the same options as MarlinCheckoutButton.
isOpenbooleantrue while the checkout overlay is visible.
close() => voidProgrammatically closes the overlay.
useMarlinCheckout must be called inside a component that is a descendant of MarlinProvider. Calling it outside throws: "useMarlinCheckout must be used within a <MarlinProvider>.".

Full working example

The example below shows a complete checkout page with both a direct button and a custom hook-based trigger.
import {
  MarlinProvider,
  MarlinCheckoutButton,
  useMarlinCheckout,
} from "@marlin/sdk/react";
import type { CheckoutResult } from "@marlin/sdk/react";

function CheckoutControls() {
  const { open, isOpen } = useMarlinCheckout();

  function handleSubscribe() {
    open({
      invoiceId: "inv_plan_may2025",
      theme: "dark",
      onSuccess: (result: CheckoutResult) => {
        console.log("Subscription paid", result.transactionSignature);
      },
      onCancel: () => console.log("User cancelled"),
    });
  }

  return (
    <div>
      {/* Pre-built button for a one-time invoice */}
      <MarlinCheckoutButton
        invoiceId="inv_abc123"
        label="Pay invoice"
        onSuccess={(result) => console.log("Invoice paid", result)}
        onCancel={() => console.log("Cancelled")}
      />

      {/* Custom button using the hook */}
      <button onClick={handleSubscribe} disabled={isOpen}>
        {isOpen ? "Opening..." : "Subscribe — $49/mo"}
      </button>
    </div>
  );
}

export default function App() {
  return (
    <MarlinProvider publishableKey={process.env.NEXT_PUBLIC_MARLIN_KEY!}>
      <CheckoutControls />
    </MarlinProvider>
  );
}