Preskočite na glavni sadržaj
Certyneo
Документација за програмера

Вебхукови примајте догађаје потписивања у реалном времену

Поставите HTTPS URL у вашу Цертинео контролну таблу и добијте HMAC-SHA256 потписан ПОСТ чим се догађај деси на вашим пољетима: потпис, одбијање, истечење. 8 подржаних догађаја, експоненцијални ретреј на 6 покушаја, криптографска верификација у 8 линија кода.

< 5s

Просечно време испоруке након догађаја

5x

Покушаји у случају неуспеха (до ~ 9h касније)

HMAC-SHA256

Алгоритам за потписивање сваког захтева

Каталог догађаја

Осам догађаја испод покривају читав животни циклус Цертинео кутије.

ПодзелаПојава
envelope.createdОбухват се ствара (по УИ, АПИ или шаблону) користан за синхронизацију CRM-овог снимања од самог стварања.
envelope.sentПоручена је поља потписаоцима (прва послана е-пошта).
envelope.completedСви потписаници су потписали. eIDAS затворен PDF и аудит траг су доступни преко `proof_pdf_url` у пјлододу.
envelope.declinedПричина за одбијање (ако је поднео потписац) је у `data.decline_reason`.
envelope.voidedПорука је поништена од стране издавача пре него што је потписано.
envelope.expiredДатум истека на пошту је прошао без потпуног потписа.
recipient.signedУпотребљив за секвенцијалне радне флове: покретање преласка на следећег потписа.
recipient.viewedЈедан од потписалаца је отворио линк за потписивање без још једног потписа, што је корисно за циљане трговинске понове.

Формат корисне оптерећења

Сви догађаји деле исти JSON шема на врху нивоа: `event`, `envelope_id`, `occurred_at`, `data`. Садржај `data` варира по догађају (поља документована по догађају у 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"
  }
}

Пајлоад је енкодиран у УТФ-8, без БОМ-а.

Проверите HMAC потпис

Сваки захтев је потписан са вашом вебхукочком тајном (видивим само једном када се креира у контролној табли, а затим шифровано на одмор).<timestamp>,в1=<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)

Честог грешка

Не користите `===` или `==` за поређење очекиваног и прихваћеног потписа. Користите функцију "тименг-сеф" (`крипто.тименг-сефЕквал` у Node-у, `hmac.compare_digest` у Python-у). Иначе, временски разлика у поређењу између два потписа постепено открива тајну пацијенту нападачу (тименг атак).

Политике ретрија

Ако ваша крајња тачка одговори на нешто друго него HTTP 2xx (тимеаут, 5xx, connection refused), ми се померимо по експоненцијалном бакофу. Укупно 6 покушаја за ~9 сати. Након 6 покушаја, догађај се означује као `фајлиран` у вашој вебхук табли и шаље се упозорење путем е-поште.

ПокушајСкупни рокПрошло време
#100
#2+ 1 min1 min
#3+ 5 min6 min
#4+ 30 min36 min
#5+ 2 h2h 36
#6+ 6 h8h 36

Ако желите да ручно пренесете неуспешну испоруку, вебхук-наводњач нуди дугме Re-deliver на свако неуспело испоруку доступно 7 дана након коначног неуспеха.

Пробајте без слања стварне пощенке

Идеално за валидацију вашег хендлера у континуираној интеграцији или током локалног развоја (са 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 или невидљивом белом простору.
  • Покључите Dead-letter на `failed` догађаје да бисте ручно ретранслирали у случају инцидента на страни ваше службе.
  • Толерисати 5 минута кашњења између `t=` и времена пријем и даље, одбацити да би се блокирали репелије.

Да бисте и даље

Спреман да повежем ваше системе?

Створите бесплатни рачун за 2 минута вебхук је доступан на Стартер плану (безплатно, 5 поља/месец).