Como funciona
- 1Cadastre o webhook
Cadastre no painel de webhooks ou por
POST /webhooks, com a URL do seu servidor e os eventos que quer receber. Sua conta precisa ter uma chave de API ativa. A URL precisa começar comhttps://e usar um domínio público que já exista no DNS: endereços IP e URLs com usuário ou senha são recusados comINVALID_INPUT. - 2Guarde o segredo de assinatura
Ele vem na resposta da criação, no formato
whsec_…, e pode ser consultado de novo comGET /webhooks/{id}?include_signing_secret=true. Não há como gerar outro: se vazar, exclua o webhook e crie um novo. Não confunda com a chave de API. - 3Receba o POST
Cada evento chega num POST, com o JSON do evento no corpo e os cabeçalhos
svix-id,svix-timestampesvix-signature. - 4Valide, grave e responda 2xx
Confira a assinatura, grave o evento e só então responda. Qualquer resposta fora de 2xx, ou a falta de resposta, gera novas tentativas.
Eventos
| Evento | Quando é enviado |
|---|---|
order.created | Ordem criada. A consulta da ordem traz os valores definitivos e o pagamento. |
order.completed | A ordem foi paga e concluída. Confirme com a consulta (status completed) antes de liberar o pedido. |
order.expired | A ordem expirou sem pagamento. |
order.canceled | A ByteMax cancelou a ordem, por exemplo porque o pagamento não pôde ser aceito e foi devolvido ao pagador. |
order.updated | Mudou um dado da ordem sem mudar o estado: o valor reembolsado, o valor retido ou os dados de pagamento. Não indica pagamento: a ordem paga envia order.completed. |
refund.created | Um reembolso pedido pela sua conta, pela API ou pelo painel, foi registrado. Reembolsos feitos pelo suporte aparecem só em order.updated. |
refund.succeeded | O reembolso terminou: o valor foi devolvido ao pagador. |
refund.failed | Não foi possível concluir o reembolso. |
webhook.test | Evento de teste, enviado só para o webhook que você testou. |
Cada evento traz type, que diz o que aconteceu, e related_object: o type do objeto (order, refund ou webhook), o id e a url, caminho da consulta em https://bytemax.exchange. Para agir, consulte essa url: a consulta sempre devolve o estado atual, mesmo que o evento chegue atrasado, repetido ou fora de ordem.
{
"id": "evt_example",
"type": "order.completed",
"created_at": "2026-09-10T13:05:00.000Z",
"related_object": {
"type": "order",
"id": "ord_example",
"url": "/api/v1/orders/ord_example"
}
}Estados de publicação
GET /events e GET /events/{id} trazem publication_status, que diz se o evento saiu da ByteMax. O resultado no seu servidor fica nas entregas.
- pending
- Registrado e aguardando o envio, ou em nova tentativa. A ByteMax tenta publicar por cerca de 2 horas; depois disso, o evento fica
not_published. - published
- Enviado para entrega. O resultado de cada tentativa fica nas entregas.
- not_published
- Não enviado: sua conta estava sem chave de API ativa, nenhum dos seus webhooks ativos assinava esse tipo de evento naquele momento, ou a publicação falhou. Não pode ser reenviado; consulte a ordem ou o reembolso para ver o estado atual.
Receber e verificar
Valide com o segredo e o corpo bruto da requisição, antes de interpretar o JSON. Use a biblioteca oficial do Svix na sua linguagem: ela confere a assinatura e a tolerância de tempo do svix-timestamp. Não implemente a verificação à mão.
Como verificar assinaturas com a biblioteca oficial (docs.svix.com)
POST /webhooks/bytemax HTTP/1.1
Content-Type: application/json
svix-id: msg_2gkQ7Wc9cD6yYq1xkKz7GJb3wQm
svix-timestamp: 1789045500
svix-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhUjM8G3xRk2w1vNq4T0=
{ "id": "evt_example", "type": "order.completed", ... }Processar sem duplicar
Eventos podem chegar mais de uma vez e fora de ordem. Cinco regras evitam efeitos duplicados:
- Use o
iddo evento como chave única: grave antes de responder e ignore repetidos. - Não dependa da ordem de chegada: a cada evento, consulte a ordem ou o reembolso e aja pelo estado que a consulta devolver.
- Grave o efeito do evento e a marca de processado na mesma transação.
- Responda 2xx só depois de gravar. Se a gravação falhar, responda 5xx para receber de novo.
- Trabalho demorado fica fora da resposta: enfileire e responda rápido.
Testar e reenviar
POST /webhooks/{id}/test-events com Content-Type: application/json e {} no corpo envia um webhook.test para esse webhook, que precisa estar ativo. Acompanhe a publicação em GET /events/{id} e confira no seu servidor se o evento chegou e a assinatura foi aceita. O teste comprova a entrega e a assinatura; para testar o tratamento de ordens e reembolsos, acompanhe uma ordem real.
Entregas que falham recebem até 7 novas tentativas automáticas: depois de 5 segundos, 5 minutos, 30 minutos, 2 horas, 5 horas, 10 horas e 10 horas. Um webhook que falha sem parar por 5 dias é desativado automaticamente. O histórico de cada tentativa fica no painel e em GET /webhooks/{id}/deliveries. Para reenviar eventos específicos, use POST /webhooks/{id}/redeliveries com até 100 IDs. A chamada responde 200 mesmo quando alguns eventos são recusados: leia o status de cada item.
- queued
- O reenvio foi aceito.
- rejected
- Nada foi reenviado. O
codediz o motivo:EVENT_NOT_FOUND(o ID não existe),EVENT_NOT_ACCEPTED(o webhook não assina esse tipo de evento, ou o teste é de outro webhook),EVENT_NOT_PUBLISHED(o evento ainda estápendingou ficounot_published) ouREDELIVERY_REJECTED(o serviço de entregas recusou). Um eventopendingpode ser reenviado quandoGET /events/{id}mostrarpublished. - retry
- O reenvio não foi feito ou não pôde ser confirmado: o tempo da chamada acabou, o serviço de entregas estava ocupado ou falhou. Envie de novo; se o evento chegar duas vezes, o
iddele evita efeito duplicado.
Limites
- Até 200 webhooks por conta, um por URL.
- Eventos ficam consultáveis por 30 dias depois da publicação.
- Listas usam
itemsenext_cursor: 30 por página, no máximo 100. Um cursor só vale na mesma lista e com os mesmos filtros.
Erros
Autenticação, erros gerais e limite de chamadas estão na página da API. Estes códigos são próprios dos webhooks:
WEBHOOK_URL_EXISTSHTTP 409- Você já tem um webhook com esta URL.
WEBHOOK_LIMIT_REACHEDHTTP 409- Você já tem 200 webhooks. Exclua um antes de criar outro.
WEBHOOK_NOT_ENABLED_FOR_V1HTTP 409- Testes e reenvios exigem um webhook ativo e na v1. Ative o webhook ou, se ele veio da API anterior, migre-o para a v1 com
PATCH. WEBHOOK_VERSION_REQUIREDHTTP 400- Um webhook da API anterior só pode ser alterado junto com a migração para a v1: envie
api_version: "v1"e os novosevents. WEBHOOK_NOT_FOUNDHTTP 404- Não há webhook com este ID na sua conta.
EVENT_NOT_FOUNDHTTP 404- Não há evento com este ID. Eventos ficam guardados por 30 dias depois da publicação.
INVALID_CURSORHTTP 400- O cursor não pertence a esta lista com estes filtros. Recomece sem
cursor.
Uma resposta 503 SERVICE_UNAVAILABLE indica que o serviço de entregas está temporariamente indisponível. Repita depois de alguns segundos.
Referência
Dez operações, todas com Authorization: Bearer <API_KEY>. As três mais usadas aparecem completas; as demais seguem o mesmo formato.
/webhooksCriar webhook
Cria o webhook e devolve o segredo de assinatura.
urlstringObrigatório: Sim- Endereço
https://do seu servidor que recebe os eventos, num domínio público. eventsarrayObrigatório: Sim- Tipos de evento que o webhook recebe, sem repetir: um ou mais dos oito de ordem e reembolso em Eventos.
webhook.testnão pode ser assinado: ele só chega pelo teste. enabledbooleanObrigatório: Não- Se o webhook recebe eventos. Padrão:
true.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
url | string | Sim | Endereço https:// do seu servidor que recebe os eventos, num domínio público. |
events | array | Sim | Tipos de evento que o webhook recebe, sem repetir: um ou mais dos oito de ordem e reembolso em Eventos. webhook.test não pode ser assinado: ele só chega pelo teste. |
enabled | boolean | Não | Se o webhook recebe eventos. Padrão: true. |
curl --request POST "https://bytemax.exchange/api/v1/webhooks" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--data '{"url":"https://merchant.example/webhooks/bytemax","events":["order.created","order.completed","order.expired","order.canceled","order.updated","refund.created","refund.succeeded","refund.failed"],"enabled":true}'{
"id": "ep_example",
"url": "https://merchant.example/webhooks/bytemax",
"events": [
"order.created",
"order.completed",
"order.expired",
"order.canceled",
"order.updated",
"refund.created",
"refund.succeeded",
"refund.failed"
],
"enabled": true,
"api_version": "v1",
"signing_secret": "<WEBHOOK_SIGNING_SECRET>"
}/webhooks/{id}/test-eventsEnviar teste
Envia um webhook.test para este webhook. O corpo é um objeto JSON vazio.
| Parâmetro | Onde | Obrigatório |
|---|---|---|
id | caminho | Sim |
curl --request POST "https://bytemax.exchange/api/v1/webhooks/ep_example/test-events" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--data '{}'{
"id": "evt_test_example",
"type": "webhook.test",
"created_at": "2026-09-10T13:05:00.000Z",
"related_object": {
"type": "webhook",
"id": "ep_example",
"url": "/api/v1/webhooks/ep_example"
},
"publication_status": "pending"
}/webhooks/{id}/redeliveriesReenviar eventos
Reenvia até 100 eventos para este webhook. A resposta traz o resultado de cada um.
| Parâmetro | Onde | Obrigatório |
|---|---|---|
id | caminho | Sim |
event_idsarrayObrigatório: Sim- IDs dos eventos a reenviar, de 1 a 100, sem repetir.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
event_ids | array | Sim | IDs dos eventos a reenviar, de 1 a 100, sem repetir. |
curl --request POST "https://bytemax.exchange/api/v1/webhooks/ep_example/redeliveries" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--data '{"event_ids":["evt_example"]}'{
"items": [
{
"event_id": "evt_example",
"status": "queued"
}
]
}Outras operações
| Operação | Nome | O que faz |
|---|---|---|
GET/webhooks | Listar webhooks | Todos os webhooks da sua conta, inclusive os criados na API anterior (api_version: "legacy"). |
GET/webhooks/{id} | Consultar webhook | Um webhook. Com include_signing_secret=true, inclui o segredo de assinatura. |
PATCH/webhooks/{id} | Alterar webhook | URL, eventos ou ativação. Para migrar para a v1 um webhook criado na API anterior, envie api_version: "v1" junto com os novos events. |
DELETE/webhooks/{id} | Excluir webhook | Exclui o webhook. |
GET/events | Listar eventos | Eventos dos últimos 30 dias e seu estado de publicação. |
GET/events/{id} | Consultar evento | Um evento e seu estado de publicação. |
GET/webhooks/{id}/deliveries | Listar entregas | Tentativas de entrega de um webhook: succeeded quando o seu servidor respondeu 2xx e failed quando não respondeu ou respondeu outro status. Filtros por estado e tipo. |
