Skip to Content
API access is available to organizations with a signed BAA. Request API access →
Campaigns

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 or an org admin’s OAuth token. 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

statusMeaningYou can
draftCreated, not yet sent.Edit everything, add and remove recipients, start, delete.
runningSending, one message every send_interval_seconds.Add recipients, pause, stop.
pausedSending is on hold.Edit the message, channel, and pace, add and remove recipients, start again to resume, stop.
completedEvery recipient was sent to.Archive.
stoppedStopped early. Unsent recipients were cancelled.Archive. It can’t be restarted.

Send a campaign

Create it

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, 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 first and use the IDs from the import results.

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"]}'
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.

Start it

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 for its counts, or list its recipients for each patient’s status:

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

Recipient status

statusMeaning
pendingWaiting its turn.
sendingBeing sent now.
sent, delivered, openedOn its way, confirmed delivered, or the secure link was opened.
failed, undeliveredDidn’t reach the patient. error says why, like landline.
skippedCouldn’t be sent, like opted_out for an SMS campaign or no_contact_method.
cancelledThe 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 from the campaign’s start with q=from:patient.

Change a campaign

Update a 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. 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 holds sending after the message in progress. Start it again to carry on where it left off.
  • Stop ends the campaign for good; recipients who haven’t been sent to are cancelled. To send to them later, create a new campaign.
  • Delete 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 instead.
Last updated on