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

# Running campaigns

> Load contacts from your system, start and stop the campaign, and get each contact's result back.

A campaign can be run entirely from your system (a CRM, a lead database) and
report each person's outcome back to it, filed under your own ids.

## 1. Create it, with somewhere to send results

```bash theme={null}
curl -X POST https://api.your-host/api/v1/campaigns \
  -H "authorization: Bearer $FIRETONE_KEY" -H 'content-type: application/json' \
  -d '{
    "name": "Spring reactivation",
    "kind": "voice_broadcast",
    "message_text": "Hi {{name}}, your {{plan}} plan renews next week...",
    "caller_id": "+61298765432",
    "reference": "crm-campaign-77",
    "result_callback_url": "https://crm.acme.com.au/firetone/results"
  }'
```

`result_callback_url` needs your organisation's [callback
secret](/api/calls#callbacks) to exist, because results are signed with it.

## 2. Load people, with your ids and data

```bash theme={null}
curl -X POST https://api.your-host/api/v1/campaigns/$ID/contacts \
  -H "authorization: Bearer $FIRETONE_KEY" -H 'content-type: application/json' \
  -H "Idempotency-Key: load-77-batch-1" \
  -d '{ "items": [
    { "e164": "+61412345678", "name": "Sam", "reference": "lead-1001", "variables": { "plan": "Gold" } },
    { "contact_id": "3f2a…", "reference": "lead-1002" }
  ] }'
```

* **A number FireTone doesn't know becomes a new contact.**
* **`variables` are the call's own:**
  * `{{plan}}` in the message or in the campaign's workflow;
  * what an AI agent knows about the person;
  * and they come back with the result.
* **Do-not-call contacts** are loaded as `suppressed` and never rung.
* **Up to 10,000 items per request.** Send more in batches, each with its own
  `Idempotency-Key`.

## 3. Start, pause, resume, stop

| Call                          | Allowed when        | What happens                              |
| ----------------------------- | ------------------- | ----------------------------------------- |
| `POST /campaigns/{id}/start`  | `draft`             | Dialling starts inside the calling window |
| `POST /campaigns/{id}/pause`  | `running`           | No new calls; calls in progress finish    |
| `POST /campaigns/{id}/resume` | `paused`            | Dialling carries on                       |
| `POST /campaigns/{id}/stop`   | any but `completed` | Completed now, with totals so far         |

* **Wrong status:** `409 wrong_status`, naming the status the campaign must be
  in.
* **Can't run:** `422 not_ready`, saying why (for example, no message or
  nobody left to call).

## 4. Results

A contact's outcome is **final** when nothing more will be done. Either the
call reached an end, or every attempt was used. Each final outcome is sent
**once**, as `campaign.contact.completed`, to `result_callback_url` and to any
webhook subscribed to it:

```json theme={null}
{
  "event": "campaign.contact.completed",
  "data": {
    "campaign_id": "…", "campaign_reference": "crm-campaign-77",
    "contact_id": "…", "reference": "lead-1001", "e164": "+61412345678", "name": "Sam",
    "outcome": "reached", "disposition": "message_played", "attempts": 1,
    "variables": { "plan": "Gold" },
    "disposition_answers": { "interested": "yes" },
    "summary": "Sam will renew; asked for a call about the family plan."
  }
}
```

| `outcome`     | Meaning                                                          |
| ------------- | ---------------------------------------------------------------- |
| `reached`     | A person or a machine got the message, or an agent took the call |
| `not_reached` | No answer, busy, rejected, or they hung up waiting               |
| `bad_number`  | The number doesn't exist or can't be routed                      |
| `suppressed`  | Do-not-call                                                      |
| `failed`      | Something on our side (no credit, no message)                    |

`disposition` gives the exact result. An agent's disposition form answers
arrive as `disposition_answers`, and for an AI agent the conversation
`summary`.

* **When nobody is left to call**, the campaign completes and sends
  `campaign.completed` with the totals by outcome and by disposition.
* **Missed a callback?** `GET /campaigns/{id}/results` pages through the same
  results, filtered by `outcome`, `disposition`, `reference` or `since`.
