تخطَّ إلى المحتوى

Webhooks

ترسل Bona Fide طلب HTTPS من نوع POST إلى نقطة النهاية لديك عن كل حدث مظروف تشترك فيه. تتبع عمليات التسليم مواصفة Standard Webhooks، لذا يمكن لأي من مكتباتها التحقق منها.

في الإعدادات › Webhooks، أو باستخدام مفتاح API يملك النطاق 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"]
}'

تتضمن الاستجابة secret (whsec_…)، في هذه المرة فقط. وقائمة events الفارغة تشترك في كل الأحداث. يجب أن يكون عنوان URL عامًا بصيغة https://. وتنتمي نقطة النهاية إلى وضع واحد: نقاط النهاية التي أُنشئت بمفتاح اختبار لا تتلقى إلا أحداث مظاريف وضع الاختبار، والمباشرة لا تتلقى إلا الأحداث المباشرة.

يغيّر PATCH /v1/webhook-endpoints/{id} عنوان URL أو الأحداث أو الوصف، ويوقف نقطة النهاية مؤقتًا أو يستأنفها (enabled). ويرسل POST /v1/webhook-endpoints/{id}/test إشارة اختبار webhook.test.

النوع متى
envelope.created أُنشئ المظروف
envelope.ready عُرض المستند وأصبح المظروف جاهزًا لمستلميه
recipient.sent حان دور أحد المستلمين (ومع التسليم عبر البريد الإلكتروني، أُرسل إليه رابطه)
recipient.viewed فتح أحد المستلمين صفحة التوقيع للمرة الأولى
recipient.signed أرسل أحد المستلمين توقيعه (أو وُقِّع توقيعًا مقابلًا تلقائيًا)
recipient.declined رفض أحد المستلمين
envelope.completed أنهى كل المستلمين. يتضمن data.values المتغيرات وكل قيمة مُدخلة
envelope.sealed ملف PDF المختوم جاهز للتنزيل
envelope.declined انتهى المظروف لأن أحد المستلمين رفض
envelope.voided ألغيت المظروف
envelope.expired انقضى expiresAt قبل الإتمام
signing_link.used بدأ زائر مظروفًا من رابط توقيع دائم

acceptance.created محجوز في المخطط ولا يُطلَق بعد.

{
"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 هو المظروف كاملًا وقت وقوع الحدث. ولا يوجد data.values إلا في envelope.completed: المتغيرات التي أرسلتها، وقيم حقول كل دور حسب معرّف الحقل.

يحمل كل تسليم:

الترويسة القيمة
webhook-id معرّف الحدث (evt_…)؛ وهو نفسه في كل إعادة محاولة. استخدمه لإزالة التكرار
webhook-timestamp ثواني Unix لحظة توقيع هذه المحاولة
webhook-signature v1,<base64 HMAC-SHA256>، مفصولة بمسافات عندما يوقّع أكثر من سر واحد
user-agent BonaFide-Webhooks/1

التوقيع هو HMAC-SHA256 على {webhook-id}.{webhook-timestamp}.{raw body}، ومفتاحه هو الجزء المفكوك من base64 من السر بعد whsec_. تحقّق من الجسم الخام (قبل تحليل JSON)، وقارن في زمن ثابت، وارفض الطوابع الزمنية التي تبعد أكثر من خمس دقائق عن ساعتك.

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

ينجح التسليم عند أي استجابة 2xx خلال 10 ثوانٍ. ولا تُتبع عمليات إعادة التوجيه. وأي شيء آخر تُعاد محاولته بتأخير متزايد، بعد 5 ثوانٍ، و5 دقائق، و30 دقيقة، وساعتين، و5 ساعات، و10 ساعات، و14 ساعة، و20 ساعة، و24 ساعة، لمدة ثلاثة أيام على الأكثر بعد الحدث. ثم يُعلَّم التسليم بأنه فاشل.

  • أجب بسرعة وعالج بشكل غير متزامن؛ وأزل التكرار بالاعتماد على webhook-id.
  • قد تصل عمليات التسليم بغير ترتيبها: تحقّق من data.envelope.status بدلًا من افتراض تسلسل معيّن.
  • يسرد GET /v1/webhook-endpoints/{id}/deliveries المحاولات الأخيرة مع رموز الحالة والأخطاء والتوقيتات، وتعرض كل نقطة نهاية معدل نجاحها خلال 24 ساعة (health).
  • يرسل POST /v1/events/{id}/redeliver حدثًا إلى نقطة نهاية مرة أخرى، مثلًا بعد انقطاع الخدمة.

يعيد POST /v1/webhook-endpoints/{id}/secret/rotate سرًا جديدًا على الفور. وخلال الساعات الأربع والعشرين التالية يُوقَّع كل تسليم بكل من السر الجديد والقديم (إدخالان في webhook-signature)، لكي تتمكن من نشر السر الجديد دون فقدان أي أحداث.