VerifycateDeveloper Docs

Webhooks

Receive, verify, and reliably process workspace events

Webhooks notify your application when something changes in Verifycate. Instead of repeatedly polling the API, your server receives an HTTPS request shortly after a certificate, recipient, request, correction, or engagement event.

Use webhooks to update an internal learner record, trigger a downstream workflow, build an audit trail, or measure recipient engagement. Webhooks require an active Pro seat.

How it works

  1. Configure one or more HTTPS endpoints in Settings → Webhooks or with Create a webhook.
  2. Choose individual event types, or subscribe to * to receive every event.
  3. Verify the signature of every request before parsing or acting on it.
  4. Process the event idempotently and return any HTTP 2xx status promptly.
  5. Use List deliveries to investigate retries and failures.

Verifycate sends requests with these headers:

HeaderValue
Content-Typeapplication/json
User-AgentVerifycate-Webhook/1.0
X-Verifycate-SignatureHex-encoded HMAC-SHA256 signature

Payload

Every delivery is a JSON POST:

{
  "id": "7c8e0b2a-3d1f-4c55-9a11-2f6b8d4e1c90",
  "event_type": "certificate.issued",
  "occurred_at": "2026-09-03T12:00:00Z",
  "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
  "certificate_id": "8ac68e9d-4aca-43ca-88f0-f2220f849626",
  "issue_id": "1069340d-5b74-4670-a319-41b8fe3a0e5d",
  "data": {
    "recipient_email": "[email protected]"
  }
}
FieldMeaning
idStable event identifier; use it as an idempotency key
event_typeThe event that occurred
occurred_atWhen the event was recorded, as an RFC 3339 timestamp
workspace_idWorkspace that owns the event
certificate_idRelated certificate when the event has one
issue_idRelated certificate issue when the event has one
dataEvent-specific data; it may be an empty object

Do not assume deliveries arrive in order. A retry for an older event can arrive after a newer event.

Verify the signature

Each endpoint has a secret returned when it is created. Store the secret in a secret manager; do not commit it or expose it to browser code.

Calculate HMAC-SHA256 over the exact raw request bytes using the endpoint secret, hex-encode the digest, and compare it with X-Verifycate-Signature using a constant-time comparison. Verify the signature before decoding JSON—the parsed and re-serialized body may not have the same bytes.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyVerifycateWebhook(rawBody, receivedSignature, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const expectedBytes = Buffer.from(expected, "hex");
  const receivedBytes = Buffer.from(receivedSignature ?? "", "hex");

  return (
    expectedBytes.length === receivedBytes.length && timingSafeEqual(expectedBytes, receivedBytes)
  );
}

Reject missing or invalid signatures with an HTTP 400 or 401 response.

Acknowledge deliveries

Return a 2xx response only after your application has durably accepted the event. If processing is slow, write the verified event to your own queue and respond immediately; the delivery request has a 10-second timeout.

Redirects and non-2xx responses are treated as failures. Verifycate stores at most the first 2 KB of a failure response for troubleshooting.

Retries

Failed deliveries are retried with this backoff schedule:

RetryDelay after failure
130 seconds
22 minutes
315 minutes
41 hour
54 hours
612 hours
724 hours

After the initial attempt and seven unsuccessful retries, the delivery is marked as permanently failed. Network errors, timeouts, and every non-2xx status follow the same retry policy.

Because a response can be lost after your server processes an event, the same event may be delivered more than once. Put a unique constraint on the payload id, or record processed IDs before applying side effects.

Event types

Certificate lifecycle

recipient.enrolled, certificate.issued, certificate.bulk_sent, certificate.reissued, certificate.amended, certificate.deleted, certificate.created, certificate.updated, certificate.archived, template.published

Requests and corrections

request.submitted, request.approved, request.rejected, request.reopened, correction.submitted, correction.approved, correction.rejected

Recipient engagement

email.opened, email.clicked, certificate.opened_from_email, certificate.downloaded, share.linkedin_add, share.linkedin, share.x, share.facebook, share.whatsapp, share.telegram, share.email, share.link_copied, certificate.verified

Forms

form_invite.sent, request_form.opened, request_form.submitted

Subscribe only to the events your application handles. Use * when forwarding events to a general-purpose queue or data warehouse.

Operational checklist

  • Serve the endpoint over HTTPS and keep it reachable from the public internet.
  • Verify signatures against the raw body before parsing JSON.
  • Deduplicate by event id and make handlers safe to retry.
  • Return 2xx quickly; move slow work to a queue.
  • Log the event ID and type, but avoid logging unnecessary recipient data.
  • Monitor delivery history for permanent failures.
  • Update subscriptions with Update a webhook when your application starts or stops handling an event.

Webhook operations