Webhook sinadura-ekitaldiak jaso denbora errealean
Konfiguratzen baduzu HTTPS helbide bat Certyneo panelean, jasoko duzu HMAC-SHA256 sinatua den POST bat zure gutun-azalera zerbait iristen denean: sinadura, uko, iraungitzea. 8 gertaera onartzen dira, 6 saiakeran berraztertzen da, 8 lerroeko kodea.
< 5s
Eragiketa-denbora ertaineko epea, gertaeraren ondoren
5x
Saiakera huts egin badugu (9 ordu arte)
HMAC-SHA256
Eskari bakoitzaren sinadura algoritmoa
Gertakarien katalogoa
Ondorengo 8 ekitaldiek Certyneo gutun-azal baten bizitza ziklo osoa hartzen dute.
| Gertaera | -Hori da. |
|---|---|
envelope.created | Gutun-azal bat sortzen da (UI, API edo txantiloiaren bidez) CRM aldeko erregistro bat sinkronizatzeko erabilgarria sortzean. |
envelope.sent | Gutun-azal hau sinatzaileei bidaltzen zaie (egiten den lehen e-mail-a). |
envelope.completed | Sinatzaile guztiek sinatu dute. eIDAS PDF zigilatua eta bidezko auditoria erabilgarri daude |
envelope.declined | Sinatzaile batek uko egin dio gutun-azal honi. Uko egiteko arrazoia (sinatzaileak ematen badu) `data.decline_reason`-n dago. |
envelope.voided | Gutun-azal hau ezabatu egin du emititzaileak sinatu aurretik. |
envelope.expired | Gutun-azal honen iraungitze-data pasa da sinatu gabe. |
recipient.signed | Sinatzaile batek sinatu du (baina ez guztiek). |
recipient.viewed | Sinatzaile batek sinatu gabe ireki du lotura, eta baliagarria da merkataritza berpizteko. |
Karga-formazioa.
Gertaera guztiek JSONren goi mailako patroia partekatzen dute: `event`, `envelope_id`, `occurred_at`, `data`.
{
"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"
}
}HMAC sinadura gorputz gordinaren gainean kalkulatzen da bidalitako moduan.
HMAC sinadura egiaztatu.
Eskari bakoitza webhook sekretuarekin sinatzen da (sartzean behin bakarrik ikus daiteke, eta gero deskantsatuz enkriptatua).<timestamp>V1=<hex_hmac>Beti egiaztatu sinadura karga prozesatu aurretik. Pauso hau gabe, edonork forjatu dezake gertaera bat eta deitu zure azken puntura.
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)Ohizko akats bat
Ez erabili `===` edo `==` sinadura espero eta jasotakoa alderatzeko. Erabili denbora-segurtasun funtzioa (`crypto.timingSafeEqual` Node-n, `hmac.compare_digest` Python-en). Bestela, bi sinaduren arteko konparazioaren denbora-desberdintasunak sekretuak paziente erasotzaile bati pixkanaka-pixkanaka agerian uzten dizkio (timing attack).
Berriz saiatzeko politika
Zure helburuak HTTP 2xx (timeout, 5xx, connection refused) baino erantzun gehiago ematen badu, erantzuna erantzuna izango da: "Eskalatzaileen segurtasun-segurtasun-sistema".
| Saiakera bat. | Denbora-tarte bat | Denbora igaro da. |
|---|---|---|
| #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 |
Porrot egindako ekitaldi bat eskuz bidali nahi baduzu, webhook-eko panelak botoi bat eskaintzen du porrot egindako entrega bakoitzeko, porrotaren ondoren 7 egunetan zehar erabilgarri.
Egiazko gutun-azal bat bidali gabe probatzea.
Webhooks-ek urrutiko helbide bat eta gertaera mota bat onartzen ditu, eta benetakoaren antzera sinatutako karga fikziozko bat POSTatzen du.
# 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 ohitura jarraitu behar dira
- HMAC sinadura egiaztatu gorputzaren irakurketa baino lehen.
- Prozesatu behin bakarrik IDak gordez. Berriz ere ekitaldi bera egin daiteke.
- HTTP 200 erantzun 5 segundotan, eta gero prozesatu asinkronikoki. Bestela, denbora-galera izango duzu eta berriro saiatze gisa kontatuko da.
- Gorputz gordina erregistratu + sinadura osoa debugatu HMAC egiaztapenak askotan huts egiten du BOM edo espazio zuri ikusezin batean.
- "Hondatu" gertaeren atzealdeko "dead-letter" bat konektatu eta eskuz bidali zure zerbitzukoek gertakariak jasotzeko.
- 5 minutuko atzerapena onartu `t=` eta harreraren artean, eta atzera bota, berriro ikustea eragozteko.
Aurrera egin behar dugu.
Prest zuen sistemak konektatzeko?
Sortzeko kontua dohainik 2 minutuan webhook konfigurazioa Starter planarekin dago eskuragarri (dohainik, 5 gutun-azal/hilean).