Przejdź do głównej zawartości

Webhooki

Bona Fide wysyła żądanie HTTPS POST do Twojego punktu końcowego dla każdego subskrybowanego zdarzenia koperty. Dostarczenia są zgodne ze specyfikacją Standard Webhooks, więc może je zweryfikować dowolna z jej bibliotek.

W sekcji Ustawienia › Webhooki lub za pomocą klucza API z zakresem org:manage:

Okno terminala
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"]
}'

Odpowiedź zawiera secret (whsec_…) – tylko ten jeden raz. Pusta lista events subskrybuje wszystkie zdarzenia. Adres URL musi być publicznym adresem https://. Punkt końcowy należy do jednego trybu: punkty końcowe utworzone kluczem testowym otrzymują tylko zdarzenia kopert w trybie testowym, a produkcyjne – tylko zdarzenia produkcyjne.

PATCH /v1/webhook-endpoints/{id} zmienia adres URL, zdarzenia lub opis oraz wstrzymuje lub wznawia punkt końcowy (enabled). POST /v1/webhook-endpoints/{id}/test wysyła testowy ping webhook.test.

Typ Kiedy
envelope.created Koperta została utworzona
envelope.ready Dokument jest wyrenderowany, a koperta gotowa dla odbiorców
recipient.sent Nadeszła kolej odbiorcy (a przy dostarczaniu e-mailem wysłano mu link)
recipient.viewed Odbiorca po raz pierwszy otworzył stronę podpisywania
recipient.signed Odbiorca przesłał podpis (lub nastąpiła automatyczna kontrasygnata)
recipient.declined Odbiorca odmówił
envelope.completed Wszyscy odbiorcy zakończyli. data.values zawiera zmienne i wszystkie wpisane wartości
envelope.sealed Zapieczętowany PDF jest gotowy do pobrania
envelope.declined Koperta zakończyła się, ponieważ odbiorca odmówił
envelope.voided Unieważniono kopertę
envelope.expired expiresAt minęło przed zakończeniem
signing_link.used Odwiedzający rozpoczął kopertę ze stałego linku do podpisu

acceptance.created jest zarezerwowane w schemacie i jeszcze nie jest emitowane.

{
"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 to pełna koperta w chwili zdarzenia. data.values występuje tylko w envelope.completed: wysłane przez Ciebie zmienne oraz wartości pól każdej roli według identyfikatora pola.

Każde dostarczenie zawiera:

Nagłówek Wartość
webhook-id Identyfikator zdarzenia (evt_…); taki sam przy każdym ponowieniu. Używaj go do deduplikacji
webhook-timestamp Czas podpisania tej próby w sekundach uniksowych
webhook-signature v1,<base64 HMAC-SHA256>, rozdzielane spacjami, gdy podpisuje więcej niż jeden sekret
user-agent BonaFide-Webhooks/1

Podpis to HMAC-SHA256 obliczony z {webhook-id}.{webhook-timestamp}.{raw body} z kluczem w postaci zdekodowanej z base64 części sekretu po whsec_. Weryfikuj surową treść (przed parsowaniem JSON), porównuj w stałym czasie i odrzucaj znaczniki czasu odbiegające od Twojego zegara o więcej niż pięć minut.

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

Dostarczenie kończy się powodzeniem przy dowolnej odpowiedzi 2xx w ciągu 10 sekund. Przekierowania nie są wykonywane. Każda inna odpowiedź powoduje ponawianie z narastającym odstępem: po 5 sekundach, 5 minutach, 30 minutach, 2 godzinach, 5 godzinach, 10 godzinach, 14 godzinach, 20 godzinach i 24 godzinach, najdłużej przez trzy dni od zdarzenia. Następnie dostarczenie jest oznaczane jako nieudane.

  • Odpowiadaj szybko, a przetwarzaj asynchronicznie; deduplikuj według webhook-id.
  • Dostarczenia mogą nadchodzić w innej kolejności: sprawdzaj data.envelope.status, zamiast zakładać określoną sekwencję.
  • GET /v1/webhook-endpoints/{id}/deliveries wyświetla ostatnie próby z kodami statusu, błędami i czasami, a każdy punkt końcowy pokazuje swój wskaźnik powodzenia z ostatnich 24 godzin (health).
  • POST /v1/events/{id}/redeliver ponownie wysyła zdarzenie do punktu końcowego, na przykład po awarii.

POST /v1/webhook-endpoints/{id}/secret/rotate natychmiast zwraca nowy sekret. Przez kolejne 24 godziny każde dostarczenie jest podpisywane zarówno nowym, jak i starym sekretem (dwa wpisy w webhook-signature), dzięki czemu możesz wdrożyć nowy sekret bez utraty zdarzeń.