TillsafeDocstillsafe.comRequest early access

Checkout

Payer-facing, publishable-key endpoints

GET /v1/checkout/exchanges

Exchange withdrawal networks and fees.

For each exchange: the network's name in that exchange's withdrawal screen and its withdrawal fee, so the checkout can say "choose Tron (TRC20) and send 51.50 (includes Binance's 1.50 fee)". A label or fee is present only if it was verified against the exchange's own public page (source_url, on verified_at); otherwise it is null and the checkout uses generic wording.

Authentication: Publishable key or Publishable key as a query parameter (for EventSource) or Secret key

Parameters

ParameterInTypeDescription
keyquerystring

Publishable key, when it cannot go in the Authorization header

Responses

StatusDescriptionBody
200
ExchangeList application/json

GET /v1/checkout/invoices/{id}

The payer's view of an invoice.

Every payment option carries address_derivation: the checkout must recompute the deposit address from it, compare the destination with the merchant destination pinned in its own config, and refuse to display the address on any mismatch.

Authentication: Publishable key or Publishable key as a query parameter (for EventSource) or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

keyquerystring

Publishable key, when it cannot go in the Authorization header

Responses

StatusDescriptionBody
200
CheckoutInvoice application/json
404
ErrorResponse application/json

GET /v1/checkout/invoices/{id}/lookup

"Already sent? Find my payment."

Looks a transaction hash up on this invoice's networks and says where the transfer went and whether it is attributed to this invoice. Informational only: a lookup never credits a payment. Payments are attributed only by the deposit address lease (or a bound sender), from our own chain observations. Rate-limited per key and client address (429 with Retry-After).

Authentication: Publishable key or Publishable key as a query parameter (for EventSource) or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

tx_hashrequiredquerystring

Transaction hash: 0x + 64 hex digits, or 64 hex digits (TRON), or a Solana signature (base58)

keyquerystring

Publishable key, when it cannot go in the Authorization header

Responses

StatusDescriptionBody
200
TxLookup application/json
400
ErrorResponse application/json
404
ErrorResponse application/json
429

Too many lookups; retry after Retry-After seconds

ErrorResponse application/json

POST /v1/checkout/invoices/{id}/notify

Email me a receipt.

The payer may leave an email address (never required). A receipt is sent once the invoice is paid (right away if it already is), and a notice of any refund the merchant creates for it (never the claim link: this route takes only the publishable key, so the address proves nothing). Nothing is sent before a payment arrived. Send the checkout view's session_token: the first address binds the invoice's receipt to that session, and only the same session may replace it (at most 3 different addresses per invoice). Emails come from the merchant's name. Rate-limited per key and client address.

Authentication: Publishable key or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

Idempotency-Keyrequiredheaderstring

Unique per submission

Request body

application/json

PayerNotifyRequest

FieldTypeDescription
emailrequiredstring

Where to send the receipt (and any refund link).

  • Example: "payer@example.com"
localestring or null

The payer's language for the emails (en, ru, vi, ...). Default en.

  • Example: "en"
session_tokenrequiredstring

The checkout view's session_token for this invoice (the first one this page got). Once an address is set, only the same session may replace it.

  • Example: "cps_q0lW1y3r0n2E5oVb7yKpQmZt8xJcNfHaUgDsLiReTwA"

Responses

StatusDescriptionBody
200
PayerNotice application/json
400

Not a valid email address or locale, or session_token is not a checkout session of this invoice (checkout_session_invalid)

ErrorResponse application/json
404
ErrorResponse application/json
409

Too many different addresses for this invoice, the address was set from another checkout session (notify_session_mismatch), or notifications are unavailable on this server

ErrorResponse application/json
429

Too many requests; retry after Retry-After seconds

ErrorResponse application/json

POST /v1/checkout/invoices/{id}/payment_option

Pick a payment option: lease its deposit address.

A payment-link invoice holds no deposit address until its payer picks a network: its options are listed in pending_options, and this call leases the chosen network's address (the same address covers every EVM network the invoice offers) and returns the invoice with that option in payment_options, ready to verify and show. Picking an option that already has its address changes nothing, so a retry is safe. If no network is picked by select_by, the invoice expires. 409 invoice_not_awaiting_payment once it is closed, 409 deposit_addresses_exhausted when no address is free right now. Rate-limited per key and client address.

Authentication: Publishable key or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

Idempotency-Keyrequiredheaderstring

Unique per pick; a retry returns the same answer

Request body

application/json

SelectPaymentOptionRequest

FieldTypeDescription
assetrequiredstring

One of the invoice's pending_options[].asset (or payment_options[].asset, which changes nothing).

  • Example: "USDT@tron:nile"

Responses

StatusDescriptionBody
200
CheckoutInvoice application/json
400

