Gareth Wilson Gareth Wilson

Guide to Aircall Webhooks: Features and Best Practices

Published


Aircall webhooks notify your systems about cloud call-center activity: a call rings, an agent answers, a voicemail lands, a transcript is ready. If you're building on Aircall's business phone platform, webhooks are how you drive screen-pops, CRM sync, and call analytics without polling.

This guide covers how Aircall webhooks work, the token-in-body verification model, the envelope and event catalog, the delivery semantics that shape your handler, and the best practices for production.

What are Aircall webhooks?

Aircall delivers webhooks as HTTPS POSTs to an endpoint you register via the API or dashboard. The distinctive part is verification: Aircall has no signature header and no cryptographic signature. Every event body carries a top-level token string equal to the token issued when the webhook was created, and you verify by comparing that field against your stored token.

Aircall webhook features

FeatureDetails
ConfigurationPOST /v1/webhooks or the dashboard; omitting the events array subscribes to all events; max 100 webhooks per company
VerificationTop-level token field in the JSON body, compared to the token issued at creation; no signature header
EnvelopeFive fields: resource, event, timestamp, token, data
Events67 across calls, users, numbers, contacts, messaging, conversation intelligence, AI voice agent, and analytics
Timeout5 seconds; a slow response counts as a failure
RetriesUp to 50 per event, then the webhook is auto-disabled; failed events retry for up to 12 hours, and a success re-enables it
DeliveryAt-least-once, with no ordering guarantee
TransportHTTPS with a valid certificate required; no source IP allowlist
SDKNone

Common events

Aircall event names are the event field values. The catalog spans 67 events; the ones most integrations start with:

EventFires when
call.createdAn inbound call hits a number, or an agent starts an outbound call
call.answeredAn agent answers
call.hungupEither party hangs up
call.endedThe call fully ends and its assets are finalized
call.tagged / call.untaggedA tag is added or removed
call.voicemail_leftA caller leaves a voicemail
message.receivedAn inbound SMS, MMS, or WhatsApp message arrives
contact.created / contact.updatedA contact changes
user.connected.v2 / user.disconnected.v2An agent opens or closes their workspace
number.opened / number.closedA number enters or leaves business hours
transcription.created / summary.createdAI artifacts are ready (AI Assist add-on)

Branch on the event field. Two catalog details worth knowing: use the User V2 events (user.created.v2 and friends), since Aircall's docs mark V1 for deprecation; and user.closed.v2 fires twice when substatus is enabled, first with the availability status and then with the substatus, which is intended behavior rather than a duplicate.

See Aircall webhook payloads in action. Inspect and replay sample Aircall webhook payloads in the Hookdeck Console — no account or setup required.

Setting up Aircall webhooks

Create a webhook via the API (Basic Auth with api_id:api_token, or an OAuth2 Bearer token; both are API credentials, a different secret from the webhook token):

curl -X POST https://api.aircall.io/v1/webhooks \
  -u "$AIRCALL_API_ID:$AIRCALL_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "custom_name": "CRM sync",
    "url": "https://example.com/webhooks/aircall",
    "events": ["call.created", "call.ended", "contact.updated"]
  }'

The response includes webhook.token; store it, since it's what you'll verify against. Two subscription pitfalls: omitting events subscribes you to all 67 events, and on PUT, omitting events also resets the subscription to all unless you pass events_action=add|remove. Dashboard-created webhooks don't surface the token in the UI, so retrieve it with GET /v1/webhooks/{webhook_id}.

The endpoint must be HTTPS with a valid certificate. For local development, the Hookdeck CLI (hookdeck listen 3000 aircall --path /webhooks/aircall) provides the HTTPS URL plus an inspector for replaying deliveries.

Securing Aircall webhooks

Every delivery has exactly five top-level fields:

{
  "resource": "call",
  "event": "call.ended",
  "timestamp": 1755001020,
  "token": "45XXYYZZa08",
  "data": { "id": 456, "...": "..." }
}

Verify the token field with a timing-safe comparison. Because the secret is in the body rather than a signature over it, you don't need the raw request body; parsing JSON before verifying is safe here.

const crypto = require("crypto");

function verifyAircallToken(payloadToken, expectedToken) {
  if (typeof payloadToken !== "string" || !expectedToken) return false;
  try {
    return crypto.timingSafeEqual(
      Buffer.from(payloadToken),
      Buffer.from(expectedToken)
    );
  } catch {
    return false; // different lengths
  }
}

