Skip to main content
When an invoice reaches a terminal state, we send one POST to its callback_url. This webhook is the source of truth for fulfillment — act on it, not on the customer returning to your success_url.

What you need to do

1

Expose an HTTPS endpoint

Set it as callback_url on the invoice, or as your business default. It must accept POST with a JSON body.
2

Verify the signature

Confirm the request is from us before trusting it (see Verifying).
3

Respond 2xx quickly

Any 2xx marks the delivery as received. Do heavy work asynchronously — acknowledge first, process after.
4

Process idempotently

The same event may arrive more than once. Deduplicate on X-Webhook-Id (or invoice_uuid), and treat a repeat as a no-op.

Events

One terminal webhook per invoice.

Payload

invoice.paid:
invoice.canceled:
Reconcile the order against amount, and credit your customer against credited_usdt. paid_amount differs from amount whenever the customer pays the commission — it is not the order value, so do not reconcile with it.

Adjustments

If the customer transfers a different amount than the invoice asked for, we resolve it as a dispute and close the invoice at the amount that actually arrived. The webhook then carries adjusted: true and three amounts:
Here you ordered 1000, the customer owed 1050 and sent 900. Of that 900, the commission takes 42.86, so the order closed at 857.14 — and that is what was credited.
Always check adjusted. When it is true, amount is smaller (or larger) than what you ordered, so a strict equality check against your own record will reject a legitimate webhook. Fulfill against credited_usdt, and decide what to do with the difference: deliver partially, credit the actual amount, or contact the customer. A paid invoice does not guarantee full payment.

Headers

Every delivery carries:

Verifying the signature

The signature is HMAC-SHA256 over the string {timestamp}.{raw_body}, keyed with your webhook secret (from the dashboard). Compute it over the raw request body and compare against X-Webhook-Signature with a constant-time check.
Reject the request if the signature doesn’t match, or if X-Webhook-Timestamp is older than a few minutes. The timestamp is inside the signed string, so an attacker can’t replay an old body with a fresh timestamp.

Retries

A delivery succeeds on any 2xx. Anything else — a non-2xx status, a timeout (15s), or a connection error — is retried on a backoff schedule. By default there are 7 attempts: the first immediately, then after 1, 5, 30, 120, 360, and 720 minutes. The last attempt lands roughly 20.6 hours after the event. If all attempts fail, the delivery is marked failed — resend it manually once your endpoint is healthy.

Manual resend

POST /external/invoices/{ident}/resend-webhook Sends the latest delivery for the invoice now — expedites it if still queued, or starts a fresh attempt if it already failed or delivered. {ident} is the order_id or your external_id.

Delivery history

GET /external/invoices/{ident}/webhooks Returns the invoice’s deliveries, each with its full attempt history — useful to debug failures (status codes, errors, timings).
Each delivery includes: Delivery id (matches X-Webhook-Id). invoice.paid or invoice.canceled. pending, delivering, delivered, or failed. Attempts made so far, out of max_attempts. HTTP status of the most recent attempt. When the next retry is scheduled (if any). When a 2xx was received. Per-attempt log: status_code, success, error, duration_ms, triggered_by, created_at.