Saltar para o conteúdo principal

Webhooks

Sua conta tem uma única URL de webhook, e todos os eventos vão para ela. Defina-a em Dashboard → API ou por meio de Configurar webhook.

Eventos

Hoje existem seis eventos.
order.updated é enviado apenas para pedidos criados com uma chave de API. Compras feitas no site ou pelo bot do Telegram não geram webhook, embora a mesma conta receba normalmente os eventos do Smart Mode.

Envelope

Toda entrega tem as mesmas três chaves de nível superior. timestamp é o momento em que montamos o evento, ISO-8601 em UTC.
Response
Cabeçalhos:

order.updated

number
ID do pedido.
string
energy ou bandwidth.
string
processing, filled, partial, failed, reclaimed ou reclaim_failed. Este campo é a fonte da verdade — veja o aviso abaixo.
string
Endereço para o qual o recurso foi delegado.
number
Quantidade pedida — unidades de energia ou pontos de bandwidth.
number
O mesmo que volume. Existe para que o esperado e o entregue possam ser comparados sem descobrir qual campo significa o quê.
number
Quanto foi de fato delegado até agora. Igual a volume quando o pedido está filled; em processing e partial é a soma das partes já entregues, e 0 em caso de falha.
string
Preço do pedido em TRX, como string decimal.
string | null
Transação que delegou o recurso.
string | null
Transação que o retomou ao fim da locação.
string | null
Quando o recurso está agendado para ser retomado, ISO-8601, ou null para pedidos que não são retomados por temporizador.
Response
Julgue o resultado pelo status, nunca pela presença de delegate_txid. Um pedido que falhou também pode trazer um id de transação — nós o mantemos de propósito, para que a falha possa ser investigada. Só o status diz se você recebeu o recurso.
Internamente dividimos pedidos grandes em partes, mas isso é problema nosso: você recebe um webhook por pedido, nunca um por parte.

subscription.transfer

number
Assinatura do Smart Mode à qual a transferência pertence.
string
O endereço monitorado de onde saiu a transferência.
string | null
O rótulo que você deu à assinatura.
string
A transação da transferência na rede.
number
Quantas transferências esta delegação cobriu.
number
Energia delegada para elas.
string
O que foi cobrado pela energia, em TRX.
string | null
Bandwidth cobrado adicionalmente, ou null quando não houve cobrança.
string
O saldo da sua conta após a cobrança.
string
Quando a transferência foi processada. Note que ele fica dentro de data e é diferente do timestamp do próprio envelope.
Response

Eventos de Transfer Package

Os quatro eventos package.* vão para a conta dona do pacote. Um pacote comprado por fatura sem login nem chave de API não tem dono e não gera eventos. Faturas canceladas, compras recusadas e compras em revisão manual também não geram eventos; um pacote em revisão envia package.activated quando for ativado. Todo evento package.* traz estes campos em data:
number
ID do pacote — o id em Listar Pacotes.
string
O endereço que o pacote atende.
string
Status do pacote após o evento: active ou completed em package.transfer, completed em package.completed, active em package.activated, expired em package.expired.
number
Transferências com que o pacote foi comprado.
number
Transferências que restam neste pacote após a mudança informada pelo evento — um número absoluto, não uma diferença.
Os eventos podem chegar fora de ordem. Cada um é entregue separadamente, com novas tentativas por cerca de 35 segundos, então o package.completed causado por uma transferência pode chegar antes do package.transfer dessa transferência, e um package.transfer pode chegar antes de package.activated. Para cada package_id, guarde o menor remaining que já viu: ele nunca aumenta. completed e expired são definitivos.
remaining também pode diminuir sem evento. Um pacote de várias transferências consome uma transferência por dia como assinatura diária — a primeira na ativação, por isso um pacote de 500 transferências começa com remaining: 499 — e essa cobrança não é anunciada. Duas transferências do mesmo endereço no mesmo bloco podem informar o mesmo remaining. Trate remaining como uma indicação e Listar Pacotes como a fonte da verdade.
Para reconhecer uma nova tentativa, use (package_id, tx_hash) em package.transfer e (event, package_id) nos demais: a nova tentativa traz o mesmo corpo, o mesmo timestamp e a mesma assinatura.

package.transfer

Uma transferência do endereço foi paga com um pacote. Enviado uma vez por pacote cobrado pela transferência — quase sempre um evento por transferência; uma transferência que usou a última transferência de um pacote e continuou no seguinte gera um evento para cada um.
string
A transação da transferência na blockchain.
number
Transferências descontadas deste pacote nesta transação. Uma transferência para um endereço sem USDT precisa do dobro de energia e conta como 2, que podem ser divididas entre dois pacotes.
Aqui status é completed quando esta transferência esgotou o pacote.
Response

package.completed

O pacote deixou de cobrir transferências.
string
transfer — uma transferência esgotou o pacote; subscription — a cobrança diária o esgotou; manual — o suporte encerrou o pacote. Depois de manual, remaining pode ser maior que zero, mas essas transferências não podem mais ser usadas.
string | null
Com reason: "transfer", a transferência que encerrou o pacote; null nos demais casos.
Um pacote sem saldo — por exemplo, um pacote comum de uma transferência cuja primeira cobrança diária levou sua única transferência — é encerrado pela transferência seguinte sem um package.transfer próprio: você recebe apenas package.completed com o tx_hash dessa transferência.
Response

package.activated

O pacote foi ativado e a partir de agora suas transferências recebem energia. Enviado a cada ativação — inclusive em uma compra com saldo, cuja resposta já diz active, e no pagamento de uma fatura, que ativa o pacote pouco depois de o pagamento aparecer na blockchain.
string
Como o pacote foi pago: exatamente balance, TRX ou USDT.
Response

package.expired

A fatura de um pacote não foi paga dentro do prazo de 30 minutos. Nada foi cobrado; compre novamente para obter uma nova fatura. Sem campos extras; remaining é igual a quota_total e não pode ser usado.
Response

Entrega

  • Até 3 tentativas, com pausas de 1 segundo e depois 4 segundos entre elas. Não há pausa após um sucesso nem após a última tentativa.
  • Tempo limite de 10 segundos por tentativa.
  • Esperamos qualquer 2xx. Qualquer outra coisa conta como tentativa falha.
  • Redirecionamentos não são seguidos. Um 301/302 é uma tentativa falha, não um salto.
  • Eventos perdidos não são reenviados depois. Se as três tentativas falharem, aquele evento se perdeu; reconcilie com Consultar pedido ou Listar Pacotes em vez de esperar uma repetição.
Sua URL precisa resolver para um endereço público. Faixas de loopback, privadas e link-local são recusadas, assim como um host que não resolve — em ambos os casos nada é enviado e nenhuma linha de registro é escrita.

Verificação da assinatura

Toda requisição traz X-Webhook-Signature: sha256=<hex>, um HMAC-SHA256 sobre o corpo bruto da requisição, com o seu segredo de webhook como chave. Dois detalhes decidem se a sua verificação funciona:
  1. Remova o prefixo sha256= antes de comparar. O cabeçalho não é um digest hexadecimal puro.
  2. Faça o hash dos bytes recebidos, não de um objeto reserializado. Analisar o JSON e serializá-lo de novo muda a ordem das chaves e os espaços, e a assinatura nunca vai bater.
Seu segredo de assinatura aparece em Dashboard → API, ao lado da URL do webhook. Ele não é devolvido a requisições com chave de API — para lê-lo é preciso entrar no site.
Verifique a assinatura antes de agir sobre o conteúdo e compare em tempo constante (hmac.compare_digest / crypto.timingSafeEqual). Comparar com == vaza por tempo.