6Manual 6 de 6·4 minutos

Webhooks outbound — eventos Tokia no seu backend

Configure URL HTTPS pra Tokia disparar HTTP POST quando eventos acontecem (saldo baixo, top-up confirmado, key suspensa). HMAC SHA-256.

Em vez de fazer polling em /usage toda hora, configure webhooks outbound: Tokia faz HTTP POST pro seu endpoint sempre que evento importante acontece.

Eventos suportados (6 hoje)

| Evento | Quando dispara | Use case | |---|---|---| | balance.low | Saldo cruza threshold (default R$ 20). 1x/dia | Notifica Slack admin | | balance.topped_up | PIX/cartão confirmado | Atualiza dashboard interno | | key.created | Nova API key criada | Auditoria | | key.suspended | Saldo zerou ou admin suspendeu | Avisa user / trocar pra key backup | | payment.failed | Auto-topup falhou (cartão recusado) | Email user atualizar cartão | | key.budget_warning | Key cruzou 80% do budget em 24h | Antecipa upgrade de plan |

Passo 1 — Cria endpoint no seu backend

Endpoint deve:

  • Aceitar POST com body JSON
  • Validar HMAC SHA-256 header (anti-spoofing)
  • Responder 2xx em até 30s (Tokia desiste depois)
  • Idempotente (retries acontecem em falha)

Exemplo Node.js / Express:

import express from "express";
import crypto from "node:crypto";

const SIGNING_SECRET = process.env.TOKIA_WEBHOOK_SECRET!;

app.post(
  "/tokia-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.header("tokia-signature-sha-256");
    const expected = crypto
      .createHmac("sha256", SIGNING_SECRET)
      .update(req.body)
      .digest("hex");

    if (
      !signature ||
      signature.length !== expected.length ||
      !crypto.timingSafeEqual(
        Buffer.from(signature, "hex"),
        Buffer.from(expected, "hex")
      )
    ) {
      return res.status(401).end();
    }

    const payload = JSON.parse(req.body.toString());
    console.log(payload.event, payload.data);

    // Faz alguma ação (notifica Slack, atualiza DB, etc)

    res.status(200).end();
  }
);

Equivalente Python / FastAPI:

import hmac, hashlib, os
from fastapi import FastAPI, Request, HTTPException

SIGNING_SECRET = os.environ["TOKIA_WEBHOOK_SECRET"].encode()
app = FastAPI()

@app.post("/tokia-webhook")
async def tokia_webhook(request: Request):
    body = await request.body()
    signature = request.headers.get("tokia-signature-sha-256", "")
    expected = hmac.new(SIGNING_SECRET, body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(signature, expected):
        raise HTTPException(401, "invalid signature")
    payload = await request.json()
    # ... handle payload.event ...
    return {"ok": True}

Passo 2 — Cadastra webhook em /dashboard/webhooks

Dashboard webhooks

Clica "Cadastrar webhook":

  • URL do seu endpoint: HTTPS (HTTP rejeita em prod). Ex: https://api.minhasaas.com.br/tokia-webhook
  • Eventos: marca os que interessam (todos 6 default)

Clica "Criar webhook". Modal retorna signing_secret — copia agora, aparece UMA vez. Guarda no .env do seu backend:

TOKIA_WEBHOOK_SECRET=ws_abc123...

Passo 3 — Teste com "Ping"

No card do webhook recém-criado, botão "Ping" dispara evento test webhook.ping na hora. Seu backend recebe + você confere logs.

Pra teste rápido sem backend próprio, usa webhook.site:

  1. Abre https://webhook.site, copia URL única
  2. Cadastra essa URL em /dashboard/webhooks
  3. Clica "Ping"
  4. Vê o POST chegar na UI do webhook.site

Retry com backoff exponencial

Se seu endpoint retornar >=400 ou timeout, Tokia tenta de novo:

| Tentativa | Quando | |---|---| | 1 | imediato | | 2 | +1 minuto | | 3 | +5 minutos | | 4 | +30 minutos | | 5 | +4 horas | | ❌ Dead letter | após 5 falhas |

Eventos dead-letter aparecem em /dashboard/webhooks → card webhook → tab "Tentativas" com status dead_letter. Você pode clicar "Reativar" pra retentar manualmente.

Anatomia do payload

Todo evento tem essa estrutura:

{
  "event": "balance.topped_up",
  "delivery_id": "del_01HQ...",
  "delivered_at": "2026-05-13T14:32:00Z",
  "data": {
    "amount_brl": 50.00,
    "new_balance_brl": 87.50,
    "method": "pix"
  }
}

Headers HTTP do POST:

  • Content-Type: application/json
  • User-Agent: Tokia-Webhook/1.0
  • tokia-signature-sha-256: <hex hmac>
  • tokia-event: <event_name>
  • tokia-delivery-id: <delivery_id> (idempotência)

Limites

  • Máximo 5 webhooks ativos por conta Tokia
  • 30s timeout por request
  • 5 tentativas antes de dead letter
  • HMAC SHA-256 obrigatório
  • HTTPS only em produção

Webhook entrante (Asaas) é coisa diferente

Tokia também recebe webhooks (do Asaas, quando PIX confirma). Esse caminho é interno — você não precisa configurar nada, já vem pronto pra contas Tokia.

Próximo passo

Volta pro /docs pra ver guias técnicos mais profundos sobre cada API.