Checkouts.
A checkout session is a short-lived intent to collect a stablecoin payment. Create one with a single POST, then redirect the customer to the returned URL or render the embedded widget. Funds settle directly to the merchant wallet specified in the session; OpenSettle never holds them.
Create a session
Four SDKs, one shape. Two modes: payment (one-off) or subscription (pass a priceId to spin up a recurring subscription on first payment). For mode payment, supply exactly one of an existing invoiceId, a one-time priceId, or an inline ad-hoc amount (minor units / cents). The chain + token fix the settlement rail (required for an inline amount; otherwise they override the defaults inherited from the invoice / price). The customer is optional for mode payment — omit customerEmail for a guest checkout.
import { OpenSettle } from "@opensettle/sdk";
const os = new OpenSettle({
apiKey: process.env.OPENSETTLE_KEY!,
workspaceId: process.env.OPENSETTLE_WORKSPACE!,
});
const checkout = await os.checkouts.create({
mode: "payment",
customerEmail: "ada@lovelace.dev",
invoiceId: "in_01jt…",
chain: "base",
token: "USDC",
successUrl: "https://yourapp.com/billing/done",
cancelUrl: "https://yourapp.com/billing",
expiresInMinutes: 30,
metadata: { order_id: "ord_4118" },
});
// hostedUrl is an absolute URL (changed 2026-05-20); redirect as-is.
return Response.redirect(checkout.hostedUrl, 303);import os
from opensettle import OpenSettle
client = OpenSettle(
api_key=os.environ["OPENSETTLE_API_KEY"],
workspace_id=os.environ["OPENSETTLE_WORKSPACE_ID"],
)
checkout = client.checkouts.create(
mode="payment",
customer_email="ada@lovelace.dev",
invoice_id="in_01jt...",
chain="base",
token="USDC",
success_url="https://yourapp.com/billing/done",
cancel_url="https://yourapp.com/billing",
expires_in_minutes=30,
metadata={"order_id": "ord_4118"},
)
# Redirect the buyer to checkout["hostedUrl"]client := opensettle.NewClient(
os.Getenv("OPENSETTLE_API_KEY"),
opensettle.WithWorkspace(os.Getenv("OPENSETTLE_WORKSPACE_ID")),
)
checkout, err := client.Checkouts.Create(ctx, &opensettle.CreateCheckoutRequest{
Mode: "payment",
CustomerEmail: "ada@lovelace.dev",
InvoiceID: "in_01jt...",
Chain: "base",
Token: "USDC",
SuccessURL: "https://yourapp.com/billing/done",
CancelURL: "https://yourapp.com/billing",
ExpiresInMinutes: 30,
Metadata: map[string]string{"order_id": "ord_4118"},
})
// http.Redirect(w, r, checkout.HostedURL, http.StatusSeeOther)use opensettle::{Client, CreateCheckoutRequest};
let client = Client::new(
std::env::var("OPENSETTLE_API_KEY")?,
std::env::var("OPENSETTLE_WORKSPACE_ID")?,
);
let checkout = client
.checkouts()
.create(CreateCheckoutRequest {
mode: "payment".into(),
customer_email: Some("ada@lovelace.dev".into()),
invoice_id: Some("in_01jt...".into()),
chain: Some("base".into()),
token: Some("USDC".into()),
success_url: "https://yourapp.com/billing/done".into(),
cancel_url: Some("https://yourapp.com/billing".into()),
expires_in_minutes: Some(30),
..Default::default()
})
.await?;The hosted page
The URL we return resolves to https://opensettle.io/checkout/<hostedToken>. The page detects the customer's wallet, prompts for the chain and token (constrained to what you allowed), and shows a live transaction tracker after submit. On confirmation, we redirect to your successUrl unchanged — use metadata or a query param of your own if you need to correlate it back to a checkout.
Expiration
Sessions expire after expiresInMinutes minutes. Default 30, maximum 1,440 (24 hours). After expiration the hosted page returns a "session expired" view and the chain reader ignores any in-flight tx, firing checkout.expired once per session. There's no force-expire endpoint today — set a short expiresInMinutes if you need tight inventory holds.
One-off vs recurring
A mode: "payment" checkout charges exactly one of three things: an existing invoice (invoiceId), a one-time price (priceId), or an inline ad-hoc amount (minor units) — an inline amount needs its own chain + token. Use mode: "subscription" with priceId to spin up a recurring subscription on first payment. The hosted page reads the amount, chain, and token off whichever you pass. For a reusable link that many buyers can pay (instead of a single-use session), reach for a payment link.
Webhooks fired
checkout.created— session created.payment.confirmed— chain reader observed the deposit; required confirmations reached and funds are in the merchant wallet.checkout.succeeded— session resolved: the deposit landed and the linked invoice or subscription was settled.checkout.expired— TTL elapsed without a confirmed deposit.