發明者資料
網路連結即時收到簽名活動
請在Certyneo儀表盤上設定HTTPS網址, 當您的封面發生事件時, 收到HMAC-SHA256簽名的POST:簽名,拒絕,到期.
< 5s
傳送時間在事件發生後的平均時間
5x
試圖失敗 (直到9小時後)
HMAC-SHA256
每個請求的簽名算法
活動目錄
請在設定 → Webhooks 啟動您關心的事件, 忽略其他事件,
| 活動 | 發動活動 |
|---|---|
envelope.created | 使用於創建時同步CRM端的記錄. |
envelope.sent | 封面會被送往簽名者 (首封電子郵件). |
envelope.completed | 已簽署所有簽名. eIDAS封鎖的PDF及監控跟蹤資料可透過 payload中的 `proof_pdf_url`. |
envelope.declined | 簽名人拒絕收封.拒絕理由 (如果是簽名人提供) 在 `data.decline_reason`. |
envelope.voided | 封面已被發行人取消, 在完全簽名之前. |
envelope.expired | 封面的到期日期沒有完全簽名. 缺席簽名人的名單請參閱: |
recipient.signed | 幫助連續工作流程:引發轉移到下一個簽名者. |
recipient.viewed | 沒有簽名, 很有用在有目標的商業活動中. |
運輸量為
關於事件的內容因事件而異 (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"
}
}該代碼是UTF-8編碼,沒有BOM. HMAC簽名是計算在原始體內,
檢查HMAC的簽名
您的網連接密碼是您的網連接密碼,<timestamp>沒有任何其他選擇.<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中的`crypto.timingSafeEqual`,Python中的`hmac.compare_digest`).否則,兩種簽名的比較時間差距會逐漸向耐心的攻擊者揭露秘密 (timing attack).
試用政策
接下來我們會在網路連接的時間結束時, 透過指數式的後備. 在 ~9小時內,
| 試圖 | 總結時間 | 已過來的時間 |
|---|---|---|
| #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 |
網上連線儀器板上提供重新送貨按,
試用沒有送真實封筒
終點 `/v1/webhooks/test` 接受 URL 和事件類型,並 POSTe 虛擬的有效負載,
# 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"}'六個必須遵守的做法
- 檢查HMAC簽名在任何讀取機身之前.
- 處理每個"封面"id` × "事件"一次,
- 請在最長的5秒內回覆HTTP 200,然後進行並不同步處理 (排隊).
- HMAC檢查通常會失敗在BOM或隱形空白中.
- 請將事件列為"失敗"的死亡字母,
- 接受播出時間以后的5分鐘,
沒有任何證據顯示,
準備好連接各位系統嗎?
網路連線設定可從初始計劃 (免費,每月5封包) 開始使用.