Webhooks
Bona Fide sender en HTTPS-POST til endepunktet ditt for hver konvolutthendelse du abonnerer på. Leveringene følger
spesifikasjonen Standard Webhooks, så alle bibliotekene for den kan verifisere
dem.
Registrere et endepunkt
Section titled “Registrere et endepunkt”Under Innstillinger › Webhooks, eller med en API-nøkkel som har omfanget
org:manage:
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"] }'Svaret inneholder secret (whsec_…), bare denne ene gangen. En tom events-liste abonnerer på alle hendelser.
URL-en må være en offentlig https://-adresse. Et endepunkt tilhører én modus: endepunkter som er opprettet med en
testnøkkel, mottar bare hendelser for konvolutter i testmodus, og endepunkter for produksjon bare hendelser fra
produksjon.
PATCH /v1/webhook-endpoints/{id} endrer URL-en, hendelsene eller beskrivelsen og setter endepunktet på pause eller
gjenopptar det (enabled). POST /v1/webhook-endpoints/{id}/test sender en webhook.test-ping.
Hendelser
Section titled “Hendelser”| Type | Når |
|---|---|
envelope.created |
Konvolutten ble opprettet |
envelope.ready |
Dokumentet er rendret, og konvolutten er klar for mottakerne |
recipient.sent |
Det ble en mottakers tur (og ved levering på e-post ble lenken sendt) |
recipient.viewed |
En mottaker åpnet signeringssiden for første gang |
recipient.signed |
En mottaker sendte inn (eller ble medsignert automatisk) |
recipient.declined |
En mottaker avslo |
envelope.completed |
Alle mottakerne er ferdige. data.values inneholder variablene og alle utfylte verdier |
envelope.sealed |
Den forseglede PDF-en er klar til nedlasting |
envelope.declined |
Konvolutten ble avsluttet fordi en mottaker avslo |
envelope.voided |
Du annullerte konvolutten |
envelope.expired |
expiresAt passerte før fullføring |
signing_link.used |
En besøkende startet en konvolutt fra en fast signeringslenke |
acceptance.created er reservert i skjemaet og sendes ikke ut ennå.
Nyttelast
Section titled “Nyttelast”{ "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 er hele konvolutten på hendelsestidspunktet. data.values finnes bare på
envelope.completed: variablene du sendte, og feltverdiene for hver rolle etter felt-ID.
Headere og signatur
Section titled “Headere og signatur”Hver levering har:
| Header | Verdi |
|---|---|
webhook-id |
Hendelsens ID (evt_…); den samme ved hvert nytt forsøk. Bruk den til deduplisering |
webhook-timestamp |
Unix-sekunder da dette forsøket ble signert |
webhook-signature |
v1,<base64 HMAC-SHA256>, atskilt med mellomrom når mer enn én hemmelighet signerer |
user-agent |
BonaFide-Webhooks/1 |
Signaturen er HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body}, med den base64-dekodede delen av
hemmeligheten etter whsec_ som nøkkel. Verifiser den rå brødteksten (før JSON-tolkningen), sammenlign i konstant
tid, og avvis tidsstempler som avviker mer enn fem minutter fra klokken din.
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);});# pip install standardwebhooks flaskimport osfrom flask import Flask, requestfrom standardwebhooks.webhooks import Webhook
wh = Webhook(os.environ["BONA_FIDE_WEBHOOK_SECRET"]) # whsec_…app = Flask(__name__)
@app.post("/hooks/bona-fide")def bona_fide(): try: event = wh.verify(request.get_data(), dict(request.headers)) except Exception: return "", 400 enqueue(event) return "", 204import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(secret: string, headers: Record<string, string>, rawBody: string) { const id = headers['webhook-id']; const ts = Number(headers['webhook-timestamp']); if (!id || !ts || Math.abs(Date.now() / 1000 - ts) > 300) throw new Error('stale or missing headers'); const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64'); const expected = createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest(); const ok = (headers['webhook-signature'] ?? '').split(' ').some((part) => { const [version, sig] = part.split(','); const given = Buffer.from(sig ?? '', 'base64'); return version === 'v1' && given.length === expected.length && timingSafeEqual(given, expected); }); if (!ok) throw new Error('bad signature'); return JSON.parse(rawBody);}Nye forsøk
Section titled “Nye forsøk”En levering lykkes ved en hvilken som helst 2xx innen 10 sekunder. Videresendinger følges ikke. Alt annet prøves på
nytt med økende ventetid, etter 5 sekunder, 5 minutter, 30 minutter, 2 timer, 5 timer, 10 timer, 14 timer, 20 timer og
24 timer, i høyst tre dager etter hendelsen. Deretter merkes leveringen som mislykket.
- Svar raskt og behandle asynkront; dedupliser på
webhook-id. - Leveringer kan komme i feil rekkefølge: sjekk
data.envelope.statusi stedet for å anta en rekkefølge. GET /v1/webhook-endpoints/{id}/deliveriesviser nylige forsøk med statuskoder, feil og tidsbruk, og hvert endepunkt viser suksessraten for de siste 24 timene (health).POST /v1/events/{id}/redeliversender en hendelse til et endepunkt på nytt, for eksempel etter et driftsavbrudd.
Rotere hemmeligheten
Section titled “Rotere hemmeligheten”POST /v1/webhook-endpoints/{id}/secret/rotate returnerer en ny hemmelighet umiddelbart. De neste 24 timene signeres
hver levering med både den nye og den gamle hemmeligheten (to oppføringer i webhook-signature), så du kan rulle ut
den nye hemmeligheten uten å miste hendelser.