Pular para o conteúdo

Webhooks

A Bona Fide envia um POST HTTPS para o seu endpoint a cada evento de envelope em que você se inscreve. As entregas seguem a especificação Standard Webhooks, então qualquer uma das bibliotecas dela pode verificá-las.

Em Configurações › Webhooks ou com uma chave de API que tenha o escopo org:manage:

Janela do terminal
curl https://api.bonafidesign.com/v1/webhook-endpoints \
-H "Authorization: Bearer $BONA_FIDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/hooks/bona-fide",
"description": "Production",
"events": ["envelope.completed", "envelope.sealed", "envelope.declined"]
}'

A resposta inclui o secret (whsec_…), somente desta vez. Uma lista events vazia inscreve o endpoint em todos os eventos. A URL precisa ser https:// pública. Um endpoint pertence a um único modo: endpoints criados com uma chave de teste recebem apenas eventos de envelopes do modo de teste, e os de produção, apenas eventos de produção.

PATCH /v1/webhook-endpoints/{id} altera a URL, os eventos ou a descrição e pausa ou retoma o endpoint (enabled). POST /v1/webhook-endpoints/{id}/test envia um ping webhook.test.

Tipo Quando
envelope.created O envelope foi criado
envelope.ready O documento foi renderizado e o envelope está pronto para os destinatários
recipient.sent Chegou a vez de um destinatário (e, com entrega por e-mail, o link dele foi enviado)
recipient.viewed Um destinatário abriu a página de assinatura pela primeira vez
recipient.signed Um destinatário enviou (ou foi contra-assinado automaticamente)
recipient.declined Um destinatário recusou
envelope.completed Todos os destinatários terminaram. data.values traz as variáveis e todos os valores preenchidos
envelope.sealed O PDF selado está pronto para download
envelope.declined O envelope foi encerrado porque um destinatário recusou
envelope.voided Você anulou o envelope
envelope.expired O expiresAt passou antes da conclusão
signing_link.used Um visitante iniciou um envelope a partir de um link de assinatura permanente

acceptance.created está reservado no esquema e ainda não é emitido.

{
"id": "evt_9sKq2Lm4Tz",
"type": "envelope.completed",
"createdAt": "2026-10-13T14:09:52.004Z",
"testMode": false,
"data": {
"envelope": {
"id": "env_8Gm2kQ4rT1",
"status": "completed",
"seal": "pending",
"recipients": [{ "id": "rcp_5Jw0pLs9Xe", "role": "client", "status": "completed", "…": "…" }],
"externalId": "user_8841",
"metadata": {},
"…": "…"
},
"values": {
"variables": { "client": { "name": "Acme Robotics, Inc." }, "effective_date": "2026-10-13" },
"recipients": {
"client": { "client_title": "CEO", "start_date": "2026-11-01" }
}
}
}
}

data.envelope é o envelope completo no momento do evento. data.values só aparece em envelope.completed: as variáveis que você enviou e os valores dos campos de cada papel, por id de campo.

Cada entrega traz:

Cabeçalho Valor
webhook-id O id do evento (evt_…); o mesmo em todas as novas tentativas. Use-o para deduplicar
webhook-timestamp Segundos Unix em que esta tentativa foi assinada
webhook-signature v1,<base64 HMAC-SHA256>, separados por espaço quando mais de um segredo assina
user-agent BonaFide-Webhooks/1

A assinatura é um HMAC-SHA256 sobre {webhook-id}.{webhook-timestamp}.{raw body}, com a chave formada pela parte do segredo depois de whsec_, decodificada de base64. Verifique o corpo bruto (antes do parsing do JSON), compare em tempo constante e rejeite carimbos de data e hora com mais de cinco minutos de diferença em relação ao seu relógio.

import express from 'express';
import { Webhook } from 'standardwebhooks'; // npm i standardwebhooks
const wh = new Webhook(process.env.BONA_FIDE_WEBHOOK_SECRET!); // whsec_…
const app = express();
app.post('/hooks/bona-fide', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = wh.verify(req.body, req.headers as Record<string, string>); // throws if forged or too old
} catch {
return res.sendStatus(400);
}
queue.add(event); // do the work asynchronously and answer quickly
res.sendStatus(204);
});

Uma entrega é bem-sucedida com qualquer 2xx em até 10 segundos. Redirecionamentos não são seguidos. Qualquer outra resposta gera novas tentativas com backoff, depois de 5 segundos, 5 minutos, 30 minutos, 2 horas, 5 horas, 10 horas, 14 horas, 20 horas e 24 horas, por no máximo três dias após o evento. Depois disso, a entrega é marcada como falha.

  • Responda rápido e processe de forma assíncrona; deduplique pelo webhook-id.
  • As entregas podem chegar fora de ordem: confira data.envelope.status em vez de presumir uma sequência.
  • GET /v1/webhook-endpoints/{id}/deliveries lista as tentativas recentes com códigos de status, erros e tempos, e cada endpoint mostra a taxa de sucesso das últimas 24 horas (health).
  • POST /v1/events/{id}/redeliver envia um evento a um endpoint de novo, por exemplo depois de uma indisponibilidade.

POST /v1/webhook-endpoints/{id}/secret/rotate retorna um novo segredo imediatamente. Nas 24 horas seguintes, toda entrega é assinada com os dois segredos, o novo e o antigo (duas entradas em webhook-signature), para que você possa implantar o novo segredo sem perder eventos.