Webhooks tirċievi l-avvenimenti tas-sinjaġġ f'ħin reali
Ipprepara URL HTTPS fid-dashboard Certyneo tiegħek u tirċievi POST iffirmat HMAC-SHA256 malli jiġri xi ħaġa fuq il-kwestjonarju tiegħek: firma, rifjut, skadenza. 8 avvenimenti appoġġjati, reprova esponenzjali fuq 6 tentattivi, verifika kriptografika f'8 linji ta' kodiċi.
< 5s
Id-data medja ta' kunsinna wara l-avveniment
5x
Attentati jekk jonqsu (sa ~ 9h wara)
HMAC-SHA256
Algoritmu ta' firma għal kull talba
Katalgu tal-avvenimenti
L-8 avvenimenti hawn taħt jkopru ċ-ċiklu sħiħ tal-ħajja ta' kunsinna Certyneo. Ativa dawk li jinteressawk f'Settings → Webhooks, injora l-oħrajn is-sottoskrizzjoni hija granulari għal kull avveniment.
| Avveniment | Tqala |
|---|---|
envelope.created | Huwa maħluq envelope (per UI, API jew template) utli biex tissinkronizza reġistrazzjoni fuq in-naħa CRM mill-ħolqien. |
envelope.sent | L-envelop jintbagħat lill-firmatarji (l-ewwel email mibgħuta). Dan jimmarka l-bidu taċ-ċiklu ta' firma attiva. |
envelope.completed | Il-PDF issiġillat eIDAS u l-awditjar trail huma disponibbli permezz ta' `proof_pdf_url` fil-payload. |
envelope.declined | Ir-raġuni għar-rifjut (jekk mogħtija mis-sinjur) tinsab f'data.decline_reason. |
envelope.voided | L-envelop ġie kkanċellat mill-emittenti qabel ma l-firma tkun kompluta. |
envelope.expired | Id-data ta' skadenza tal-kwartina għaddiet mingħajr ma ġiet iffirmata b'mod sħiħ. Il-lista ta' min kien f'pożizzjoni li ma kienx ffirmat tinsab f'data.missing_signers. |
recipient.signed | F'dan il-każ, il-proċess ta' ċertifikazzjoni għandu jkun kompletament komplut. |
recipient.viewed | Wieħed li ffirma l-ittra ħareġ il-link biex jiffirma mingħajr ma kien għadu ffirmat, utli għal riklami kummerċjali mmirati. |
Format tal-payload
Il-ġrajjiet kollha jaqsmu l-istess skema ta' JSON top-level: `event`, `envelope_id`, `occurred_at`, `data`. Il-kontenut ta' `data` ivarja skont l-avveniment (kampijiet dokumentati għal kull avveniment fir-referenza API).
{
"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"
}
}Il-payload huwa encoded UTF-8, mingħajr BOM. Is-sinja HMAC hija kkalkulata fuq il-body raw kif mibgħuta ma tbiddilx l-ispazji, l-ipparsing mill-ġdid JSON spiss jibdel l-ordni tal-ċwievet u jkisser il-verifika.
Iċċekkja l-HMAC
Kull talba hija ffirmata bis-sigriet webhook tiegħek (viżibbli darba biss meta tinħoloq fid-dashboard, imbagħad ikkodifikata meta tkun qed toqgħod).<timestamp>,v1=<hex_hmac>`. Dejjem iċċekkja s-sinjata qabel ma tipproċessa l-payload mingħajr dan il-pass, kull min jista' jforża avveniment u jsejjaħ l-endpoint tiegħek.
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)Żball Komuni
Uża l-funzjoni time-safe (`crypto.timingSafeEqual` f'Node, `hmac.compare_digest` f'Python). inkella, id-differenza fil-ħin bejn żewġ sinjuri tiżvela l-kunċett lil attakkant paċenzjuż (timing attack).
Politika ta' ttestjar mill-ġdid
Jekk l-endpoint tiegħek jirrispondi xi ħaġa oħra ħlief HTTP 2xx (timeout, 5xx, connection refused), aħna nirringrazzjaw skont backoff esponenzjali. Total ta' 6 tentattivi f'~9 sigħat. Wara l-6, l-avveniment huwa mmarkat `failed` fid-dashboard webhook tiegħek u jintbagħat email ta' twissija.
| Attentat | Id-data tal-għeluq | Il-ħin li għadda |
|---|---|---|
| #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 |
Jekk trid tibgħat mill-ġdid event li ma jkunx sar, id-dashboard tal-webhook joffri buttuna Re-deliver fuq kull konsenja li ma tkunx saret disponibbli għal 7 ijiem wara li ma tkunx saret.
It-testijiet mingħajr ma tintbagħat enveloppa vera
L-endpoint `/v1/webhooks/test` jaċċetta URL u tip ta' avveniment, u POSTe payload fintiku ffirmat eżattament bħal reali. Ideali biex tivvalida l-maniġer tiegħek fl-integrazzjoni kontinwa jew waqt l-iżvilupp lokali (b'ngrok jew ekwivalenti).
# 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 Prattiki li Għandek Tsegwi
- Iċċekkja s-sinja HMAC QABEL kull qari tal-ġisem uża tqabbil li jkun timing-safe.
- Proċessa kull `envelope_id` × `event` darba biss billi taħżen l-IDs li diġà rajt fil-bażi (ir-ritrieħi jistgħu jerġgħu jagħtu l-istess avveniment).
- Tweġiba HTTP 200 fi żmien 5 sekondi, u mbagħad ipproċessa bħala asinkronju (laħlaħ). Inkella inti se tkun timeout u jingħatalha bħala reattemp.
- Il-logging tal-ġisem brut + is-sinjur sħiħ fid-debug il-verifika HMAC spiss tonqos fuq BOM jew spazju abjad inviżibbli.
- Tgħaqqad dead-letter fil-kera fuq l-avvenimenti `failed` biex tibgħat manwalment f'każ ta' inċident fuq in-naħa tiegħek.
- Tollera l-iskadenza ta' 5 minuti bejn `t=` u l-ħin tal-irċevuta lil hinn, irrifjuta biex jimblokka r-ripetizzjonijiet.
Biex tmur 'il quddiem
Lesti biex tgħaqqad is-sistemi tiegħek?
l-installazzjoni tal-webhook hija disponibbli mill-pjan Starter (b'xejn, 5 enveloppi/xahar).