Core concepts
This page explains the objects the API works with and who can reach them. The rest of the docs build on it.
Organizations
Everything in BloomText belongs to an organization: a practice, clinic, agency, or health system. An API key or OAuth token belongs to one organization and never sees another’s data. Retrieve the organization to check which one.
Two credentials
The API has two credentials, for two jobs. See Authentication.
- An API key belongs to the organization, not a person. A server uses it for patient communication: managing and importing patients, messaging patients, reading what a patient wrote, and running campaigns.
- An OAuth token belongs to one org admin who connected your app. It reaches the same patient operations, plus the admin’s own conversations.
What the API can reach
Access is narrow on purpose:
- Patients are always named. You find a patient record by patient ID, phone number, or MRN. No call lists the patient directory or searches it by name.
- Reads are bounded. Every read of patient messages or conversations is limited by a time range, a patient, or a conversation.
- Staff conversations need a member’s OAuth token. A conversation other than a patient conversation is reachable only through OAuth, and only when the connected admin is in it, directly or through a team. The admin can then read its full history, including messages from before they joined. Any other conversation returns
404, as if it didn’t exist. An API key never sees one.
For the other protections and your responsibilities under the BAA, see Security and BAA.
Patients
A patient is someone your organization messages, with a name, mobile number, email, date of birth, and mrn (their ID in your system). Patients belong to the organization. Messaging a new phone number creates the patient. See Patients.
Phone numbers
Each clinic phone number belongs to a team, like “Front desk” at +1 512-555-0100. Texts to patients come from a phone number, and patients’ replies go back to that team’s conversation. Name the number with from when you send, or leave it out to use the default. An API key can send from any of the organization’s numbers; an admin, from their teams’ numbers. See List phone numbers.
Conversations
A conversation is a thread between people in your organization and, often, a patient or family member. Its type is patient, direct, group, or broadcast. A patient conversation belongs to one phone number, so a patient who has texted two teams has two conversations. Participants can be staff or patients.
Either credential can read patient conversations by time range, by patient (patient_id), or one conversation at a time; see Read messages. Other conversations follow the access rules above.
Messages, replies, and reactions
- A message carries either text (
body) or a file (file). It includes itssender(name, and whether they’re staff or a patient), itsconversationandpatient, and itschannel, so you can read a list of messages without extra lookups. - Messages to patients carry a
deliverystatus. See Send messages to patients. - A reply is a message with
reply_to_message_idset. A conversation’s messages include its replies; group them by that field to rebuild a thread. - Reactions are emoji on a message. They have no ID of their own; each is identified by the message, the user, and the emoji.
Messages sent through the API
Messages to patients go by secure link unless the request sets channel to sms. Who a message comes from depends on the credential:
| Sent with | sender | Staff see | Patients see |
|---|---|---|---|
| An API key | The key, like “Reminder service” (kind: api_key) | The key’s name | The clinic |
| OAuth | The connected admin | The admin, with a “via” label naming your app (sent_via) | The admin |
Every message is recorded against the key, or the admin and your app, so an organization can always tell what came through the API. Make sure staff know what your integration sends, and in whose name. See Build an AI agent.
Read state
With OAuth, each message has an unread flag, and each conversation an unread_count, for the connected admin. They match the unread badges the admin sees in BloomText. API keys have no read state, so unread is always false for them.
Reading through the API never marks anything as read, so a background digest won’t clear the admin’s badges. Sending a message in a conversation with OAuth marks it as read for the admin, the same as replying in BloomText. There’s no separate “mark as read” call.
Finding and following messages
- Read messages:
GET /patient-messages(Patient API) andGET /me/messages(OAuth) return every message in a time range, newest first, one by one or grouped by conversation, with a cursor. Narrow it to a patient or conversation. - Search: add
qfor words and filters, likerefill from:patient is:unread. - Keep up: ask again with
afterset to the newest message you’ve seen.
IDs, timestamps, and requests
| Convention | Detail |
|---|---|
| Base URL | https://api.bloomtext.com/v1 |
| Authentication | Authorization: Bearer <access token>. See Authentication. |
| IDs | Objects have a stable id, usually a UUID. Reactions have none; each is identified by its message, user, and emoji. |
| Timestamps | RFC 3339 strings in UTC, like 2026-09-21T12:00:00Z. |
| Bodies | JSON in and out. Send Content-Type: application/json. |
| Lists | Cursor-paginated. See Pagination. |
| Writes | Every POST takes an Idempotency-Key. See Idempotency. |
| Errors | RFC 9457 problem details. See Errors. |