Webhooks de saída
Webhooks notificam um servidor externo sobre eventos habilitados da organização. A organização escolhe uma URL e os tipos de evento. O catálogo disponível é consultado na própria API; não presuma que toda mudança de tabela emita um webhook.
Rotas
| Operação | Endpoint em /api/v1 |
|---|---|
| Catálogo de eventos | GET /webhooks/event-kinds |
| Cadastro e listagem | POST, GET /webhooks |
| Detalhe e edição | GET, PATCH /webhooks/{webhook_id} |
| Revogação | POST /webhooks/{webhook_id}/revoke |
| Histórico de entregas | GET /webhooks/{webhook_id}/deliveries |
Leitura exige identity.webhooks.read; gestão exige identity.webhooks.manage. A criação recebe name, url e event_kinds. O segredo de assinatura, com prefixo whsec_, aparece uma única vez.
Fora de desenvolvimento, a URL precisa usar HTTPS e apontar para destino público permitido. O worker verifica a resolução DNS e não segue redirecionamentos.
Headers enviados
| Header | Conteúdo |
|---|---|
Content-Type | application/json |
User-Agent | <marca>-Webhooks/1.0 |
X-Sg-Event | Tipo de evento |
X-Sg-Delivery | Identificador da entrega |
X-Sg-Signature | t=TIMESTAMP,v1=DIGEST |
A assinatura é HMAC-SHA256 com o segredo completo. O conteúdo assinado é a concatenação do timestamp decimal, um ponto e o corpo JSON bruto: timestamp + "." + body.
Verificar a mensagem
- Leia o corpo original antes de reformatar ou desserializar o JSON.
- Extraia
tev1do header. - Rejeite timestamps fora da janela de tolerância adotada; o verificador do COBRES usa 300 segundos.
- Calcule o HMAC sobre os bytes esperados.
- Compare os digests em tempo constante.
- Deduplicate a entrega antes de executar um efeito de negócio.
Usar um objeto JSON reserializado pode alterar espaços, acentos ou ordem e invalidar a assinatura.
Entrega e repetição
O worker trata resposta 2xx como sucesso. Falhas de rede e respostas HTTP fora de 2xx geram novas tentativas pela outbox, com intervalo que cresce um minuto por tentativa até 30 minutos. Um destino recusado pela validação de segurança (resolução DNS para endereço não público) falha sem nova tentativa. O timeout de uma entrega é de 10 segundos. O corpo da resposta do destinatário não é armazenado.
Aceite a mensagem rapidamente e processe-a em uma fila própria quando o trabalho for demorado. Não dependa de entrega exatamente uma vez ou de uma ordem global de eventos. Guarde o identificador recebido e torne a atualização no consumidor idempotente.
Revogar o webhook impede novas entregas elegíveis. Use o histórico para investigar falhas e correlacione entregas com seus próprios logs, sem registrar o segredo.
Eventos de demandas e tarefas
Cada tarefa da cobrança e cada pedido de aprovação de proposta é uma demanda. Os eventos requests.demand.created, transitioned, closed, assigned, held, released, rescheduled e reopened trazem em data o retrato da demanda no momento do evento, para agir sem uma segunda leitura:
| Campo | Conteúdo |
|---|---|
code | Código público da demanda (é o que os caminhos /requests/demands/{código} recebem) |
request_type_key | Tipo: call, callback, verify_payment, approve_offer… |
workflow_key, stage_key, phase, outcome | Quadro, etapa, fase e desfecho |
title, due_at, due_precision | O que fazer e até quando (date ou time) |
assignee_id, held | Responsável e se está pausada |
pinned | Registro a que a demanda pertence, por exemplo {"kind": "cobres.debt", "target_id": "…"} |
Um pedido de aprovação decidido chega como requests.demand.closed com request_type_key = approve_offer e outcome fulfilled (aprovada), rejected (recusada) ou canceled (retirada ou sem validade).