Skip to Content
API access is available to organizations with a signed BAA. Request API access →
Send messages to patients

Send messages to patients

Reach a patient with one request. Send a message to a patient takes a patient ID or phone number and the text. BloomText finds the patient (or creates one for a new number), finds or starts the conversation on the right clinic phone number, and sends the message.

Request
curl -X POST https://api.bloomtext.com/v1/patient-messages \ -H "Authorization: Bearer $BLOOMTEXT_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "to": { "patient_id": "5a1c9e2b-7d44-4f1a-9c3e-2b8d6f0a1e77" }, "body": "Hi Jane, Dr. Example moved your appointment to Friday at 9:00. Reply here with any questions." }'

The response holds the sent message, with its conversation, patient, channel, and delivery status, plus patient_created and conversation_created.

Use an API key or an org admin’s OAuth token. The request needs only the messages.write scope, even when it creates a patient.

Who it comes from

Sent withThe patient seesStaff see
An API keyThe clinicThe key’s name, like “Reminder service”
OAuthThe adminThe admin, with a “via” label naming your app

With OAuth, sending also marks the conversation as read for the admin, as replying in BloomText does. See Messages sent through the API.

Who gets it

Set to to exactly one of:

toWhat happens
{"patient_id": "…"}Sends to that patient.
{"phone": "…"}Looks up the phone number in your organization’s patients.

A phone number can be in any common format, like (512) 555-0143 or +15125550143. BloomText resolves it this way:

  • No patient has that number: BloomText creates one, as it does when a new number texts the clinic. Add a patient object with first_name, last_name, date_of_birth, email, or mrn to fill in the new record. If patient.mrn matches an existing patient, BloomText uses that patient instead of creating one.
  • One patient has it: that patient.
  • Several patients share it, like a family phone: 409 ambiguous_recipient. BloomText never guesses; the error’s candidates lists the matching patients. Send again with the right patient_id, or add patient.mrn to say which one.
Request · a new number
{ "to": { "phone": "(512) 555-0199", "patient": { "first_name": "John", "last_name": "Doe", "mrn": "MRN-21004" } }, "body": "Welcome to Example Clinic. Your intake form is ready." }

Secure or plain text

Messages to patients are secure unless you set channel to sms:

channelThe patient receivesUse it for
secure (default)A text or email with a secure link. The message itself stays inside BloomText, and the patient reads and replies there.Anything clinical or personal.
smsThe message text as a regular SMS from the clinic’s number. Replies come back by SMS.Logistics, like reminders, directions, or “your forms are ready.”
Request · plain SMS
{ "to": { "patient_id": "5a1c9e2b-7d44-4f1a-9c3e-2b8d6f0a1e77" }, "body": "Reminder: your appointment is tomorrow at 9:00 at 1200 Main St.", "channel": "sms" }

Plain SMS puts the message on the patient’s phone and the carrier’s network, outside BloomText. Keep clinical detail out of sms messages.

Which number it comes from

Each clinic phone number belongs to a team, like “Front desk” at +1 512-555-0100 or “Billing” at +1 512-555-0200. Texts come from one of them, and the patient’s replies go back to that team’s conversation. Name the number with from:

Request
{ "to": { "patient_id": "5a1c9e2b-7d44-4f1a-9c3e-2b8d6f0a1e77" }, "from": "+15125550200", "body": "Your statement is ready. Reply here with any billing questions." }
  • List phone numbers returns the numbers you can send from: every number in the organization for an API key, or the admin’s teams’ numbers for OAuth.
  • Without from, BloomText uses the default number, marked is_default: the one set on the API key when it was created, or the admin’s own default.
  • If there’s no default and more than one number, the request returns 422 from_required. Pass from.

BloomText keeps one conversation per phone number and patient. Sending again from the same number continues that conversation; sending from another team’s number starts a separate one.

Reply in a conversation

With an API key, reply to a patient with this same request: name the patient and the from number, and BloomText continues their conversation on that number.

With OAuth, you can also reply by conversation ID, for example one you found by reading messages. Send a message in the conversation (POST /me/conversations/{id}/messages); it uses the conversation’s phone number and channel.

Request
curl -X POST https://api.bloomtext.com/v1/me/conversations/e5c3b7b8-8f08-4d5a-9af1-0d11b0f4b7a0/messages \ -H "Authorization: Bearer $BLOOMTEXT_ACCESS_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"body": "Friday at 9:00 works. You are all set."}'

Delivery status

A text can fail after BloomText accepts it: a landline, a disconnected number, or a carrier block. Every message to a patient carries a delivery status that BloomText updates from the carrier.

delivery.statusMeaning
queuedAccepted, not yet handed to the carrier.
sentHanded to the carrier.
deliveredThe carrier confirmed delivery.
openedThe patient opened the secure link.
failed, undeliveredThe message didn’t reach the patient. delivery.error says why, like landline, invalid_number, or opted_out.

To follow up on failures, read messages with after set to the start of the day and q=is:failed, or check one message with Retrieve a patient message.

Opt-outs

A patient who replies STOP to texts from a phone number stops getting SMS from that number. Their patient record shows sms_opted_out: true, and sending them channel: sms returns 422 patient_opted_out. Secure messages by email still reach them. When they reply START, texts resume.

Errors to handle

StatusCodeWhat to do
404not_foundThe patient_id doesn’t exist in your organization, or from isn’t one of its numbers.
409ambiguous_recipientPick a patient from candidates and send with patient_id, or add patient.mrn.
422from_requiredPass a from number from List phone numbers.
422no_contact_methodThe patient has no phone number for sms, or neither phone nor email for secure. Update the patient.
422patient_opted_outSend with channel: secure so it goes by email, or wait for the patient to reply START.

Every send takes an Idempotency-Key, so a retry after a timeout never texts a patient twice. For automated jobs, derive the key from something stable, like the appointment ID. See Idempotency.

Sending to many patients

Every send names one patient; there’s no “send to everyone” call. To send the same message to many patients, use a campaign: add the recipients, start it, and BloomText sends to each one in turn and tracks delivery. For a different message per patient, loop over this endpoint within your rate limits, and queue the sends rather than firing hundreds at once.

Last updated on