Documentação da API

Webhooks e verificação de assinatura

Como receber eventos do BetBackoffice no seu servidor, verificar a assinatura e lidar com retentativas.

Webhooks avisam o seu servidor sobre eventos (decisão de KYC, mudança de status de saque, depósito confirmado…) sem que você precise consultar a API repetidamente.

Eventos

Evento Quando
player.status_changed a situação da conta do jogador mudou (ex.: suspensão, autoexclusão)
kyc.status_changed a situação do KYC mudou (ex.: em_analise → aprovado)
deposit.confirmed um depósito foi confirmado e creditado
deposit.failed um depósito foi marcado como não concretizado
withdrawal.status_changed a situação pública do saque mudou (under_review, approved, paid, rejected, cancelled, failed)
webhook.test evento de teste, enviado por POST /webhooks/test

Os esquemas dos payloads estão na seção webhooks da referência OpenAPI. Todo evento tem o mesmo envelope: id, type, createdAt, apiVersion e data.

Receber

  • Exponha um endpoint HTTPS público no seu servidor; a URL é configurada pela equipe (não são aceitos http, IPs privados nem localhost).
  • Responda 2xx em poucos segundos (o limite é de 10 s) e processe o evento de forma assíncrona. Qualquer outra resposta, incluindo redirecionamentos (3xx), conta como falha.
  • As entregas são at-least-once: podem chegar repetidas. Use o cabeçalho X-Webhook-Id (ou o id do evento) como chave de deduplicação.
  • Falhas são retentadas com espera exponencial (30 s, 1 min, 2 min…, até 6 h), no máximo 8 tentativas. Depois disso o evento fica como falho e a equipe pode reenviá-lo.

Cabeçalhos de cada entrega

Cabeçalho Conteúdo
X-Webhook-Id id do evento (igual em todas as tentativas)
X-Webhook-Timestamp epoch em segundos desta tentativa
X-Webhook-Signature hex do HMAC-SHA256 de TIMESTAMP + "." + CORPO_BRUTO com o segredo whsec_…

Verificar a assinatura

Recalcule o HMAC sobre o corpo bruto (os bytes recebidos, antes de qualquer parse de JSON) e compare em tempo constante.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyWebhook(rawBody, headers, secret) {
  const timestamp = headers["x-webhook-timestamp"];
  const signature = headers["x-webhook-signature"];
  if (!timestamp || !signature) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Rejeite (401) qualquer entrega que falhe na verificação.

Testar

Depois que a equipe configurar a URL e o segredo, chame POST /webhooks/test: um evento webhook.test é enviado à sua URL em alguns segundos. Em sandbox, as rotas de decisão de KYC e saque disparam os eventos reais. O testador da documentação tem um verificador de webhook para conferir uma entrega recebida.

Verificação em outras linguagens e vetor de teste

Os snippets abaixo incluem a verificação do webhook em Node.js, Python, PHP, Go, Java, C# e bash, com o vetor de teste (segredo, timestamp, corpo bruto e assinatura esperada).

sign.mjs

import { createHash, createHmac, timingSafeEqual } from "node:crypto";

/** Assina uma requisição: retorna o valor do cabeçalho X-Signature. */
export function signRequest(secret, method, pathWithQuery, timestamp, body = "") {
  const canonical = [
    method.toUpperCase(),
    pathWithQuery, // exatamente como enviado, com /api/v1 e a query string
    timestamp, // epoch em segundos (string)
    createHash("sha256").update(body).digest("hex"),
  ].join("\n");
  return createHmac("sha256", secret).update(canonical).digest("hex");
}

/** Verifica um webhook recebido (use o corpo BRUTO, antes de parsear o JSON). */
export function verifyWebhook(secret, timestamp, rawBody, signature) {
  const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Vetor de teste

Se o seu código gerar exatamente estes valores para as entradas abaixo, a assinatura está correta. O vetor também está em test-vectors.json.

Segredo do webhook
whsec_vetor_de_teste_nao_use_em_producao
X-Webhook-Timestamp
1700000000
Corpo bruto
{"id":"evt_vetor","type":"webhook.test","createdAt":"2023-11-14T22:13:20.000Z","apiVersion":"1.0.0","data":{"message":"ok"}}
X-Webhook-Signature esperada
a95e51addfc7fd14d048f689f85dfc36b8b8b3f48c8fd8dd98e114c4b6711c14