Zum Inhalt springen

Webhooks

Bona Fide sendet für jedes abonnierte Umschlag-Event einen HTTPS-POST an Ihren Endpunkt. Die Zustellungen folgen der Spezifikation Standard Webhooks, sodass jede ihrer Bibliotheken sie verifizieren kann.

Unter Einstellungen › Webhooks oder mit einem API-Schlüssel, der den Scope org:manage hat:

Terminal-Fenster
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"]
}'

Die Antwort enthält secret (whsec_…), nur dieses eine Mal. Eine leere events-Liste abonniert alle Events. Die URL muss öffentlich und https:// sein. Ein Endpunkt gehört zu einem Modus: Mit einem Testschlüssel erstellte Endpunkte erhalten nur Events von Umschlägen im Testmodus, Live-Endpunkte nur Live-Events.

PATCH /v1/webhook-endpoints/{id} ändert URL, Events oder Beschreibung und pausiert oder reaktiviert den Endpunkt (enabled). POST /v1/webhook-endpoints/{id}/test sendet einen webhook.test-Ping.

Typ Wann
envelope.created Der Umschlag wurde erstellt
envelope.ready Das Dokument ist gerendert und der Umschlag bereit für seine Empfänger
recipient.sent Ein Empfänger ist an der Reihe (und bei Zustellung per E-Mail wurde sein Link gesendet)
recipient.viewed Ein Empfänger hat die Signaturseite zum ersten Mal geöffnet
recipient.signed Ein Empfänger hat abgesendet (oder es wurde automatisch gegengezeichnet)
recipient.declined Ein Empfänger hat abgelehnt
envelope.completed Alle Empfänger sind fertig. data.values enthält die Variablen und alle eingegebenen Werte
envelope.sealed Das versiegelte PDF steht zum Download bereit
envelope.declined Der Umschlag endete, weil ein Empfänger abgelehnt hat
envelope.voided Sie haben den Umschlag storniert
envelope.expired expiresAt ist vor dem Abschluss verstrichen
signing_link.used Ein Besucher hat über einen dauerhaften Signaturlink einen Umschlag gestartet

acceptance.created ist im Schema reserviert und wird noch nicht ausgelöst.

{
"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 ist der vollständige Umschlag zum Zeitpunkt des Events. data.values gibt es nur bei envelope.completed: die von Ihnen gesendeten Variablen und die Feldwerte jeder Rolle nach Feld-ID.

Jede Zustellung enthält:

Header Wert
webhook-id Die Event-ID (evt_…); bei jeder Wiederholung gleich. Verwenden Sie sie zur Deduplizierung
webhook-timestamp Unix-Sekunden, zu denen dieser Versuch signiert wurde
webhook-signature v1,<base64 HMAC-SHA256>, durch Leerzeichen getrennt, wenn mehr als ein Secret signiert
user-agent BonaFide-Webhooks/1

Die Signatur ist ein HMAC-SHA256 über {webhook-id}.{webhook-timestamp}.{raw body}, mit dem base64-dekodierten Teil des Secrets nach whsec_ als Schlüssel. Verifizieren Sie den rohen Body (vor dem JSON-Parsing), vergleichen Sie in konstanter Zeit und weisen Sie Zeitstempel zurück, die mehr als fünf Minuten von Ihrer Uhr abweichen.

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

Eine Zustellung ist erfolgreich bei jedem 2xx innerhalb von 10 Sekunden. Weiterleitungen werden nicht verfolgt. Alles andere wird mit Backoff wiederholt, nach 5 Sekunden, 5 Minuten, 30 Minuten, 2 Stunden, 5 Stunden, 10 Stunden, 14 Stunden, 20 Stunden und 24 Stunden, höchstens drei Tage nach dem Event. Danach wird die Zustellung als fehlgeschlagen markiert.

  • Antworten Sie schnell und verarbeiten Sie asynchron; deduplizieren Sie anhand von webhook-id.
  • Zustellungen können in anderer Reihenfolge eintreffen: Prüfen Sie data.envelope.status, statt eine Abfolge vorauszusetzen.
  • GET /v1/webhook-endpoints/{id}/deliveries listet die letzten Versuche mit Statuscodes, Fehlern und Laufzeiten auf, und jeder Endpunkt zeigt seine Erfolgsquote der letzten 24 Stunden (health).
  • POST /v1/events/{id}/redeliver sendet ein Event erneut an einen Endpunkt, etwa nach einem Ausfall.

POST /v1/webhook-endpoints/{id}/secret/rotate liefert sofort ein neues Secret. In den nächsten 24 Stunden wird jede Zustellung mit beiden Secrets signiert, dem neuen und dem alten (zwei Einträge in webhook-signature), sodass Sie das neue Secret ausrollen können, ohne Events zu verlieren.