ESign Docs

Webhooks

Receive signed event notifications, verify their signatures, and handle retries.

Webhooks notify your systems when signing events happen, so you don't have to poll the API. Register an endpoint and ESign will POST a JSON event to it. Manage endpoints via the /webhooks API.

Events

EventWhen
document.sentA document was sent for signature.
document.openedA recipient opened the signing page.
recipient.completedA recipient finished signing their fields.
recipient.declinedA recipient declined to sign.
document.completedAll signers are done; the sealed PDF is ready.
document.voidedThe document was voided (e.g. a decline or expiry).

Payload

Payloads carry IDs and summary fields only — never file bytes. Fetch protected content via the API using the IDs.

{
  "id": "evt_019...",
  "type": "document.completed",
  "createdAt": "2026-06-17T01:23:45.000Z",
  "data": {
    "documentId": "019...",
    "title": "NDA",
    "sealedFileHash": "…",
    "status": "completed"
  }
}

Verifying signatures

Each delivery is signed with your endpoint's secret in an X-Esign-Signature header:

X-Esign-Signature: t=1718590000,v1=<hex HMAC-SHA256>

v1 is HMAC-SHA256(secret, "<t>.<raw request body>"). To verify, recompute it from the raw body and the timestamp, then compare in constant time:

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

function verify(rawBody: string, header: string, secret: string): boolean {
  const m = /t=(\d+),v1=([a-f0-9]+)/.exec(header);
  if (!m) return false;
  const expected = createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');
  return timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}

Delivery & retries

  • Respond with 2xx quickly to acknowledge receipt; do heavy work asynchronously.
  • Failed deliveries are retried with staged backoff: 1m → 5m → 30m → 2h → 8h.
  • After 20 consecutive failures the endpoint is automatically disabled.
  • Events may be delivered more than once — use the event id to deduplicate.

On this page