Integrar

Webhooks

Em vez de fazer polling, registre um canal de webhook e o Gabinete360 fará um POST de cada evento ao seu endpoint assim que ele acontecer — assinado com HMAC-SHA256 para que você possa verificar que veio de nós.

1. Registrar um canal de webhook

Crie um canal webhook com a URL que o Gabinete360 deve chamar e um secret que você gera. O secret é usado para assinar cada entrega. Você também pode criar canais de webhook pelo painel.

curl -X POST https://gabinete360.ia.br/api/v1/channels \
  -H "Authorization: Bearer argos_ak_live_••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "webhook",
    "name": "Production webhook",
    "config": {
      "type": "webhook",
      "url": "https://your-app.com/argos/webhook",
      "secret": "whsec_a_long_random_string"
    }
  }'

2. O payload do evento

O Gabinete360 envia um POST com Content-Type: application/json. A assinatura HMAC fica no cabeçalho x-argos-signature como uma string hexadecimal.

corpo do POST
{
  "id": "c0ffee…",
  "eventType": "price_change",
  "severity": "high",
  "title": "Price changed on Acme pricing page",
  "summary": "Pro plan went from $49 to $59 / month.",
  "sourceUrl": "https://example.com/pricing"
}

3. Verificar a assinatura

A assinatura é HMAC-SHA256 sobre o corpo bruto da requisição, com a chave sendo o secret do seu canal, codificada em hexadecimal. Recalcule-a do seu lado e compare com uma verificação em tempo constante. Use os bytes brutos — reserializar o JSON já parseado pode alterar os espaços em branco e quebrar a comparação.

Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';

const app = express();

// Capture the RAW body — the signature is computed over the exact bytes sent.
app.post(
  '/argos/webhook',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.header('x-argos-signature') ?? '';
    const expected = createHmac('sha256', process.env.ARGOS_WEBHOOK_SECRET)
      .update(req.body) // raw Buffer, not the parsed JSON
      .digest('hex');

    const a = Buffer.from(signature, 'hex');
    const b = Buffer.from(expected, 'hex');
    if (a.length !== b.length || !timingSafeEqual(a, b)) {
      return res.status(401).send('invalid signature');
    }

    const event = JSON.parse(req.body.toString('utf8'));
    // ... handle the verified event ...
    res.status(200).send('ok');
  },
);

Sempre verifique antes de confiar em um payload

Um endpoint de webhook não verificado pode ser acessado por qualquer pessoa que descubra sua URL. Rejeite qualquer requisição cuja assinatura recalculada não coincida e mantenha seu secret fora do código do lado do cliente.

Respostas e retentativas

Retorne um status 2xx para confirmar o recebimento. Faça o processamento pesado de forma assíncrona e confirme rápido — o Gabinete360 expira em 10 segundos. Uma resposta diferente de 2xx marca a entrega como falha; falhas persistentes incrementam o contador de falhas do canal e podem pausar a entrega.