Developers
A stablecoin payments API with no surprises.
Create an invoice on your server, send the payer to the checkout, fulfil on a signed webhook. That is the whole integration.
Create an invoice
Price it in dollars. Tillsafe works out the exact amount for every asset and network you accept, and reserves a deposit address for this invoice alone.
curl "$TILLSAFE_API/v1/invoices" \
-H "Authorization: Bearer $TILLSAFE_SECRET_KEY" \
-H "Idempotency-Key: order-1001" \
-H "Content-Type: application/json" \
-d '{"amount": "30.00", "currency": "USD", "description": "Order #1001",
"metadata": {"order_id": "1001"}}'const res = await fetch(`${process.env.TILLSAFE_API}/v1/invoices`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TILLSAFE_SECRET_KEY}`,
"Idempotency-Key": `order-${order.id}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: "30.00",
currency: "USD",
description: `Order #${order.id}`,
metadata: { order_id: String(order.id) },
}),
});
const invoice = await res.json(); // id, status, payment_options, expires_atEarly-access merchants get their API address and keys with their account.
Hard to get wrong
Money is a string
{"amount": "30.00", "currency": "USD"}. Never a JSON number, so nothing is rounded by a float.Retries are safe
Every write takes an
Idempotency-Key. Repeat a request and you get the first response back.One error shape
A
type, a stablecodeto branch on, a readablemessageand a link to the docs.Signed webhooks with replay
HMAC-SHA256 over a timestamp and the body. Retried for about 72 hours. Every attempt logged, any one replayable.
Live status events
Follow an invoice over Server-Sent Events, and resume after a dropped connection without missing a step.
Test mode on real testnets
Test keys see only testnets, such as TRON Nile. A test helper pays an invoice through the real pipeline, so your webhooks see what a real payment sends.
What the API covers
| Resource | What you can do |
|---|---|
| Invoices | Create, list, cancel; accept or reject a held payment; follow live status |
| Payments | List every on-chain transfer matched to your invoices |
| Refunds | Create, cancel, mark sent; the payer claims through a private link |
| Payment links | Fixed or payer-chosen amounts, with quantity limits |
| Plans, customers, subscriptions | Bill each period with an invoice; pause, resume, cancel; prepaid credit |
| Reconciliation | Reconcile a period, read balances as of a date, export CSV |
| Webhook deliveries | Inspect every attempt and replay any of them |
The API is described in OpenAPI, and the reference is generated from it.
Questions developers ask
- Do I handle wrong networks and short payments myself?
No, the invoice does. Its status says
paid,partially_paid,overpaid,paid_late,under_revieworexpired. Fulfil oninvoice.paid.- Can a payer fake a payment with a transaction ID?
No. Payments are matched by the address they arrived at, which belongs to one invoice at a time. A transaction ID never credits anything.
- Is there an SDK?
Early-access merchants get a TypeScript client generated from the OpenAPI document, with a webhook verifier. The docs have webhook receivers in Node.js, Python, PHP and Go.
- Do the docs match the API?
Our test suite runs the quickstart and the Node.js and Python webhook examples against a real server.