Salta ai contenuti

Webhook

Bona Fide invia una richiesta HTTPS POST al Suo endpoint per ogni evento di busta a cui si è iscritto. Le consegne seguono la specifica Standard Webhooks, quindi qualsiasi sua libreria può verificarle.

In Impostazioni › Webhook, oppure con una chiave API che ha l’ambito org:manage:

Finestra del terminale
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"]
}'

La risposta include secret (whsec_…), solo questa volta. Un elenco events vuoto iscrive a tutti gli eventi. L’URL deve essere un indirizzo https:// pubblico. Un endpoint appartiene a una sola modalità: gli endpoint creati con una chiave di prova ricevono solo gli eventi delle buste in modalità di prova, quelli di produzione solo gli eventi di produzione.

PATCH /v1/webhook-endpoints/{id} cambia URL, eventi o descrizione e sospende o riattiva l’endpoint (enabled). POST /v1/webhook-endpoints/{id}/test invia un ping webhook.test.

Tipo Quando
envelope.created La busta è stata creata
envelope.ready Il documento è stato composto e la busta è pronta per i destinatari
recipient.sent È arrivato il turno di un destinatario (e, con la consegna via e-mail, il suo link è stato inviato)
recipient.viewed Un destinatario ha aperto la pagina di firma per la prima volta
recipient.signed Un destinatario ha inviato (o è stato controfirmato automaticamente)
recipient.declined Un destinatario ha rifiutato
envelope.completed Tutti i destinatari hanno terminato. data.values contiene le variabili e tutti i valori inseriti
envelope.sealed Il PDF sigillato è pronto per il download
envelope.declined La busta si è chiusa perché un destinatario ha rifiutato
envelope.voided Lei ha annullato la busta
envelope.expired expiresAt è trascorso prima del completamento
signing_link.used Un visitatore ha avviato una busta da un link di firma sempre attivo

acceptance.created è riservato nello schema e non viene ancora emesso.

{
"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 è la busta completa al momento dell’evento. data.values è presente solo in envelope.completed: le variabili che ha inviato e i valori dei campi di ogni ruolo, per id del campo.

Ogni consegna contiene:

Header Valore
webhook-id L’id dell’evento (evt_…); è lo stesso a ogni nuovo tentativo. Lo usi per la deduplicazione
webhook-timestamp Secondi Unix del momento in cui questo tentativo è stato firmato
webhook-signature v1,<base64 HMAC-SHA256>, separati da spazi quando firma più di un segreto
user-agent BonaFide-Webhooks/1

La firma è un HMAC-SHA256 su {webhook-id}.{webhook-timestamp}.{raw body}, con chiave pari alla parte del segreto dopo whsec_, decodificata da base64. Verifichi il corpo grezzo (prima del parsing JSON), esegua il confronto in tempo costante e rifiuti i timestamp che si discostano di oltre cinque minuti dal Suo orologio.

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);
});

Una consegna riesce con qualsiasi 2xx entro 10 secondi. I reindirizzamenti non vengono seguiti. In tutti gli altri casi la consegna viene ritentata con backoff, dopo 5 secondi, 5 minuti, 30 minuti, 2 ore, 5 ore, 10 ore, 14 ore, 20 ore e 24 ore, per al massimo tre giorni dopo l’evento. Dopodiché la consegna viene contrassegnata come non riuscita.

  • Risponda rapidamente ed elabori in modo asincrono; esegua la deduplicazione su webhook-id.
  • Le consegne possono arrivare fuori ordine: controlli data.envelope.status invece di presupporre una sequenza.
  • GET /v1/webhook-endpoints/{id}/deliveries elenca i tentativi recenti con codici di stato, errori e tempi, e ogni endpoint mostra la propria percentuale di successo nelle ultime 24 ore (health).
  • POST /v1/events/{id}/redeliver invia di nuovo un evento a un endpoint, ad esempio dopo un’interruzione del servizio.

POST /v1/webhook-endpoints/{id}/secret/rotate restituisce subito un nuovo segreto. Per le 24 ore successive ogni consegna viene firmata con entrambi i segreti, il nuovo e il vecchio (due voci in webhook-signature), così può distribuire il nuovo segreto senza perdere eventi.