# Campaigns

> Send one message to many patients from a clinic phone number. Create, start, pause, stop, and archive campaigns, and track each delivery.

Source: https://www.bloomtext.com/developers/api/campaigns/

Use a campaign to send the same message to many patients, one at a time, from a clinic phone number: flu shot reminders, a new office address, forms everyone needs to fill out. Campaigns are the API version of BloomText's broadcasts. Each patient gets the message in their own conversation on that phone number, so replies come back to the team like any other patient message.

Campaigns work with an [API key](https://www.bloomtext.com/developers/api/api-keys/) or an [org admin's OAuth token](https://www.bloomtext.com/developers/api/oauth/). They need the `messages.write` scope to create, change, and run, and `messages.read` to check on them. Messages come from whoever created the campaign: the API key's name, like "Reminder service", or the admin, with your app recorded in `sent_via`.

## The lifecycle

```mermaid
stateDiagram-v2
  [*] --> draft: Create
  draft --> running: Start
  running --> paused: Pause
  paused --> running: Start
  running --> completed: Every recipient sent
  running --> stopped: Stop
  paused --> stopped: Stop
```

| `status` | Meaning | You can |
| --- | --- | --- |
| `draft` | Created, not yet sent. | Edit everything, add and remove recipients, start, delete. |
| `running` | Sending, one message every `send_interval_seconds`. | Add recipients, pause, stop. |
| `paused` | Sending is on hold. | Edit the message, channel, and pace, add and remove recipients, start again to resume, stop. |
| `completed` | Every recipient was sent to. | Archive. |
| `stopped` | Stopped early. Unsent recipients were cancelled. | Archive. It can't be restarted. |

## Send a campaign

### Create it

```bash filename="Request"
curl -X POST https://api.bloomtext.com/v1/campaigns \
  -H "Authorization: Bearer $BLOOMTEXT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Flu shot reminders, October",
    "body": "Flu shots are available at Example Clinic. Reply here to book a time.",
    "from": "+15125550100"
  }'
```

Every recipient gets the same `body`, up to 1,600 characters. `name` is for staff; patients never see it. Like [single messages](https://www.bloomtext.com/developers/api/send-messages/#secure-or-plain-text), campaigns are secure unless you set `channel` to `sms`.

`from`, the phone number to send from, defaults to the default number (the API key's, or the admin's). `send_interval_seconds` (0.5 to 30, default 1) sets the pace.

### Add recipients

Add up to 10,000 patient IDs per request. To reach patients you've loaded from your EHR, [import them](https://www.bloomtext.com/developers/api/patients/#import-patients) first and use the IDs from the import results.

```bash filename="Request"
curl -X POST https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65/recipients \
  -H "Authorization: Bearer $BLOOMTEXT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"patient_ids": ["5a1c9e2b-7d44-4f1a-9c3e-2b8d6f0a1e77", "9e0d3f7a-2c1b-4e8d-a5f6-7b3c2d1e0f98"]}'
```

```json filename="Response · 200 OK"
{ "changed": 2, "skipped": [] }
```

Unknown patient IDs come back in `skipped` with `reason: not_found`, and patients already on the campaign with `already_added`. Recipients are always patient IDs; there's no "every patient" option.

To take patients off while the campaign is a draft or paused, use [Remove campaign recipients](https://www.bloomtext.com/developers/api/reference/remove-campaign-recipients/).

### Start it

```bash filename="Request"
curl -X POST https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65/start \
  -H "Authorization: Bearer $BLOOMTEXT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

BloomText sends to one recipient every `send_interval_seconds`, in the order they were added. A campaign of 400 patients at the default pace takes about seven minutes.

### Watch it go

[Retrieve the campaign](https://www.bloomtext.com/developers/api/reference/get-campaign/) for its `counts`, or [list its recipients](https://www.bloomtext.com/developers/api/reference/list-campaign-recipients/) for each patient's status:

```json filename="counts"
{ "recipients": 412, "pending": 148, "sent": 264, "delivered": 251, "failed": 6, "skipped": 0 }
```

## Recipient status

| `status` | Meaning |
| --- | --- |
| `pending` | Waiting its turn. |
| `sending` | Being sent now. |
| `sent`, `delivered`, `opened` | On its way, confirmed delivered, or the secure link was opened. |
| `failed`, `undelivered` | Didn't reach the patient. `error` says why, like `landline`. |
| `skipped` | Couldn't be sent, like `opted_out` for an SMS campaign or `no_contact_method`. |
| `cancelled` | The campaign was stopped before this patient's turn. |

List only the ones that need attention with `?status=failed`. Each sent recipient has a `message_id`, and the message sits in that patient's conversation on the campaign's phone number. Messages a campaign sent carry its `campaign_id`. To pick up replies, [read messages](https://www.bloomtext.com/developers/api/read-messages/) from the campaign's start with `q=from:patient`.

## Change a campaign

[Update a campaign](https://www.bloomtext.com/developers/api/reference/update-campaign/) with only the fields you want to change:

- **Name, message, channel, phone number, and pace** can change while the campaign is a draft or paused. Pause it first to fix a typo mid-send; patients already sent to keep the original.
- **Phone number** (`from`) can change only while it's a draft.
- **`archived: true`** hides a finished campaign from [List campaigns](https://www.bloomtext.com/developers/api/reference/list-campaigns/). Archiving isn't allowed while it's running. `archived: false` brings it back.

A change the campaign's status doesn't allow returns `409 campaign_not_editable`.

## Pause, stop, and delete

- [Pause](https://www.bloomtext.com/developers/api/reference/pause-campaign/) holds sending after the message in progress. [Start](https://www.bloomtext.com/developers/api/reference/start-campaign/) it again to carry on where it left off.
- [Stop](https://www.bloomtext.com/developers/api/reference/stop-campaign/) ends the campaign for good; recipients who haven't been sent to are `cancelled`. To send to them later, create a new campaign.
- [Delete](https://www.bloomtext.com/developers/api/reference/delete-campaign/) removes a draft. Once a campaign has started, its messages are in patients' conversations, so it can't be deleted; archive it instead.

## Good to know

- Plain SMS campaigns put the message on patients' phones and the carrier's network. Keep clinical detail out of them.
- In SMS campaigns, opted-out patients are skipped and show as `skipped` with `error: opted_out`.
- Every recipient gets the same text; campaigns don't fill in names or other details yet. For personalized messages, loop over [Send a message to a patient](https://www.bloomtext.com/developers/api/send-messages/) instead.
