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 inline ad-hoc amount (minor units / cents — the simplest, no invoice needed), a one-time priceId, or an existing invoiceId. The chain + token fix the settlement rail (required for an inline amount or priceId; otherwise inherited from the invoice). That rail must have a verified settlement wallet (see GET /rails). 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",
amount: 19_900, // minor units — $199.00 (no invoice needed)
currency: "USD", // optional — defaults to USD
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_KEY"],
workspace_id=os.environ["OPENSETTLE_WORKSPACE"],
)
checkout = client.checkouts.create(
mode="payment",
amount=19_900, # minor units — $199.00 (no invoice needed)
currency="USD", # optional — defaults to USD
chain="base",
token="USDC",
successUrl="https://yourapp.com/billing/done", # SDK is camelCase-only (no translation)
cancelUrl="https://yourapp.com/billing",
expiresInMinutes=30,
metadata={"order_id": "ord_4118"},
)
# Redirect the buyer to checkout["hostedUrl"]client := opensettle.NewClient(
os.Getenv("OPENSETTLE_KEY"),
opensettle.WithWorkspace(os.Getenv("OPENSETTLE_WORKSPACE")),
)
checkout, err := client.Checkouts.Create(ctx, &opensettle.CreateCheckoutRequest{
Mode: "payment",
Amount: 19_900, // minor units — $199.00 (no invoice needed)
Currency: "USD", // optional — defaults to USD
Chain: "base",
Token: "USDC",
SuccessURL: "https://yourapp.com/billing/done",
CancelURL: "https://yourapp.com/billing",
ExpiresInMinutes: 30,
Metadata: map[string]any{"order_id": "ord_4118"},
})
// http.Redirect(w, r, checkout.HostedURL, http.StatusSeeOther)use opensettle::{ChainId, CheckoutMode, CreateCheckoutRequest, OpenSettle, TokenSymbol};
let client = OpenSettle::builder(
std::env::var("OPENSETTLE_KEY")?,
std::env::var("OPENSETTLE_WORKSPACE")?,
)
.build()?;
let checkout = client
.checkouts()
.create(&CreateCheckoutRequest {
mode: CheckoutMode::Payment,
amount: Some(19_900), // minor units — $199.00 (no invoice needed)
currency: Some("USD".into()),
chain: Some(ChainId::Base),
token: Some(TokenSymbol::USDC),
success_url: Some("https://yourapp.com/billing/done".into()),
cancel_url: Some("https://yourapp.com/billing".into()),
expires_in_minutes: Some(30),
customer_id: None,
customer_email: None,
customer_name: None,
invoice_id: None,
price_id: None,
description: None,
metadata: None,
})
.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.