API & Security
CertSeal Webhooks
Get notified in real time when certificates are issued, sent, fail to send, or are viewed. Deliveries are signed and retried.
Last updated: June 18, 2026
Webhooks push certificate events to your endpoint as they happen, so you can update systems, notify your team, or trigger downstream automation without polling. Subscriptions are managed through the REST API, and the same events power our Zapier and Make.com apps.
Events
| Event | Fires when |
|---|---|
certificate.issued | A recipient is created (API, bulk, or CSV import). |
certificate.sent | A certificate email is successfully sent. |
certificate.failed | A certificate email fails to send (payload includes an error). |
certificate.viewed | A recipient opens their certificate for the first time (payload includes viewer details). |
Creating a subscription
Register an endpoint and the events you want with the REST API:
curl -X POST \
https://services.certseal.com/api/v1/webhooks/subscriptions \
-H "Authorization: Bearer $CERTSEAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/certseal",
"events": ["certificate.issued", "certificate.sent"]
}'
The response includes a signing secret (prefixed wh_sec_) shown once — store it to verify deliveries. Your endpoint URL must be HTTPS in production. A workspace can have up to 20 subscriptions.
To send yourself a sample delivery, call POST /webhooks/subscriptions/{id}/test. You can rotate the secret with POST /webhooks/subscriptions/{id}/rotate-secret.
Delivery format
CertSeal sends an HTTP POST with a JSON envelope:
{
"id": "whe_AbC123...",
"type": "certificate.issued",
"createdAt": "2026-05-01T00:00:00.000Z",
"data": {
"id": "rec_...",
"batchId": "batch_...",
"name": "Ada Lovelace",
"email": "ada@example.com",
"certificateId": "CERT-2026-003843-000001",
"shareToken": "…",
"certUrl": "https://services.certseal.com/v/…",
"issueDate": "2026-05-01T00:00:00.000Z",
"expiryDate": null,
"data": { "score": "94%" },
"emailStatus": "sent",
"emailSentAt": "2026-05-01T00:01:00.000Z",
"createdAt": "2026-05-01T00:00:00.000Z"
}
}
For certificate.failed, data also includes an error string. For certificate.viewed, data also includes a viewer object (viewedAt, userAgent, referer, ip).
Every delivery includes these headers:
| Header | Value |
|---|---|
X-CertSeal-Event | The event type, e.g. certificate.issued. |
X-CertSeal-Delivery | A unique delivery ID — use it as an idempotency key. |
X-CertSeal-Signature | t=<unix>,v1=<hmac> — see below. |
X-CertSeal-Timestamp | Unix seconds, matching t in the signature. |
User-Agent | CertSeal-Webhook/1 |
Verifying signatures
Each request is signed with HMAC-SHA256 using your subscription’s signing secret. The X-CertSeal-Signature header has the form t=<timestamp>,v1=<hex>, where the HMAC is computed over the string `${t}.${rawRequestBody}`.
To verify: recompute the HMAC with your secret and compare it to v1 using a constant-time comparison, and reject requests where the timestamp is more than ~5 minutes from now (to prevent replay).
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (Math.abs(Date.now() / 1000 - t) > 300) return false; // replay window
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
Verify against the raw request body, before any JSON parsing reformats it.
Retries and delivery
- Deliveries are at-least-once — the same delivery may arrive more than once. Deduplicate on
X-CertSeal-Delivery. - A delivery succeeds on any
2xxresponse. Non-2xx responses and timeouts are retried with increasing backoff (1m → 5m → 30m → 2h → 12h → 24h) for up to 7 attempts before the delivery is marked failed. - Respond quickly (within ~10 seconds) — do heavy work asynchronously after acknowledging.
- Return
410 Goneto have CertSeal unsubscribe the endpoint automatically.
Support
Questions about webhooks? Email support@certseal.com — we typically reply within 1 business day (Monday–Friday, 9:00 AM–6:00 PM SGT). See the support guide for all contact options.