Skip to content

Webhook

The webhook notifies your backend, via a signed POST, whenever a TRP transaction changes status — so you don’t have to keep polling for the status.

There are two levels, which can be combined.

Set a URL that receives notifications for all of your transactions. Only the partner owner can configure it.

The easiest way is the Webhook screen in the console (side menu): paste the URL, generate the secret, and enable it — no code. For automation, the same endpoints are available via the API (authenticate with the console session token):

Janela do terminal
curl -X PUT https://api.tonramp.io/v1/partner/webhook \
-H "Authorization: Bearer <session-token>" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-store.com/webhooks/tonramp"}'

Response — the secret is shown only once (store it securely; it’s what you use to validate the signature):

{ "webhook_url": "https://your-store.com/webhooks/tonramp", "webhook_enabled": true, "secret": "<signing-secret>" }

GET /v1/partner/webhook retrieves the current configuration (without the secret); DELETE /v1/partner/webhook disables it.

For a callback specific to a single transaction, send callback_url in the POST /v1/wallet/trp/generate. It takes priority over the account webhook for that tx_id. The URL does not go in the payload — it is stored on the server.

Janela do terminal
curl -X POST https://api.tonramp.io/v1/wallet/trp/generate \
-H "Authorization: Bearer tonr_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"wallet": "UQBJ6gU8gh_jRrzYDlfw9cpCwHaSn2mrK4O-1h8CDENehGYJ",
"merchant": "store123",
"amount": 100.00,
"currency": "USDT",
"tx_id": "order-001",
"callback_url": "https://your-store.com/webhooks/order-001"
}'

After configuring, fire a test webhook to verify that your endpoint receives the POST and validates the signature — without depending on a real transaction.

  • In the console: Webhook screen → Test webhook button. Shows, in real time, the HTTP status your endpoint returned.
  • Via API: POST /v1/partner/webhook/test (owner only, console session token).
Janela do terminal
curl -X POST https://api.tonramp.io/v1/partner/webhook/test \
-H "Authorization: Bearer <session-token>"

The response carries the delivery result — the HTTP status your endpoint returned:

{ "delivered": true, "status_code": 200, "url": "https://your-store.com/webhooks/tonramp", "error": null }

The body sent is a sample signed with event: "trp.webhook.test" and test: true — it does not correspond to any real order.

The POST is sent on these status changes:

status meaning
paid PIX received, processing the USDT delivery
completed USDT delivered to your wallet, order paid
error processing failure
expired expired without payment
cancelled cancelled
refunded amount refunded to the payer

Content-Type: application/json:

{
"event": "trp.transaction.status",
"tx_id": "order-001",
"order_id": "c_0677de185a882d43",
"status": "completed",
"amount_usdt": 100.0,
"amount_brl": 567.63,
"partner_id": 7,
"attempt": 1
}
  • tx_id — the tx_id from the TRP payload (field 05), to match with your order.
  • status — see the events table above.
  • attempt — the delivery attempt number (increments on retries).

Each request carries the headers:

X-TonRamp-Signature: sha256=<hmac_sha256(secret, raw_body)>
X-TonRamp-Event: trp.transaction.status

Compute the HMAC-SHA256 of the raw body received (do not reserialize the JSON) with your secret and compare in constant time.

import hmac
import hashlib
def verify(secret: str, body: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)

Respond 2xx to confirm receipt. On error, timeout, or status >= 300, the delivery is retried with backoff (up to 5 attempts). Since there may be a retry, handle the notification idempotently (for example, by deduplicating on tx_id + status).