Skip to content

Settings — Webhooks

The Settings ▸ Webhooks page is the admin surface for registering real-time HTTP callbacks. Each webhook is an HTTPS URL plus a list of typed events; when a matching event fires in your tenant, the platform POSTs a signed JSON payload to your endpoint.

This is the primary integration mechanism for hooking Athenty into your own systems — Slack notifications, internal CRMs, regulator reporting pipelines, ETL jobs.

Settings Webhooks — Acme Financial Group demo tenant

Standard PageHeader with the title Webhooks and a one-line description. The Add Webhook button sits to the right.

Each row carries:

  • The endpoint URL (with a copy-button)
  • A badge group of subscribed events
  • Active toggle
  • Last delivery timestamp + status pill
  • Row actions (Test, Edit, Rotate secret, Delete)

Clicking the chevron expands the row to show the per-webhook delivery history with status codes and response bodies.

The slide-out captures URL, description, and an event multi-select. Save creates the webhook server-side, generates a signing secret (shown once), and dispatches a one-time test ping.

The same typed event names used by Settings ▸ Audit Log are available as subscription keys here. Common subscriptions:

EventTriggered by
request.createdNew verification opened
request.approved / request.rejectedReviewer decision
request.expiredAuto-expiry
envelope.completedEvery recipient signed
envelope.declinedA signer refused
matter.created / matter.updatedMatter lifecycle
client.createdNew client added
user.invited / user.deactivatedTeam change

The full list lives in packages/api/src/webhooks/events.ts.

Every payload is a JSON document with this shape:

{
"id": "01jdc233-4dae-7776-...",
"type": "request.approved",
"created_at": "2026-05-07T20:15:00Z",
"tenant_id": "01jdc234-...",
"data": { /* event-specific payload */ },
"metadata": {
"test": false,
"delivery_attempt": 1
}
}

metadata.test is true for synthetic test deliveries; false otherwise. delivery_attempt is 1-indexed and increments on each retry.

Every POST carries an HMAC-SHA-256 signature in X-Athenty-Signature, computed over the raw request body using your registered secret:

import crypto from 'crypto'
const sig = req.headers['x-athenty-signature']
const expected = crypto
.createHmac('sha256', SECRET)
.update(req.rawBody)
.digest('hex')
if (sig !== expected) throw new Error('invalid signature')

Always verify against the raw body; many frameworks parse JSON before your handler sees it, which mutates whitespace and breaks the signature.

  • Initial POST: 5-second timeout
  • Failure retries with exponential backoff: 1m, 5m, 15m, 1h, 6h, 24h
  • 6 attempts total; after that the webhook stays active but flags as failed on the row
  • All retries are visible in the per-webhook delivery history

A delivery is considered successful when the endpoint returns any 2xx status code. 3xx, 4xx, and 5xx all count as failure.

The Test action POSTs a synthetic payload with metadata.test = true. The synthetic event has the schema of a real event but doesn’t reflect any actual record state — useful for verifying your handler in production without polluting downstream systems.

Click Rotate signing secret on the row’s More menu. The platform:

  1. Generates a new secret (shown once)
  2. Sends both old and new signatures on the next 24 hours of deliveries (graceful overlap)
  3. After 24 hours, only the new secret is used

This lets you update your verifier without dropping events.

RoleViewManage
Owner / Admin
Member
Viewer

Webhooks are tenant-scoped — your endpoint only receives events from your own tenant.

ActionEvent
Createwebhook.created
Editwebhook.updated
Rotate secretwebhook.secret_rotated
Deletewebhook.deleted
Disable / enablewebhook.toggled

All events surface in Settings ▸ Audit Log.

SymptomMost likely causeFix
Test delivery failsEndpoint not reachableVerify DNS + TLS; check egress IP allowlist
Signature mismatchVerifying parsed JSON, not raw bodyUse the raw body for HMAC
Missing some eventsNot subscribedEdit and add the event
Failed deliveries pile upEndpoint 5xx persistentlyFix endpoint; pause the webhook to stop retries
Lost signing secretOne-time-shown onlyRotate to get a new secret + update verifier