---
title: "AI phone call API: webhooks, retries and no double calls"
description: "How to run AI phone calls from your own code: get results by webhook, retry safely with an Idempotency-Key, and know when a failed call is worth placing again."
url: https://callforme.tel/guides/phone-call-api-webhooks-and-retries
published: 2026-11-13
updated: 2026-11-13
author: Jake Marsh
---

# AI phone call API: webhooks, retries and no double calls

> 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.

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](/docs/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.

```bash
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}` shows `webhook.status` (`pending`, `delivered`, `failed`) and the last error, so you can see why something didn't arrive.
- For [call_around](/guides/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](/docs/rest-api#webhooks).

## 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 `402` with a setup link, or `400` for 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](/agents/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

- [REST API reference](/docs/rest-api)
- [Use CallForMe in Zapier, Make or n8n](/agents/automations)
- [Call several places at once](/guides/call-around)
- [Pricing](/docs/pricing)

## FAQ

### 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.

## Related

- [Changelog: what's new, newest first](https://callforme.tel/docs/changelog.md)
- [How to add phone calls to your own AI agent](https://callforme.tel/guides/add-phone-calls-to-your-ai-agent.md)
- [Can Codex make phone calls? How to give OpenAI Codex a phone](https://callforme.tel/guides/can-codex-make-phone-calls.md)
- [Can ChatGPT make phone calls? How to let it call a business](https://callforme.tel/guides/let-chatgpt-call-a-business.md)
- [AgentPhone vs CallForMe: own number, or calls done for you](https://callforme.tel/compare/agentphone.md)
