ウェブフック リアルタイムでサインアップイベントを受信
Certyneoのダッシュボードに HTTPS URL を設定して,HMAC-SHA256で署名された POST を受信します. 署名,拒否,有効期限のイベントが起きたら, 8 つのイベントがサポートされます. 6 回の試行後に指数値再試行, 8 行の暗号化検証.
< 5s
事件後の平均的な配達時間
5x
失敗した場合は試行 (~9h後まで)
HMAC-SHA256
要求の各項の署名アルゴリズム
事件カタログ
設定 → Webhooks で興味のあるイベントを有効に,他のイベントを無視します 登録はイベントごとに粒状です.
| 事件 | 発症 |
|---|---|
envelope.created | 作成時に CRM側で記録を同期するのに役立つエンベラップが作成されます. |
envelope.sent | 封筒は署名者に送られる (最初のメール送信). 署名サイクルが始まることを意味します. |
envelope.completed | 署名者全員署名しました. eIDASの PDFとトラウルの監査は,ペイロードの `proof_pdf_url`で入手できます. |
envelope.declined | 署名者が封筒を拒否した.拒否理由 (署名者が提供した場合は) は `data.decline_reason` にあります. |
envelope.voided | 封筒は発行者が署名が完了する前にキャンセルされました. `expired` (human vs timeout) とは異なります. |
envelope.expired | 封筒の有効期限は,完全な署名なしで過ぎました. 欠落した署名者のリストは, `data.missing_signers` にあります. |
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"
}
}payload は UTF-8 でエンコードされ,BOM は含まれていない. HMAC 署名は送信されたままのボディ・ブルートに計算される. 空間を改変しないでください. JSON 再解析はしばしばキー順序を変更し,検証を破ります.
HMACの署名を確認する
ウェブフークの秘密で署名されます (ダッシュボードで作成時に1回だけ表示され,その後休憩時に暗号化されます).署名は, `Certyneo-Signature`ヘッダーで, `t=形式で送信されます.<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)よくある間違い
期待された署名と受信された署名を比較するために, `===`または `==`を使用しないでください. タイムセーフ関数 (`crypto.timingSafeEqual` in Node, `hmac.compare_digest` in Python) を使用してください. そうでなければ,二つの署名間の比較時間の差が,徐々に秘密を患者攻撃者に明らかにします.
試行錯誤の方針
端末が HTTP 2xx (タイムアウト,5xx,接続拒否) 以外の返信をすると,指数的なバックオフで鳴り響く.合計で~9時間以内に 6回試みます. 6回終了すると,Webフックダッシュボードにイベントが `失敗`とマークされ,警告メールが送信されます.
| 試行錯誤 | 合計期限 | 時間が経った |
|---|---|---|
| #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 |
失敗したメールを手動で転送したい場合は Webhook のダッシュボードに 再配信 ボタンが表示されます. 失敗したメールが 返信後 7 日間利用できます.
試しに送るのに 本物の封筒を送らない
`/v1/webhooks/test`のエンドポイントは URLとイベントタイプを受け入れ,実際のものと同じサインの虚構のペイロードを POSTします.継続的な統合やローカル開発 (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の署名をチェックする 身体を読み取る前に タイムセーフの比較をします
- データベースに既に見たIDを保存して,それぞれの"envelope_id"を"回処理する (リトリープは同じイベントをリデリバーできる).
- HTTP 200に 5秒以内に返信し,その後アシンクロン処理 (キュー) します. そうでなければタイムアウトして再試行としてカウントされます.
- 粗質なボディログ + 完全なサインをデバッグする HMAC 検証はしばしばBOMや見えないホワイトスペースで失敗します
- 事件の"失敗"のデッドレターに 接続して 事件が起きたら 部下に手動で転送します
- `t=`と受信時間の間の 5分間の遅延を許し,再放送を阻止するために拒否します.
更に進めるために
システム接続準備はいいか?
ウェブフックの設定はスタートアッププランから利用できます (無料,5封筒/月)