شبكات الويب تتلقى أحداث التوقيع في الوقت الحقيقي
قم بتعيين عنوان URL HTTPS في لوحة التحكم Certyneo الخاصة بك وتتلقى POST موقعة HMAC-SHA256 بمجرد حدوث حدث على المظروف: التوقيع، الرفض، انتهاء الصلاحية. 8 أحداث مدعومة، إعادة التجربة على مستوى 6 محاولات، التحقق من التشفير في 8 أسطر من الرموز.
< 5s
متوسط مدة التسليم بعد الحدث
5x
محاولات في حالة الفشل (حتى بعد 9 ساعات)
HMAC-SHA256
خوارزمية توقيع كل طلب
قائمة الأحداث
تتضمن الأحداث الثمانية أدناه دورة حياة كاملة لفاتورة Certyneo. قم بتشغيل الأحداث التي تهمك في الإعدادات → الويب هووك، وتجاهل الآخرين الاشتراك هو حجرة لكل حدث.
| الحدث | إطلاق |
|---|---|
envelope.created | يتم إنشاء غلاف (بواسطة واجهة المستخدم، واجهة برمجة التطبيقات أو قالب) مفيد لمزامنة تسجيل جانب CRM في وقت إنشائه. |
envelope.sent | يتم إرسال المظروف إلى الموقعين (أول بريد إلكتروني تم إرساله). يمثل بداية دورة التوقيع النشطة. |
envelope.completed | جميع الموقعين وقعوا. ويمكن الوصول إلى PDF eIDAS المختوم ومتابعة التدقيق عبر `proof_pdf_url` في الحمولة. |
envelope.declined | رفض أحد الموقعين الملف. سبب الرفض (إذا قدم من قبل الموقع) في `data.decline_reason`. |
envelope.voided | تم إلغاء المظروف من قبل المصدر قبل التوقيع الكامل. |
envelope.expired | لقد مرت فترة انتهاء صلاحية المظروف دون توقيع كامل. قائمة الموقعين المفقودين موجودة في `data.missing_signers`. |
recipient.signed | تم توقيع أحد الموقعين (ولكن ليس بالضرورة جميعهم) مفيد لدورات العمل المتتالية: إطلاق التحول إلى الموقع التالي. |
recipient.viewed | أحد الموقعين فتح رابط التوقيع دون أن يوقع بعد، مفيد لإعادة التجارة المستهدفة. |
شكل الحمولة
جميع الأحداث تتشارك نفس مخطط JSON العلوي: `event`, `envelope_id`, `occurred_at`, `data`. يختلف محتوى `data` حسب الحدث (حقول موثقة حسب الحدث في مرجع API). إليك مثال كامل `envelope.completed`.
{
"event": "envelope.completed",
"envelope_id": "env_01HG3K8X9Y2N4P5Q6R7S8T9V0W",
"occurred_at": "2026-05-27T08:42:13.521Z",
"data": {
"title": "Contrat de prestation Acme Corp",
"status": "completed",
"created_at": "2026-05-24T14:12:00.000Z",
"completed_at": "2026-05-27T08:42:13.000Z",
"signers": [
{
"email": "client@acme.example",
"name": "Alex Client",
"signed_at": "2026-05-27T08:42:13.000Z",
"method": "eidas_aes",
"ip": "203.0.113.42"
}
],
"proof_pdf_url": "https://certyneo.com/api/envelopes/env_01HG.../proof.pdf"
}
}يتم تشفير الحمولة بالرمز UTF-8 ، بدون BOM. يتم حساب توقيع HMAC على الجسم الخام كما تم إرساله لا تغير المساحات ، غالبًا ما يغير إعادة تحليل JSON ترتيب المفاتيح ويكسر التحقق.
تحقق من توقيع HMAC
يتم توقيع كل طلب باستخدام سر الويب هوك الخاص بك (يمكن رؤيته مرة واحدة عند إنشاؤه في لوحة التحكم، ثم يتم تشفيره في الراحة) ، ويتم نقل التوقيع في عنوان `Certyneo-Signature` بتنسيق `t=<timestamp>,v1=<hex_hmac>`. دائماً تحقق من التوقيع قبل معالجة الحمولة بدون هذه الخطوة، يمكن لأي شخص تزوير حدث و الاتصال بمنصبك.
Node.js / TypeScript
import crypto from "node:crypto";
export function verifyCertyneoSignature(
rawBody: string,
signatureHeader: string,
secret: string,
): boolean {
// Header format: t=<timestamp>,v1=<hex_hmac>
const parts = Object.fromEntries(
signatureHeader.split(",").map((p) => p.split("=")),
);
const ts = parts.t;
const sig = parts.v1;
if (!ts || !sig) return false;
// Reject events older than 5 minutes (replay protection).
const age = Math.abs(Date.now() / 1000 - Number(ts));
if (age > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
// timingSafeEqual to mitigate timing attacks.
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(sig, "hex"),
);
}Python
import hashlib
import hmac
import time
def verify_certyneo_signature(
raw_body: bytes, signature_header: str, secret: str
) -> bool:
"""Verify a Certyneo webhook signature.
Header format: `t=<timestamp>,v1=<hex_hmac>`
Rejects events older than 5 minutes (replay protection).
"""
parts = dict(p.split("=") for p in signature_header.split(","))
ts = parts.get("t")
sig = parts.get("v1")
if not ts or not sig:
return False
if abs(time.time() - int(ts)) > 300:
return False
expected = hmac.new(
secret.encode("utf-8"),
f"{ts}.{raw_body.decode('utf-8')}".encode("utf-8"),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, sig)خطأ شائع
لا تستخدم `===` أو `==` لمقارنة التوقيع المتوقع مع التوقيع المستلم. استخدم وظيفة مؤقتة (`crypto.timingSafeEqual` في Node ، `hmac.compare_digest` في Python). خلاف ذلك ، فإن فاصل وقت المقارنة بين اثنين من التوقيعات يكشف السر تدريجياً لمهاجم مريض (هجوم توقيت).
سياسة إعادة التجربة
إذا كانت النتيجة النهائية غير HTTP 2xx (توقيت انتهاء، 5xx، اتصال رفض) ، سنقوم بالرد على النظام الاحتياطي. إجمالاً 6 محاولات في ~ 9 ساعات. بعد 6، يتم وضع علامة `فشل` على الحدث في لوحة تحكم شبكة الإنترنت الخاصة بك ويتم إرسال رسالة تنبيه عبر البريد الإلكتروني.
| محاولة | المدة المتراكمة | الوقت المنصرم |
|---|---|---|
| #1 | 0 | 0 |
| #2 | + 1 min | 1 min |
| #3 | + 5 min | 6 min |
| #4 | + 30 min | 36 min |
| #5 | + 2 h | 2h 36 |
| #6 | + 6 h | 8h 36 |
إذا كنت ترغب في إعادة تقديم حدث فشل يدوياً، فإن لوحة التحكم على الويب توفر زر إعادة التسليم على كل تسليم فشل متاح لمدة 7 أيام بعد الفشل النهائي.
اختبار دون إرسال مظروف حقيقي
نقطة النهاية `/v1/webhooks/test` تقبل عنوان URL ونوع حدث، وتضع حمولة وهمية موقعة تمامًا مثل الحملة الحقيقية. مثالية للتحقق من صحة المُدير الخاص بك في التكامل المستمر أو أثناء التطوير المحلي (مع ngrok أو ما يعادلها).
# Trigger a test webhook to your endpoint
curl -X POST https://api.certyneo.com/v1/webhooks/test \
-H "Authorization: Bearer $CERTYNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "envelope.completed", "url": "https://your.app/webhooks/certyneo"}'6 أساليب يجب اتباعها
- تحقق من توقيع HMAC قبل أي قراءة للجسم استخدم مقارنة آمنة للوقت.
- معالجة كل `envelope_id` × `event` مرة واحدة فقط من خلال تخزين المميزات التي تم رؤيتها بالفعل في القاعدة (يمكن أن تعيد التسجيلات نفس الحدث).
- يجب أن تجيب على HTTP 200 في 5 ثوانٍ كحد أقصى، ثم قم بمعالجة التسلسل غير المتزامن، وإلا سيتم إيقافك وتعتبر محاولة إعادة.
- تسجيل الجسم الخام + التوقيع الكامل في التحليل الاختياري التحقق من HMAC غالبا ما يفشل على BOM أو مساحة بيضاء غير مرئية.
- إدخال "موت الرسالة" على التوقيت "الفشل" لتتبعها يدوياً في حالة وقوع حادث على جانب قسمك
- يجب أن تتسامح مع فترة 5 دقائق بين `t=` و وقت الاستقبال بعد ذلك، و يجب أن ترفض لتغلق المشاركات.
للذهاب إلى أبعد من ذلك
هل أنتم مستعدون لربط أنظمتكم؟
إنشاء حساب مجاني في دقيقتين تطبيق webhook متاح من الخطة الابتدائية (مجانية، 5 غلافات/شهر).