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.

Every invoice you create in Marlin comes with a paymentUrl — a fully hosted checkout page at checkout.marlin.fi that handles wallet connection, transaction building, and on-chain confirmation. You do not need to build any payment UI. Share the link and Marlin takes care of the rest. When you create an invoice, Marlin generates a paymentUrl automatically. No extra call or configuration is required.
import { Marlin } from "@marlin/sdk";

const marlin = new Marlin({ apiKey: process.env.MARLIN_API_KEY! });

const invoice = await marlin.invoices.create({
  customerId: "cus_01HXYZ",
  currency: "USDC",
  lineItems: [
    { description: "Consulting — May 2026", quantity: 1, unitAmount: 25000 },
  ],
});

// Ready to share immediately
console.log(invoice.paymentUrl);
// https://checkout.marlin.fi/i/tok_abc123
The paymentUrl follows the format https://checkout.marlin.fi/i/{token} where {token} is a short-lived opaque token tied to the invoice. The token is not the invoice ID — this prevents customers from guessing or enumerating other invoices.

Subscription plan checkout URLs

For recurring billing plans, the hosted checkout URL is derived from the plan’s public slug:
https://checkout.marlin.fi/sub/{planSlug}
Create a plan and then share or embed this URL anywhere — in an email, a pricing page, or a “Subscribe” button.
const plan = await marlin.plans.create({
  name: "Pro Monthly",
  currency: "USDC",
  amount: 4900,
  interval: "month",
});

// Plan checkout URL (use plan.publicSlug from the response)
const checkoutUrl = `https://checkout.marlin.fi/sub/${plan.id}`;
Plan slugs are stable and do not expire, so you can hardcode them into marketing pages and emails.

What the customer experiences

The checkout page at checkout.marlin.fi supports any Solana wallet (Phantom, Backpack, Solflare, and any wallet adapter-compatible wallet). The flow:
  1. The customer opens the payment link in a browser.
  2. They click Pay with Wallet and connect their Solana wallet.
  3. The page shows the invoice amount, line items, and due date.
  4. The customer clicks Pay and approves the transaction in their wallet.
  5. Marlin confirms the transaction on-chain and displays a success screen with a Solscan link.
For subscription checkouts, the customer also selects an authorization period (6 months, 1 year, or 2 years) before signing. This sets the maximum total spend the Marlin program is authorized to charge.

What happens after payment

Once the transaction is confirmed on Solana:
  1. Marlin detects the on-chain confirmation.
  2. The invoice status transitions to paid (or the subscription activates).
  3. Marlin posts an invoice.paid (or subscription.activated) webhook to your endpoint.
  4. Funds settle directly to your merchant wallet — Marlin does not hold them.
The webhook is how your server knows to fulfill the order. See the Accept payments guide for a full webhook handler example.

Theme and appearance

The hosted checkout page automatically follows the customer’s OS preference (light or dark). There are no per-merchant branding options on the hosted page itself — for a fully custom look-and-feel, embed the checkout widget in your own UI instead.
If you want the payment flow to stay inside your app without a redirect, use the embeddable checkout widget. It loads the same hosted checkout in a sandboxed iframe with a modal overlay. See the Embed the checkout widget guide.
If you need to invalidate an unpaid invoice, void it via the API. The hosted checkout page will show an “Invoice canceled” message to anyone who opens the link after it has been voided.
await marlin.invoices.void("inv_01HXYZ");