What AI phone webhooks are
AI phone webhooks are HTTPS requests that an AI phone line sends to a URL you choose, each one describing a single event on your business number, such as a finished call, a message taken or an appointment booked. Each request is JSON and signed, so your server can prove where it came from.
Routing means two things in telephony. Call routing decides where the audio goes: which phone rings, who picks up. That stays inside the product. Your AI answers every call to your number, and puts a caller through to a person when your rules say so.
Webhook routing is about the record of the call. Without webhooks the facts sit in your dashboard. With webhooks they also land wherever your business already works.
If you don't write code, you may not need this. The Integrations page connects HubSpot and Zoho Bigin, so each call is logged to the contact with no server of your own.
How call data is routed from a local business number
Call data is routed from a local business number in three steps: the AI phone agent answers the call and records what happened, the platform builds an event for each thing worth knowing, and it posts that event to every endpoint you have subscribed to it. Your server verifies the signature, answers, and files the data.
The ten events
You choose which events each endpoint receives.
| Event | Fires when |
|---|---|
call.started | A call to your number has begun |
call.ended | A call finished and has been metered |
call.transcript.ready | A finished call's transcript is stored |
booking.created | Your AI booked an appointment on a call |
message.taken | Your AI took a message for you |
call.urgent | Your AI flagged a call as urgent |
question.unanswered | A caller asked something your AI could not answer |
credit.low | Credits are low or gone, or plan minutes are used up |
plan.expiring | Your plan is about to end |
number.released | A number went back to the carrier after its plan lapsed |
What a delivery looks like
Every delivery is the same four-field envelope, whatever the event:
| Field | What it holds |
|---|---|
id | A stable id for the event. A retry carries the same one |
type | The event name, for example call.ended |
created | When the event was first built, as an ISO timestamp |
data | The event's own fields |
For call.ended, data carries call_id, from, to, caller_name, outcome, duration_seconds and started_at. The outcome is one of booked, message, transferred, completed, missed_intent or spam. A withheld number arrives with from set to null, so don't key your records on it alone.
A message or an urgent flag carries message_id, kind, body, caller_name, caller_phone and call_id. The two events share one shape, and kind tells you which it is.
One detail saves a lot of confusion. The transcript event does not contain the transcript. It carries the call_id and a count of turns, and you fetch the words from the REST API with your API key when you want them.
Four places to send your call data
A CRM
Subscribe to call.ended, message.taken and call.urgent, and add call.transcript.ready if you want the words on the record too. Look the caller up by phone number, create them if they are new, and write the call as a note or an activity.
A Slack bot
Subscribe one endpoint to call.urgent alone and post the body, the caller's name and their number into the channel your on-call person watches.
A spreadsheet
For a call log your bookkeeper or manager can filter, append one row per call.ended: when it started, who called, how long it ran and how it ended. A small serverless function is enough.
A job system
Trades and clinics often want a booking to become a job card. booking.created carries the start time, the service, the caller's name and a source showing the AI made it on a call. Create the job from that, and let message.taken open a quote request when the caller wanted a price instead of a time.
How to verify a webhook signature
Your endpoint is a public URL, and anybody who finds it can post JSON to it. Verify every delivery before acting on it.
Each request carries an x-signature header with three parts: t is the time in unix seconds, n is a nonce, and v1 is the signature in hex. The signature is HMAC-SHA256, keyed with your endpoint's secret, over the string made of t, a full stop, n, a full stop, and the body in canonical form. Canonical form means keys sorted at every depth with no whitespace.
- Read the raw request body before any framework changes it.
- Split the header on commas and take
t,nandv1. Reject the request if any is missing. - Reject it if
tis more than 300 seconds from your own clock. - Parse the body, serialise it again with sorted keys and no whitespace, and compute the HMAC over
t.n.bodywith your secret. - Compare your result with
v1in constant time, using your language's timing-safe compare. - Answer with any 2xx straight away, then do the slow work.
Verify the signature instead of allowlisting IP addresses, because the sending addresses are not fixed. The webhooks reference has copy-ready verifiers in Node.js and Python.
Retries, duplicates and the delivery log
Your endpoint has ten seconds to answer. Redirects are not followed, so a 3xx counts as a failure. A failed delivery is tried up to six times in all: after 5 minutes, 30 minutes, 2 hours, 8 hours and 24 hours.
So deduplicate on the event id, because the same event can arrive twice, and queue the work so you can answer 200 first.
An endpoint that fails 12 times in a row is paused, and the console tells you. Fix it, then press Resume. Every attempt is in the delivery log under Settings, Webhooks, and failed deliveries can be replayed from there.
Getting a local number and wiring it up
A plan includes a local number for your AI to answer. Numbers are instant in the US and Canada, and arrive after a carrier check in New Zealand, Australia and the UK. The numbers page and local business numbers by country cover each country.
Then, in the console:
- Open Settings, Webhooks and press Add an endpoint.
- Give it your HTTPS URL and tick the events you want.
- Copy that endpoint's signing secret into your server's environment. No other endpoint shares it.
- Ring your number, have a short conversation, and watch the delivery log.
To ask questions of your call data instead of building a receiver, see connecting Claude, ChatGPT and Cursor to your call data.
Try it before you pay
The free trial runs 7 days with no card, and you can talk to your AI in the browser before you buy anything. When you're ready for a number of your own, plans start at US$29 for 100 minutes over 30 days, and webhooks and API keys come with every one. The pricing page has the full list.
FAQ
Can a webhook change where a phone call goes?
No. Webhooks report what happened on a call and cannot redirect it. Who answers and when a caller is put through to a person is set in your AI's own settings.
Which plans include webhooks?
All of them. Webhooks and API keys are included on Lite, Standard and Pro.
How do I verify an AI phone webhook?
Recompute the HMAC-SHA256 signature over the timestamp, the nonce and the canonical body using your endpoint's secret, then compare it with the v1 value in the x-signature header in constant time. Reject anything more than 300 seconds old.
What happens if my server is down?
The delivery is retried up to six times over about 35 hours. After 12 failures in a row the endpoint is paused until you press Resume, and you can replay failed deliveries from the delivery log.
Does the webhook include the call transcript?
Not the words themselves. The call.transcript.ready event carries the call id and the number of turns, and you fetch the transcript from the REST API.
- docs.prepaid.ai/docs/api/webhooks · read 12 November 2026
- docs.prepaid.ai/docs/webhooks/events · read 12 November 2026
- docs.prepaid.ai/docs/guides/calls-to-crm · read 12 November 2026



