EaserixDocs
Developers

Webhooks

Signed outbound webhooks from Links and Sign, and email delivery for Forms submissions.

View as Markdown
How Easerix webhooks work

Links and Sign can POST JSON to your HTTPS endpoint when events happen — link clicks and conversions, document signatures and completions. Every delivery is signed with HMAC-SHA256 in an X-Easerix-Signature header so you can verify it came from Easerix. Forms delivers submissions to email destinations today.

Registering a webhook

Links and Sign share the same registration API:

curl -s https://api.easerix.com/links/v1/webhooks \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/easerix", "events": ["link.created", "link.clicked"]}'

The response includes the webhook and a signing secret (whsec_...) — shown once, so store it immediately. The URL must be HTTPS. Manage webhooks with GET /v1/webhooks, PATCH /v1/webhooks/:id (change url, events, or active), and DELETE /v1/webhooks/:id.

LinksSign
Base URLhttps://api.easerix.com/linkshttps://api.easerix.com/sign
Default eventslink.created, link.updated, link.deleted* (all events)
Wildcard * subscriptionNoYes
Test deliveryPOST /v1/webhooks/:id/test sends a pingNot available
Webhooks per accountUnlimited10

Verifying signatures

Every delivery carries these headers:

HeaderValue
X-Easerix-EventThe event name, e.g. link.clicked
X-Easerix-Signaturesha256=<hex HMAC-SHA256 of the raw request body>
X-Easerix-DeliveryUnique delivery ID, stable across retries (Links only)

Compute the HMAC of the raw request body with your whsec_... secret and compare:

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

function verify(rawBody, header, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

Reject anything that doesn't verify. On Links, use X-Easerix-Delivery to deduplicate retried deliveries.

The payload envelope is always:

{ "event": "link.clicked", "at": "2026-08-09T17:30:00Z", "data": { ... } }
Eventdata contains
link.created / link.updated / link.deleted{id, shortCode, destinationUrl, title, active, archived}
link.clicked{link: {id, shortCode}, clicks, totalClicks}
link.converted{link: {id, shortCode}, conversion: {id, name, amountCents, currency}, clickId, clickedAt, convertedAt}

link.clicked is aggregated: rapid clicks on the same link are batched into one event with a clicks count, so don't assume one event per click — totalClicks is the link's running total.

Sign events

Sign payloads are flat (no data wrapper):

{
  "event": "document.signed",
  "documentId": "doc_...",
  "document": { "id": "doc_...", "name": "MSA — Acme", "status": "in_progress" },
  "occurredAt": "2026-08-09T17:30:00Z",
  "recipient": { "id": "...", "name": "...", "email": "...", "role": "signer", "status": "signed" }
}
EventFires when
document.sentA document is sent for signature
document.viewedA recipient opens the document
document.signedA recipient signs
document.declinedA recipient declines
document.completedEveryone has signed
document.voidedThe sender voids the document
document.expiredThe document passes its expiry

recipient is present only on the recipient-scoped events (viewed, signed, declined).

Delivery and retries

Both tools deliver with a 10-second timeout and treat any 2xx as success. A failed delivery is retried twice (Links waits ~1s then ~5s; Sign waits 5s then 20s). After 20 consecutive failures a webhook is automatically disabled — re-enable it with PATCH /v1/webhooks/:id {"active": true}, which also resets the failure count. Respond quickly (queue the work, return 200 immediately) to stay under the timeout.

Forms: email destinations

Forms doesn't send outbound webhooks yet — email is the delivery channel. Each form has destinations managed at https://f.easerix.com/v1/forms/:id/destinations; an email destination with config {"to": ["[email protected]"]} receives a branded notification for every non-spam submission, with Reply-To set to the submitter when their email is detected. Forms can also send an autoresponder to the submitter if you enable it on the form.

To get form submissions into your own systems today, poll GET /v1/forms/:id/submissions on the Forms API.

Frequently asked questions

Are deliveries replayed in order?

No ordering guarantee — treat each event independently and use the payload's timestamp (at / occurredAt) rather than arrival order.

My endpoint was down — did I lose events?

Each delivery is retried twice, then dropped. After 20 consecutive failures the webhook is disabled entirely, so re-enable it and reconcile via the REST API after an outage.

Can I rotate the signing secret?

Delete the webhook and create a new one — a fresh secret is generated and returned once on creation.

Last updated on

On this page