> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firetone.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Placing calls

> Click-to-call from your CRM, an AI agent ringing a lead, and hearing how each call went.

Your system can place two kinds of call: a **click-to-call** that rings one of
your people first, and an **AI call** where a virtual agent rings someone. Both
run on FireTone's own call engine, with the same routing, credit check,
recording and call records as any other call.

## Click-to-call

```bash theme={null}
curl -X POST https://api.your-host/api/v1/calls \
  -H "authorization: Bearer $FIRETONE_KEY" -H 'content-type: application/json' \
  -H "Idempotency-Key: task-8812" \
  -d '{
    "from": { "user_email": "dana@acme.com.au" },
    "to": "+61412345678",
    "reference": "crm-task-8812",
    "callback_url": "https://crm.acme.com.au/firetone/calls"
  }'
```

1. **Dana's phone rings first.** The response comes back once she answers (up
   to 30 seconds), with the `call_uuid`.
2. When she answers, **the number is dialled**.

`from` can be `extension`, `agent_id` or the `user_email` of a person linked to
an agent. You can still send `extension` and `destination` on their own.

If Dana doesn't answer, the response is an error, and your callback gets
`call.failed`.

## An AI agent calls someone

```bash theme={null}
curl -X POST https://api.your-host/api/v1/calls/ai \
  -H "authorization: Bearer $FIRETONE_KEY" -H 'content-type: application/json' \
  -d '{
    "profile_id": "7c1e…",
    "to": "+61412345678",
    "caller_id": "+61298765432",
    "variables": { "name": "Sam", "interest": "teeth whitening", "enquired": "yesterday" },
    "reference": "lead-5521",
    "callback_url": "https://crm.acme.com.au/firetone/calls"
  }'
```

* **It answers `202` straight away**, with a `request_id`. The call is dialled
  in the background.
* **The agent follows its profile.** It uses its role, SOP, knowledge and
  rules, and it knows it made the call. The `variables` are in its brief as
  what it knows about this call.
* **`caller_id`** must be one of your numbers. You can leave it out if you have
  only one.
* **When the call ends**, `conversation.completed` brings the summary and any
  review flags, and `call.ended` brings the outcome.
* **If nobody answers**, `call.failed` comes with the reason: `no_answer`,
  `busy`, `invalid_number`, and so on.

Refused straight away, with `422` and the reason:

* the number is one of your own;
* no route reaches it;
* billing refuses it;
* no virtual agent uses the profile.

## Try it first: `dry_run`

Add `?dry_run=true` to either call. FireTone checks everything a real call
would and places nothing:

* the phone that should ring first is registered;
* the number resolves;
* a route reaches it;
* there's credit for it;
* the agent exists.

```json theme={null}
{ "dry_run": true, "plan": { "to_e164": "+61412345678", "caller_id": "+61298765432", "agent": "Ava", "trunk": "Carrier A", "max_seconds": 3600 } }
```

## Hearing how it went

### Callbacks

A `callback_url` receives that call's events as signed JSON `POST`s, in the
same format as [webhooks](/tenant/phone-system/integrations#webhooks):

| Event                    | When                                                      |
| ------------------------ | --------------------------------------------------------- |
| `call.started`           | The call reached FireTone                                 |
| `call.answered`          | Someone picked up                                         |
| `call.ended`             | It's over: duration, cause, cost, whether it was recorded |
| `recording.ready`        | The recording can be downloaded                           |
| `conversation.completed` | For an AI call: the summary and review flags              |
| `call.failed`            | It never connected, with the reason                       |

* **What every event carries:** your `reference` and the `request_id`.
* **How they're signed:** with your organisation's **callback secret**. Create
  it once with `POST /integration/callback-secret` (the secret is shown once),
  and verify `X-FireTone-Signature` exactly as for webhooks. A `callback_url`
  sent before the secret exists is refused with `409 no_callback_secret`.
* **Delivery:** retried like webhooks. `GET /calls/{uuid}/callbacks` lists what
  was sent.

### Asking

* `GET /call-requests/{request_id}` returns `dialing`, `connected` (with the
  `call_uuid`), `completed`, or `failed` (with why).
* `GET /calls/{call_uuid}` returns the call itself: live while it lasts, and
  from its record afterwards. That includes your `reference` and the
  recording's URL.

Your `reference` is also on the call's record, so a CDR export names your
record without a lookup.
