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.

An invoice in Marlin represents a payment request from you to a customer. You create an invoice with one or more line items, and Marlin generates a hosted payment URL your customer uses to pay in USDC, PYUSD, or USDG directly from their Solana wallet. Once the customer pays, the funds settle on-chain immediately — 99.5% to your wallet, 0.5% to the Marlin protocol — with no intermediary holding the money.

The Invoice interface

Every invoice returned by the API conforms to this TypeScript interface:
export type InvoiceStatus =
  | "draft"
  | "open"
  | "paid"
  | "void"
  | "uncollectible"
  | "processing";

export interface Invoice {
  id: string;
  object: "invoice";
  customerId: string;
  subscriptionId: string | null;
  status: InvoiceStatus;
  currency: string;
  amount: number;
  amountPaid: number;
  amountRemaining: number;
  description: string | null;
  memo: string | null;
  dueDate: string | null;
  paidAt: string | null;
  voidedAt: string | null;
  lineItems: InvoiceLineItem[];
  metadata: Record<string, string>;
  paymentUrl: string | null;
  transactionSignature: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface InvoiceLineItem {
  description: string;
  quantity: number;
  unitAmount: number;
  amount: number;
}

Key fields

lineItems — An array of InvoiceLineItem objects that make up the invoice total. Each line item has a description, quantity, unitAmount (in the currency’s smallest unit), and the computed amount (quantity × unitAmount). You supply line items when creating the invoice via CreateInvoiceInput. dueDate — An ISO 8601 timestamp indicating when payment is expected. Marlin uses this to transition an unpaid invoice to uncollectible and to trigger the invoice.overdue webhook event. paymentUrl — The hosted checkout URL you send to your customer. It encodes a short-lived token that grants access to the checkout page for this specific invoice. The URL is null while the invoice is in draft status and is set once the invoice moves to open. transactionSignature — The Solana transaction signature recorded on-chain when the invoice is paid. You can use this to verify the payment independently on any Solana explorer. It is null until the invoice reaches paid status.

Invoice lifecycle

Invoices move through a defined set of states. Understanding these states helps you build reliable payment flows and respond to the right webhook events.
The invoice has been created in your system but has not yet been sent to the customer. The paymentUrl is null. Drafts are useful when you want to preview or stage an invoice before it becomes payable. You can update line items and metadata while an invoice is in draft.
The invoice is active and awaiting payment. The paymentUrl is set and the customer can pay. This is the state most invoices enter immediately after creation when autoSend: true is passed to CreateInvoiceInput. Marlin fires the invoice.created webhook when an invoice becomes open.
The customer has submitted a payment transaction, and Marlin is waiting for on-chain confirmation. This is a transient state — the invoice moves to paid once the transaction is finalized on Solana.
You have cancelled the invoice before payment. Void invoices cannot be paid or reopened. Call marlin.invoices.void(id) or POST /api/invoices/:id/void to transition to this state. Marlin fires invoice.voided.
The invoice has passed its dueDate without being paid and has been marked uncollectible by Marlin’s system. You can use this state to write off bad debt in your own records. Marlin fires invoice.overdue when transitioning to this state.

Fee split

When a customer pays an invoice, the Marlin smart contract splits the payment atomically on-chain:
  • 99.5% goes directly to your settlement wallet
  • 0.5% (50 basis points) goes to the Marlin protocol
This split is enforced by the on-chain smart contract — there is no server-side step that could intercept or redirect funds. You receive the net amount in the same transaction the customer signs.
The fee is charged only on settled payments. Failed, void, and uncollectible invoices are never charged.

Creating an invoice

Use CreateInvoiceInput to specify the customer, currency, line items, and optional metadata:
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",
  dueDate: "2026-06-01T00:00:00Z",
  lineItems: [
    { description: "Pro plan — May 2026", quantity: 1, unitAmount: 4900000 },
  ],
  metadata: { internalOrderId: "ord_9821" },
  autoSend: true,
});

console.log(invoice.paymentUrl); // Share this with your customer
Amounts are always in the token’s smallest unit. For USDC (6 decimals), 4900000 equals $4.90. See Supported stablecoins and currencies for a full explanation.

Next steps

Accept payments guide

End-to-end walkthrough for creating and collecting your first invoice payment.

Invoices API reference

Full endpoint reference including request parameters and response schemas.