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 carriesadjusted: true and three amounts:
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 isHMAC-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 any2xx. 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).
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..webp?fit=max&auto=format&n=O6SgNi-K863CxPv7&q=85&s=5a022604a7f294c9858b55256ba8a593)
