Webhook
O webhook notifica o seu backend, via POST assinado, sempre que uma transação TRP muda de status — assim você não precisa ficar consultando o status por polling.
Configuração
Seção intitulada “Configuração”Há dois níveis, que podem ser combinados.
No console (nível conta)
Seção intitulada “No console (nível conta)”Defina uma URL que recebe as notificações de todas as suas transações. Apenas o owner do parceiro pode configurar.
A forma mais simples é pela tela Webhook no console (menu lateral): cole a URL, gere o secret e habilite, sem escrever código. Para automação, os mesmos endpoints estão na API (autentique com o token de sessão do console):
curl -X PUT https://api.tonramp.io/v1/partner/webhook \ -H "Authorization: Bearer <token-da-sessao>" \ -H "Content-Type: application/json" \ -d '{"url": "https://sua-loja.com/webhooks/tonramp"}'Resposta — o secret é exibido uma única vez (guarde com segurança; é com ele que você valida a assinatura):
{ "webhook_url": "https://sua-loja.com/webhooks/tonramp", "webhook_enabled": true, "secret": "<secret-de-assinatura>" }GET /v1/partner/webhook consulta a configuração atual (sem o secret); DELETE /v1/partner/webhook desabilita.
Por pedido (via API)
Seção intitulada “Por pedido (via API)”Para um callback específico de uma transação, envie callback_url no POST /v1/wallet/trp/generate. Ele tem prioridade sobre o webhook de conta para aquele tx_id. A URL não vai no payload — fica guardada no servidor.
curl -X POST https://api.tonramp.io/v1/wallet/trp/generate \ -H "Authorization: Bearer tonr_SUA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "wallet": "UQBJ6gU8gh_jRrzYDlfw9cpCwHaSn2mrK4O-1h8CDENehGYJ", "merchant": "store123", "amount": 100.00, "currency": "USDT", "tx_id": "pedido-001", "callback_url": "https://sua-loja.com/webhooks/pedido-001" }'Testar a integração
Seção intitulada “Testar a integração”Depois de configurar, dispare um webhook de teste para validar que seu endpoint recebe o POST e valida a assinatura — sem depender de uma transação real.
- No console: tela Webhook → botão Testar webhook. Mostra na hora o status HTTP que o seu endpoint retornou.
- Via API:
POST /v1/partner/webhook/test(apenas owner, token de sessão do console).
curl -X POST https://api.tonramp.io/v1/partner/webhook/test \ -H "Authorization: Bearer <token-da-sessao>"A resposta traz o resultado do disparo — o status HTTP que o seu endpoint devolveu:
{ "delivered": true, "status_code": 200, "url": "https://sua-loja.com/webhooks/tonramp", "error": null }O corpo enviado é um exemplo assinado com event: "trp.webhook.test" e test: true — não corresponde a nenhum pedido real.
Eventos
Seção intitulada “Eventos”O POST é enviado nestas mudanças de status:
| status | significado |
|---|---|
paid |
PIX recebido, processando a entrega de USDT |
completed |
USDT entregue, transação concluída |
error |
falha no processamento |
expired |
expirou sem pagamento |
cancelled |
cancelada |
refunded |
valor estornado ao pagador |
Corpo da notificação
Seção intitulada “Corpo da notificação”Content-Type: application/json:
{ "event": "trp.transaction.status", "tx_id": "pedido-001", "order_id": "topup_pedido-0_a1b2", "status": "completed", "amount_usdt": 100.0, "amount_brl": 567.63, "partner_id": 7, "attempt": 1}tx_id— otx_iddo payload TRP (campo 05), para casar com o seu pedido.status— ver a tabela de eventos acima.attempt— número da tentativa de entrega (incrementa em re-tentativas).
Assinatura
Seção intitulada “Assinatura”Cada requisição traz os headers:
X-TonRamp-Signature: sha256=<hmac_sha256(secret, corpo_cru)>X-TonRamp-Event: trp.transaction.statusCalcule o HMAC-SHA256 do corpo cru recebido (não reserialize o JSON) com o seu secret e compare em tempo constante.
import hmacimport hashlib
def verificar(secret: str, corpo: bytes, header: str) -> bool: esperado = "sha256=" + hmac.new(secret.encode(), corpo, hashlib.sha256).hexdigest() return hmac.compare_digest(esperado, header)import crypto from "node:crypto";
function verificar(secret, corpo, header) { const esperado = "sha256=" + crypto.createHmac("sha256", secret).update(corpo).digest("hex"); return crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(header));}Responda 2xx para confirmar o recebimento. Em erro, timeout ou status >= 300, a entrega é re-tentada com backoff (até 5 tentativas). Como pode haver re-tentativa, trate a notificação de forma idempotente (por exemplo, deduplicando por tx_id + status).