Webhook URL
Overview
This feature delivers the data of a paid invoice to the merchant's server. It exists so the merchant's store can process the payment automatically and deliver the product or service to your customer.
The Webhook URL is set individually for each project and points to the payment handler scripts inside the merchant's store. The address must use HTTPS and a domain name: IP addresses are not accepted, and the certificate is verified on every delivery.
Every time an invoice's status changes to Paid, the service sends a POST request to this URL in the following format:
{
"wallet":{
"id":"47aa71e2-07a0-482e-9172-7114d7376ba0",
"name":"usdt-tron",
"blockchain":"tron",
"cryptocurrency":"usdt",
"address":"TKbstUwMzLrfTAGL4erYb7gc7ghmHQ9zG7"
},
"project":{
"id":"9deea1e2-0c08-41a3-bdc2-a34eada3892d",
"name":"My project",
"commissionPayer":"seller",
"commissionRate":1
},
"invoice":{
"id":"a4c9e2ee-9a03-43e5-a1a1-00caf679d16a",
"uid":"AFhygKX21ecd",
"createDatetime":"2024-02-26 13:29:24",
"timeToPayDatetime":"2024-02-27 01:29:24",
"commissionFiatUSD":0.05,
"amountFiatUSD":5.02,
"amountFiat":5,
"calcAmountFiat":5.02,
"currencyFiat":"USD",
"description":null,
"serviceData":null,
"status":"paid"
},
"payment":{
"id":"f986ad8d-2298-473d-982a-efbc817b975d",
"amount":5.02,
"hash":"74763b65e43bcc9492a6ce9a7f26fbfdbd7635aecd3454420b5e9534cba50ee6",
"transactionDatetime":"2024-02-26 13:32:57"
}
}
The notification is sent on every transition to Paid—both when the service found the payment automatically and when the merchant matched the payment to the invoice manually.
Request parameters
| Parameter | Description |
|---|---|
wallet.id | Wallet ID in UUID format |
wallet.name | Wallet name |
wallet.blockchain | The crypto wallet's blockchain |
wallet.cryptocurrency | The wallet's cryptocurrency |
wallet.address | The crypto wallet's address |
project.id | Project ID in UUID format |
project.name | Project name |
project.commissionPayer | Who pays the service fee |
project.commissionRate | Fee rate in % |
invoice.id | Invoice ID in UUID format |
invoice.uid | Invoice ID (for the customer) |
invoice.createDatetime | Invoice creation date and time (UTC) |
invoice.timeToPayDatetime | Date and time until which the invoice is valid for the customer (UTC). The payment search continues for 1 more hour after this mark—to account for slow networks. So a notification may arrive for an invoice that was already shown as expired |
invoice.commissionFiatUSD | Service fee amount. Calculated from the invoice.amountFiatUSD amount |
invoice.amountFiatUSD | Amount in USD. At invoice creation it is calculated from invoice.amountFiat at the current exchange rate. At the moment of payment it is overwritten with the amount actually received, converted to USD at the rate at that moment. The fee in invoice.commissionFiatUSD is recalculated from it as well |
invoice.amountFiat | The original invoice amount in fiat currency. Does not change |
invoice.calcAmountFiat | The calculated amount in the invoice.currencyFiat currency at the crypto exchange rate at the moment of payment. It can differ from invoice.amountFiat because the customer may have paid the invoice some time after creation rather than right away. Over that time, the crypto rate against invoice.currencyFiat could move either way |
invoice.currencyFiat | Fiat currency |
invoice.description | The description set at invoice creation |
invoice.serviceData | The service data set at invoice creation |
invoice.status | Invoice status |
payment.id | Payment ID in UUID format |
payment.amount | Payment amount in cryptocurrency |
payment.hash | The on-chain transaction hash |
payment.transactionDatetime | Date and time of the on-chain transaction (UTC) |
Notification signature
Every request is signed with the webhook secret. The signature travels in the X-Timestamp and X-Signature headers and lets you make sure the notification came from the service, not from an outsider who learned your handler's address.
Verify the signature before processing the order. The mechanics and ready-made examples are in Webhook signature verification.
Handling recommendations
Do not reject a notification because the payment deadline has passed. A check like “the invoice is expired, so the payment is invalid” looks logical but cuts off a share of real payments: on slow networks a transaction may confirm after the deadline, and the merchant can manually match a payment to an expired invoice. The notification itself confirms the payment.
Verify the amount against the original field invoice.amountFiat. This is the invoice amount as issued, and it does not change. The amountFiatUSD field reflects the amount actually received and can differ from the issued one—both because of rate movement and because of manual payment matching.
Parse amounts as numbers. Trailing zeros are dropped: an amount of 10.00 arrives as 10; format it on your side for display. Amounts below 0.0001 arrive in exponential notation, for example 1.0e-6—standard JSON parsing returns the correct number; only manual string parsing breaks.
Handle notifications idempotently. The same notification can arrive again—for example, if your script processed the payment successfully but returned a non-2xx code. Before fulfilling the order, check whether this invoice.id has already been processed.
Escape values on output. The invoice.description and invoice.serviceData fields come back exactly as the merchant submitted them. If you render them in HTML, escape them on your side.
Delivery schedule
The server at the Webhook URL must respond with a 2xx HTTP code. Any other code, a timeout, or a dropped connection counts as a failed delivery.
Redirects are not followed: a 301 or 302 response is a failed delivery, not a hop to the new address. Set the handler's final address.
The connection is allowed 5 seconds, the whole request 10 seconds. If the handler does not fit within that, the delivery counts as failed.
After a failed delivery, the service retries on the following schedule:
- 5 minutes after the last failed delivery
- After 15 minutes
- After 30 minutes
- After 1 hour
- After 3 hours
- After 6 hours
- After 12 hours
- After 24 hours
After that, delivery attempts stop.
Disabling the Webhook URL
Sometimes a store's webhook script processes the payment correctly but returns a non-2xx HTTP code. This leads to frequent retries from our server on the schedule above, putting extra load on both our server and yours.
To prevent such cases, we have a mechanism that disables the Webhook URL in a project. To avoid it, take the following steps:
- Change your webhook handler code so it returns a 2xx code, usually 200, on successful payment processing. Test it with any emulator, for example Postman.
- Contact technical support to correct the settings.
- Re-enable the Webhook URL in the project settings and save the project.