TillsafeDocstillsafe.comRequest early access

Payment links

A reusable link you can post anywhere; every payer who opens it gets an invoice of their own.

A payment link is a URL you share in a chat, an email or on social media. You create it once; each payer who opens it gets their own invoice, so payments never mix.

Creating one

POST /v1/payment_links:

json
{
  "amount_type": "fixed",
  "amount": "25.00",
  "currency": "USD",
  "description": "Workshop ticket",
  "quantity_limit": 40
}
  • amount_type: fixed (you set amount) or payer_chosen (the payer types the amount, optionally between min_amount and max_amount; good for donations and tips). When you leave it out it is fixed if you gave an amount, otherwise payer_chosen.
  • quantity_limit: how many payers may pay, 1 to 1,000,000, or null for unlimited.
  • expires_at: optional; after it the link stops creating invoices. It must be in the future.
  • description (shown to payers), metadata (yours; copied to every invoice) and assets (default: your default_assets at the time each invoice is created) work as on invoices.

The response has an id (plink_…), a random, unguessable slug and a url. Payers open the URL with your publishable key added: https://pay.example.com/?link=<slug>&key=cp_live_pk_….

What payers see

  1. The checkout reads the link (GET /v1/checkout/links/{slug}) and lets the payer enter an amount if you allowed it.
  2. It creates the payer's invoice (POST /v1/checkout/links/{slug}/invoices). The invoice copies the link's description, assets and metadata, and its payment_link field names the link: that is how you match payments to links in your webhooks.
  3. The payer picks a network (POST /v1/checkout/invoices/{id}/payment_option), and only then does the invoice get a deposit address. Opening a public link therefore uses none of your addresses. A payer who does not pick a network within 30 minutes finds the invoice expired.

From there the checkout runs exactly as for any invoice.

Status and quantity

StatusWhen
activePayers can open it.
inactiveYou switched it off (active: false). Switch it back on any time.
expiredexpires_at has passed.
sold_outquantity_used reached quantity_limit.

Creating a payer's invoice reserves a unit, in the same step, so concurrent payers can never pay for more than quantity_limit. While the invoice is open and unpaid the unit counts in quantity_reserved; once a payment is seen it moves to quantity_used; if the invoice expires or is cancelled, it comes back. While every remaining unit is reserved, a new payer gets 409 payment_link_fully_reserved. invoices_created counts every invoice.

To keep a busy public link from piling up, a link holds at most 50 open unpaid invoices, and your account at most 200 across all links. Beyond that, new payers get 409 payment_link_busy until earlier invoices are paid or expire.

Changing and switching off

POST /v1/payment_links/{id} changes a link (omitted fields stay, null clears). Changes apply to invoices created afterwards; invoices that already exist keep their terms. There is no delete: switch a link off with {"active": false}.

Each change sends a webhook: payment_link.created, payment_link.updated or payment_link.deactivated (with invoice_id: null). Every payer's invoice sends the normal invoice.* events.