app.post("/webhooks/aircall", express.json(), (req, res) => {
  const { resource, event, token, data } = req.body;
  if (!verifyAircallToken(token, process.env.AIRCALL_WEBHOOK_TOKEN)) {
    return res.sendStatus(401);
  }

  // Respond within 5 seconds; process asynchronously
  processQueue.add({ resource, event, id: data?.id, data });
  res.sendStatus(200);
});

Don't use the timestamp field as a replay or staleness control. It's unsigned metadata with no replay protection behind it, so a tolerance check only causes false rejections. The token travels in cleartext in every payload, which is why HTTPS is mandatory.

Make Aircall webhooks production-ready. Hookdeck Event Gateway verifies the body token upstream, deduplicates, and durably queues every event.

Aircall webhook limitations and pain points

A shared token instead of a signature

The Problem: The token field authenticates the sender but signs nothing, so there's no payload-integrity guarantee and no replay protection, and the secret itself is present in every delivery.

Why It Happens: Aircall chose a shared-secret model over payload signing; TLS carries the integrity burden.

Workarounds:

  • Compare the token timing-safely, rotate it by recreating the webhook if it leaks, and don't log request bodies with the token in them.

How Hookdeck Can Help: Hookdeck's Aircall source takes the webhook token as its one verification field and checks it at the edge, so unverified traffic never reaches your handler.

A 5-second timeout that can disable your webhook

The Problem: A response slower than 5 seconds is a failure, 50 failed retries disable the webhook entirely, and after that you receive nothing until it's re-enabled.

Why It Happens: Aircall protects its delivery infrastructure from slow endpoints, and auto-disable is the backstop. Failed events retry for up to 12 hours, and one success in that window re-enables the webhook automatically.

Workarounds:

  • Acknowledge immediately and process asynchronously, monitor for the dashboard's deactivation notification, and keep handler work off the response path.

How Hookdeck Can Help: Hookdeck acknowledges Aircall in milliseconds and retries delivery to your handler on its own schedule, so a slow or crashed consumer never burns Aircall's 50-attempt budget or triggers auto-disable.

At-least-once, unordered delivery

The Problem: The same event can arrive twice, and events for one call can arrive out of sequence, so a handler that inserts on call.created and updates on call.ended breaks when they arrive reversed.

Why It Happens: Aircall documents delivery as at least once with no ordering guarantee, and many events fire for a single call.

Workarounds:

  • Upsert on data.id (Aircall's own recommendation) rather than assuming a lifecycle order, and make side effects idempotent.

How Hookdeck Can Help: Deduplication rules drop repeats at the edge. See our guide to webhook idempotency.

Subscription and token management pitfalls

The Problem: Omitting events on create or update silently subscribes you to all 67 events, the dashboard never shows a webhook's token, and messaging events only arrive in native mode (numbers in Proxy mode deliver to a separately configured callback URL).

Why It Happens: The API treats an absent events array as "everything", and the token is API-retrievable only.

Workarounds:

  • Always pass an explicit events array (or events_action on updates), and fetch tokens via GET /v1/webhooks/{webhook_id}.

How Hookdeck Can Help: Filters let you subscribe broadly but deliver narrowly, routing only the events each handler cares about, and the dashboard shows exactly which event types are actually arriving.

Best practices

Verify the body token on every request

Timing-safe comparison against the stored webhook token, 401 on mismatch. Skip the raw-body plumbing; it isn't needed here.

Respond fast, process asynchronously

You have 5 seconds, and slow responses count against the 50-attempt disable budget. Acknowledge, then queue. See why to process webhooks asynchronously.

Upsert on data.id

Many events fire per call and arrive in no guaranteed order. Key call records on data.id and upsert.

Subscribe explicitly

Pass an events array on create and events_action on update, or you'll receive all 67 event types.

Prefer User V2 events

The un-suffixed user events are deprecated; use the .v2 names.

Watch for deactivation

Auto-disable means silence, not errors. Alert on webhook inactivity so a disabled webhook doesn't go unnoticed past the 12-hour re-enable window.

Conclusion

Aircall webhooks verify with a token in the body rather than an HMAC signature, deliver at least once in no guaranteed order, and give you 5 seconds to respond before a failure counts toward the 50 retries that disable the webhook. Verify the token timing-safely, acknowledge fast, upsert on data.id, and subscribe to events explicitly.

Hookdeck Event Gateway verifies the token at the edge, absorbs Aircall's delivery pace, deduplicates, and retries your handler independently, so Aircall's timeout and auto-disable rules stop being constraints your code has to satisfy.

Get started with Hookdeck for free and handle Aircall webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.