Webhooks

Receba um POST assinado no seu servidor sempre que uma ordem ou um reembolso mudar. Assim você não precisa consultar a API a cada poucos segundos.

Nesta página

Como funciona

  1. 1
    Cadastre 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 com https:// 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 com INVALID_INPUT.

  2. 2
    Guarde o segredo de assinatura

    Ele vem na resposta da criação, no formato whsec_…, e pode ser consultado de novo com GET /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.

  3. 3
    Receba o POST

    Cada evento chega num POST, com o JSON do evento no corpo e os cabeçalhos svix-id, svix-timestamp e svix-signature.

  4. 4
    Valide, 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

EventoQuando é enviado
order.createdOrdem criada. A consulta da ordem traz os valores definitivos e o pagamento.
order.completedA ordem foi paga e concluída. Confirme com a consulta (status completed) antes de liberar o pedido.
order.expiredA ordem expirou sem pagamento.
order.canceledA ByteMax cancelou a ordem, por exemplo porque o pagamento não pôde ser aceito e foi devolvido ao pagador.
order.updatedMudou 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.createdUm reembolso pedido pela sua conta, pela API ou pelo painel, foi registrado. Reembolsos feitos pelo suporte aparecem só em order.updated.
refund.succeededO reembolso terminou: o valor foi devolvido ao pagador.
refund.failedNão foi possível concluir o reembolso.
webhook.testEvento 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.

Exemplo: order.completed
{
  "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)

O que chega no seu servidor
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 id do 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 code diz 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á pending ou ficou not_published) ou REDELIVERY_REJECTED (o serviço de entregas recusou). Um evento pending pode ser reenviado quando GET /events/{id} mostrar published.
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 id dele 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 items e next_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 novos events.
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.

POST/webhooks

Criar webhook

Cria o webhook e devolve o segredo de assinatura.

Corpo JSON
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.test não pode ser assinado: ele só chega pelo teste.
enabledbooleanObrigatório: Não
Se o webhook recebe eventos. Padrão: true.
Requisição
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}'
Resposta 201
{
  "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>"
}
POST/webhooks/{id}/test-events

Enviar teste

Envia um webhook.test para este webhook. O corpo é um objeto JSON vazio.

Parâmetros
ParâmetroOndeObrigatório
idcaminhoSim
Requisição
curl --request POST "https://bytemax.exchange/api/v1/webhooks/ep_example/test-events" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{}'
Resposta 202
{
  "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"
}
POST/webhooks/{id}/redeliveries

Reenviar eventos

Reenvia até 100 eventos para este webhook. A resposta traz o resultado de cada um.

Parâmetros
ParâmetroOndeObrigatório
idcaminhoSim
Corpo JSON
event_idsarrayObrigatório: Sim
IDs dos eventos a reenviar, de 1 a 100, sem repetir.
Requisição
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"]}'
Resposta 200
{
  "items": [
    {
      "event_id": "evt_example",
      "status": "queued"
    }
  ]
}

Outras operações

OperaçãoNomeO que faz
GET/webhooksListar webhooksTodos os webhooks da sua conta, inclusive os criados na API anterior (api_version: "legacy").
GET/webhooks/{id}Consultar webhookUm webhook. Com include_signing_secret=true, inclui o segredo de assinatura.
PATCH/webhooks/{id}Alterar webhookURL, 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 webhookExclui o webhook.
GET/eventsListar eventosEventos dos últimos 30 dias e seu estado de publicação.
GET/events/{id}Consultar eventoUm evento e seu estado de publicação.
GET/webhooks/{id}/deliveriesListar entregasTentativas 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.