Payment Links.
A payment link is a reusable, shareable URL — https://opensettle.io/pay/<token> — that spawns a fresh checkout on every visit, so one link can collect many payments. Unlike a single-use checkout, it never expires after a payment: drop it in a pricing page, an email signature, a QR code, or a social bio and let buyers pay on their own time. Buyers check out as guests — no email or account required.
Amount modes
Every link fixes a settlement rail (chain + token, both required) and exactly one amount source:
amount— a fixed charge in minor units (cents; USDC and USDT are USD-pegged, so 2500 = $25.00). Requires adescription.priceId— a saved one-time price; the link charges that price's amount and currency.openAmount: true— “name your price” / top-up: the buyer types the amount on the pay page. Bound it withminAmount/maxAmount(minor units) and offerpresetAmountsquick-pick chips (1–8 unique values). The floor defaults to $0.50 when you don't setminAmount. An open-amount link also requires adescription.
A fixed-amount link can't be underpaid, and an open-amount link is validated against your bounds when each checkout spawns — so the rail and the limits you set always hold.
Create a link
Four SDKs, one shape. Supply exactly one amount source plus chain + token, then share the returned url. All amounts are in minor units (cents). The example below is an open-amount tip jar with a $5.00 floor.
import { OpenSettle } from "@opensettle/sdk";
const os = new OpenSettle({
apiKey: process.env.OPENSETTLE_KEY!,
workspaceId: process.env.OPENSETTLE_WORKSPACE!,
});
// Open amount — "name your price" / tip jar (amounts in minor units / cents)
const link = await os.paymentLinks.create({
openAmount: true,
minAmount: 500, // $5.00 floor
presetAmounts: [500, 1000, 2500],
description: "Tip jar",
currency: "USD",
chain: "base",
token: "USDC",
});
// Share this anywhere — every visit spawns a fresh checkout.
console.log(link.url); // https://opensettle.io/pay/<token>import os
from opensettle import OpenSettle
client = OpenSettle(
api_key=os.environ["OPENSETTLE_API_KEY"],
workspace_id=os.environ["OPENSETTLE_WORKSPACE_ID"],
)
# Open amount — buyer names the price. Amounts are minor units (cents).
link = client.payment_links.create(
openAmount=True,
minAmount=500, # $5.00 floor
presetAmounts=[500, 1000, 2500],
description="Tip jar",
currency="USD",
chain="base",
token="USDC",
)
print(link["url"]) # https://opensettle.io/pay/<token>client := opensettle.NewClient(
os.Getenv("OPENSETTLE_API_KEY"),
opensettle.WithWorkspace(os.Getenv("OPENSETTLE_WORKSPACE_ID")),
)
// Amount-bearing fields are *T pointers; tiny helpers keep the call tidy.
ptrBool := func(v bool) *bool { return &v }
ptrInt64 := func(v int64) *int64 { return &v }
ptrStr := func(v string) *string { return &v }
// Open amount — buyer names the price. Amounts are minor units (cents).
link, err := client.PaymentLinks.Create(ctx, opensettle.CreatePaymentLinkRequest{
OpenAmount: ptrBool(true),
MinAmount: ptrInt64(500), // $5.00 floor
PresetAmounts: []int64{500, 1000, 2500},
Description: ptrStr("Tip jar"),
Currency: ptrStr("USD"),
Chain: opensettle.ChainBase,
Token: opensettle.TokenUSDC,
})
if err != nil {
return err
}
fmt.Println(link.URL) // https://opensettle.io/pay/<token>use opensettle::{Client, CreatePaymentLinkRequest, ChainId, TokenSymbol};
let client = Client::new(
std::env::var("OPENSETTLE_API_KEY")?,
std::env::var("OPENSETTLE_WORKSPACE_ID")?,
);
// CreatePaymentLinkRequest has no Default — construct every field.
// Amounts are minor units (cents).
let link = client
.payment_links()
.create(&CreatePaymentLinkRequest {
amount: None,
price_id: None,
open_amount: Some(true),
min_amount: Some(500), // $5.00 floor
max_amount: None,
preset_amounts: Some(vec![500, 1000, 2500]),
description: Some("Tip jar".into()),
currency: Some("USD".into()),
chain: ChainId::Base,
token: TokenSymbol::USDC,
success_url: None,
metadata: None,
})
.await?;
println!("{}", link.url); // https://opensettle.io/pay/<token>Fixed amount
Swap the open-amount fields for a single amount(minor units) to collect a set price. The link can't be underpaid.
// $25.00 fixed — amount is in minor units (cents)
const link = await os.paymentLinks.create({
amount: 2500,
description: "Workshop ticket",
currency: "USD",
chain: "base",
token: "USDC",
});
return link.url;REST API
Under the hood the SDKs call POST /v1/workspaces/{workspaceId}/payment_links. The body takes exactly one of amount, priceId, or openAmount, plus the open-amount bounds (minAmount, maxAmount, presetAmounts), description, currency, the required chain + token, optional successUrl, and metadata.
# Open-amount link with a $5.00 floor and quick-pick chips
curl -X POST \
-H "Authorization: Bearer $OPENSETTLE_API_KEY" \
-H "Content-Type: application/json" \
"https://api.opensettle.io/v1/workspaces/$WORKSPACE_ID/payment_links" \
-d '{
"openAmount": true,
"minAmount": 500,
"presetAmounts": [500, 1000, 2500],
"description": "Tip jar",
"currency": "USD",
"chain": "base",
"token": "USDC"
}'The 201 response wraps the resource as { "paymentLink": { … } }:
id,url,description,priceId,amountMinor,openAmount,minAmountMinor,maxAmountMinor,presetAmounts,currency,chain,token,successUrl,active,createdAt
For a fixed or price-backed link openAmount is false and the open-amount fields are null; amountMinor is 0 for an open-amount or price-backed link.
List + deactivate
GET /payment_links returns every link in the workspace as a flat { "data": [ … ] } envelope (not cursor-paginated). DELETE /payment_links/{id} deactivates a link — its /pay URL stops spawning new checkouts, while checkouts already created from it are unaffected. The server responds { "ok": true }.
// List every payment link (not paginated)
const links = await os.paymentLinks.list();
// Stop a link from spawning new checkouts
await os.paymentLinks.deactivate(links[0].id);