AI phone call API: webhooks, retries and no double calls
Short answer: Start calls with POST /v1/calls and add webhook_url to get the finished call POSTed to you, signed, instead of polling. Send an Idempotency-Key header so a timed-out request can be retried without dialing the business twice. When a call ends without success, retryable says whether placing it again could work or whether it needs a change first.
Add CallForMe to your agentTry a free demo call
Using ChatGPT? Add it from ChatGPT's plugin directory in one step, on any plan.
$1 when someone answers, first 2 minutes included. Nothing if nobody picks up. Connecting asks for nothing.
On your phone? Email yourself the setup steps
If your backend, a cron job or a workflow tool places calls, three things matter beyond the call itself: getting the result without a polling loop, retrying a request without calling a business twice, and knowing which failures are worth another try. The REST API handles all three.
1. Get the result by webhook
Add webhook_url to the request. Once the call's outcome is final, CallForMe POSTs the whole call there: the same JSON GET /v1/calls/{id} returns, with the full transcript.
curl -X POST https://callforme.tel/v1/calls \
-H "Authorization: Bearer $CALLFORME_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"phone": "+14697707412",
"business_name": "Maple Street Pizza",
"goal": "Ask what time they close tonight.",
"webhook_url": "https://example.com/hooks/callforme"
}'
- Deliveries go only to https URLs on public hostnames.
- Answer with any 2xx. Anything else, or no answer within 10 seconds, is retried after 30 seconds, 5 minutes and 30 minutes.
GET /v1/calls/{id}showswebhook.status(pending,delivered,failed) and the last error, so you can see why something didn't arrive.- For call_around, every call in the batch gets its own delivery.
Verify each one with the CallForMe-Signature header. The code is in the REST docs.
2. Retry without double calls
Networks drop responses. If a request times out, you can't know whether the call was placed. Send an Idempotency-Key header (a UUID per call you mean to make):
- The same key with the same body, within 24 hours, returns the first response with
Idempotent-Replayed: true. Nobody is dialed twice. - A key is only used up once a call starts. If the first try came back
402with a setup link, or400for a missing field, the same key works after you fix it. - The same key with a different body returns
409 IDEMPOTENCY_MISMATCH, so a bug that reuses keys can't send the wrong call.
3. Know which failures to retry
When a call ends without success, it carries retryable:
| Ended as | retryable | What to do |
|---|---|---|
| Voicemail, no answer, busy, early hang-up | true | Try again later, or during their hours. next says when if they're closed. |
| Needs something from the user | false | Get it, then POST /v1/calls/{id}/redial with the changes. |
| Won't talk to an assistant | false | Redial with transfer_to so the user joins when a person answers, or have them call. |
| The business can't help, or the number is invalid | false | Find another business. |
No-code tools
Zapier, Make and n8n can catch the webhook with their own hook triggers, with no loops or delays. See automations.
What it costs
$1 per answered call, including the first 2 minutes, then $0.40 a minute, up to 30 minutes. Unanswered and busy calls are free. Webhooks and retries cost nothing extra.
Related
Questions
Do I have to poll for results?
No. Add webhook_url to the request and the finished call arrives there once its outcome is final, with answers, summary and transcript. Polling GET /v1/calls/{id}?wait=45 still works and returns early as soon as something changes.
What happens if my request times out and I send it again?
With an Idempotency-Key header, the retry returns the first response and nobody is dialed twice. Without one, an identical request from the same account within 2 minutes also returns the call already in progress.
How do I know a webhook really came from CallForMe?
Each delivery carries a CallForMe-Signature header: an HMAC-SHA256 of the timestamp and raw body, keyed with your webhook_signing_secret from GET /v1/account. Check it in constant time and reject old timestamps.
Should I retry every failed call?
No. Use retryable. Voicemail, no answer and early hang-ups are usually worth another try later. A call that needs something from the user, a business that won't talk to an assistant, or one that can't help comes back with retryable false and a next step.
Add CallForMe to your agent
One URL for any MCP agent. Connecting asks for nothing.
Install steps for your agentTry a free demo callPricing
On your phone? Email yourself the setup steps
One email with the link, for when you're at your computer. Nothing else.