Skip to main content

Webhook Subscriptions

Subscribe your system to tenant-wide events (calls, SMS, leads, campaigns) and AutoRev will POST signed JSON to your URL as they happen. No polling required.

Every webhook CRUD endpoint requires the admin scope. Delivery uses HMAC-SHA256 with 3 inline retries (1s, 5s, 25s backoff). After 20 consecutive failures a subscription is auto-disabled. Destination URLs must be HTTPS.

Signing secrets are shown exactly once

When you create a webhook, the response includes a signing_secret starting with whsec_. Store it immediately. No endpoint will ever return it again. If you lose it, delete the subscription and create a new one.

You need the secret to verify the HMAC-SHA256 signature on delivered events:

signature == sha256(signing_secret, timestamp + "." + body)

Compare with timingSafeEqual, never ==. See Signature Verification.

Choosing events: subscribe-all vs whitelist

Omit events (or pass an empty array) on create to subscribe to all events. Otherwise pass a whitelist of event names. Unknown event names are accepted (future-compatible); they just won't deliver until the emitter ships.

See Event Types for the full list of subscribable events and payloads.

Create a subscription

POST /api/v1/webhooks creates a webhook subscription. Scope: admin. Returns signing_secret once.

curl -X POST https://app.autorev.ai/api/v1/webhooks \
-H "Authorization: Bearer $AUTOREV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-system.com/autorev-events",
"events": ["call.completed", "sms.received", "lead.created"],
"description": "Acme HVAC production inbox"
}'
{
"id": "a1b2c3d4-...",
"url": "https://your-system.com/autorev-events",
"events": ["call.completed", "sms.received", "lead.created"],
"description": "Acme HVAC production inbox",
"is_active": true,
"signing_secret": "whsec_xxx...",
"created_at": "2026-04-22T14:00:00Z",
"_warning": "Store signing_secret now — it will not be shown again."
}

List subscriptions

GET /api/v1/webhooks lists subscriptions. Scope: admin. signing_secret is never returned.

curl https://app.autorev.ai/api/v1/webhooks \
-H "Authorization: Bearer $AUTOREV_API_KEY"

Get a subscription

GET /api/v1/webhooks/{id} returns subscription detail. Scope: admin.

curl https://app.autorev.ai/api/v1/webhooks/a1b2c3d4-... \
-H "Authorization: Bearer $AUTOREV_API_KEY"

Delete a subscription

DELETE /api/v1/webhooks/{id} hard-deletes the subscription. Scope: admin. This is also the signing_secret rotation path: delete the subscription and create a new one to get a fresh secret.

curl -X DELETE https://app.autorev.ai/api/v1/webhooks/a1b2c3d4-... \
-H "Authorization: Bearer $AUTOREV_API_KEY"

Test a subscription

POST /api/v1/webhooks/{id}/test fires a synthetic webhook.test event to the subscription URL using the real HMAC signing path. Scope: admin. Single attempt, no retry.

curl -X POST https://app.autorev.ai/api/v1/webhooks/a1b2c3d4-.../test \
-H "Authorization: Bearer $AUTOREV_API_KEY"
{
"subscription_id": "a1b2c3d4-...",
"event_id": "evt_abc...",
"delivered": true,
"status_code": 200,
"error": null,
"signature_header": "x-autorev-signature",
"timestamp_header": "x-autorev-timestamp",
"payload": { "id": "evt_abc...", "type": "webhook.test" }
}

Delivery and reliability

BehaviorDetail
SigningHMAC-SHA256 over timestamp + "." + rawBody, delivered in the x-autorev-signature header
Retries3 inline attempts with 1s, 5s, 25s backoff
Auto-disableAfter 20 consecutive failures the subscription is auto-disabled
TransportHTTPS destination URLs only
Test deliveriesSingle attempt, no retry

Legacy per-receptionist webhook_url

A receptionist's webhook_url (set via PATCH /api/v1/receptionists/:id) also receives per-receptionist event notifications, but its signing secret is not retrievable via the API. Signature verification is only practical with the Webhook Subscriptions API on this page, which returns a whsec_... secret once at creation. Use subscriptions for anything that needs signature verification; new integrations should use subscriptions. The event payloads are shared by both paths.