Not one of the invoice's options

ErrorResponse application/json
404
ErrorResponse application/json
409

The invoice is closed, or no deposit address is free right now

ErrorResponse application/json
429

Too many requests; retry after Retry-After seconds

ErrorResponse application/json

POST /v1/checkout/invoices/{id}/wallet_binding

Pay from a connected wallet.

Binds the invoice to the payer's wallet address for one payment option and returns the exact transfer to build: the token, the merchant's registered destination and the amount (the amount due plus a sub-cent suffix when the same wallet has another open payment of the same amount). A transfer is attributed when its sender, exact amount and time all match; a transaction hash is never an input. Binding the same wallet again returns the same binding. A different wallet (the payer switched) gets its own binding, and the earlier one stays valid; at most 5 wallets per invoice and network. Only while the invoice is awaiting payment. Rate-limited per key and client address.

Authentication: Publishable key or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

Idempotency-Keyrequiredheaderstring

Unique per submission

Request body

application/json

WalletBindingRequest

FieldTypeDescription
assetrequiredstring

The payment option to pay: its asset code, SYMBOL@network (one of the invoice's options).

  • Example: "USDT@eip155:97"
senderrequiredstring

The connected wallet's address on that network, in its display form (0x… or T…). The transfer must come from exactly this address.

  • Example: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"

Responses

StatusDescriptionBody
200
WalletBinding application/json
400

Not an address on that network, or not one of the invoice's payment options

ErrorResponse application/json
404
ErrorResponse application/json
409

The invoice is not awaiting payment, too many wallets, no unique amount left, or wallet payments are unavailable on this server

ErrorResponse application/json
429

Too many requests; retry after Retry-After seconds

ErrorResponse application/json

A payment link, as the payer sees it.

The landing screen: the merchant, the description, and either the fixed price or the bounds of the amount the payer may choose. status says whether the link still takes payments.

Authentication: Publishable key or Publishable key as a query parameter (for EventSource) or Secret key

ParameterInTypeDescription
slugrequiredpathstring

The link's slug (22 characters)

keyquerystring

Publishable key, when it cannot go in the Authorization header

StatusDescriptionBody
200
CheckoutPaymentLink application/json
404
ErrorResponse application/json

POST /v1/checkout/links/{slug}/invoices

Create this payer's invoice from a payment link.

Fixed-price links take no body fields; payer-chosen links need amount (within the link's bounds). Returns the payer's view of the new invoice; continue with the normal checkout for its id. The invoice reserves one unit of the link's quantity_limit and holds no deposit address yet: its options are in pending_options until the payer picks one (POST /v1/checkout/invoices/{id}/payment_option) before select_by. 409 when the link is deactivated, expired or sold out (payment_link_inactive, _expired, _sold_out), when every remaining unit is reserved by unpaid invoices (payment_link_fully_reserved), or when too many unpaid link invoices are open (payment_link_busy). Rate-limited per key and client address.

Authentication: Publishable key or Secret key

Parameters

ParameterInTypeDescription
slugrequiredpathstring

The link's slug (22 characters)

Idempotency-Keyrequiredheaderstring

Unique per payer attempt; a retry returns the same invoice

Request body

application/json

CreateLinkInvoiceRequest

FieldTypeDescription
amountstring or null

The amount the payer chose, in the link's currency, as a decimal string. Required for payer_chosen links; must be omitted for fixed ones.

  • Example: "20.00"

Responses

StatusDescriptionBody
201

Created

CheckoutInvoice application/json
400

Missing or out-of-bounds amount

ErrorResponse application/json
404
ErrorResponse application/json
409

The link is inactive, expired, sold out, fully reserved, or busy

ErrorResponse application/json
429

Too many requests; retry after Retry-After seconds

ErrorResponse application/json

GET /v1/invoices/{id}/events

Live invoice status as Server-Sent Events.

Each event: id: is the per-invoice sequence number, event: is invoice.created or invoice.{status} (invoice.detected, invoice.confirming, invoice.paid, …), and data: is a complete [InvoiceEvent] JSON object. On connect, every past event is sent first. Resume after a disconnect with the Last-Event-ID header (browsers do this automatically) or ?last_event_id=.

Authentication: Publishable key or Publishable key as a query parameter (for EventSource) or Secret key

Parameters

ParameterInTypeDescription
idrequiredpathstring

Invoice id (inv_…)

Last-Event-IDheaderstring or null

Resume after this sequence number

last_event_idqueryinteger (int64)

Same as the header, for the first connection

  • Minimum: 0
keyquerystring

Publishable key (EventSource cannot set headers)

Responses

StatusDescriptionBody
200

An event stream

InvoiceEvent text/event-stream
404
ErrorResponse application/json