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

Errors

Failed requests return a standard HTTP status code and an RFC 9457  problem details body with Content-Type: application/problem+json. Branch on the code field, not the human-readable text.

Response · 403 Forbidden
{ "type": "https://www.bloomtext.com/developers/api/errors/#insufficient_scope", "title": "Forbidden", "status": 403, "code": "insufficient_scope", "detail": "This endpoint needs the messages.write scope, and the user didn't grant it.", "request_id": "0b6c2d1e-5f4a-4c3b-9a8d-7e6f5a4b3c2d", "field_errors": [] }

The problem object

typeURLRequired

Link to the documentation for this error.

titlestringRequired

Short, human-readable summary of the status.

statusintegerRequired

The HTTP status code, repeated for convenience.

codestringRequired

Machine-readable error code. See Error codes.

detailstring

Explanation of this specific occurrence.

request_idUUIDRequired

Unique ID for the request. Include it when you contact support.

field_errorsarray of FieldErrorRequired

Per-field problems for 422 responses. Empty otherwise.

Show child attributes
pathstringRequired

JSON pointer to the field, like /body, or the query parameter or header name.

codestringRequired

Machine-readable validation code, like too_long or required.

messagestringRequired

Human-readable explanation.

HTTP status codes

StatusMeaningRetry?
200, 201, 202, 204Success. A 202 send waits for the patient’s consent to texting.No
400The request is malformed.No, fix the request.
401The API key is missing, expired, or revoked (or, with OAuth, the access token is).No; with OAuth, after refreshing the token.
403The credential lacks the scope, an API key called an OAuth-only endpoint, or API access isn’t turned on for the organization.No
404The resource doesn’t exist, or the key can’t see it.No
405The path exists but doesn’t take that method. The Allow header lists the ones it does.No
409An idempotency or state conflict.Sometimes. See the code.
422A field failed validation.No, fix the fields.
429Rate limited.Yes, after Retry-After seconds.
500, 503A temporary problem on our side.Yes, with backoff and the same Idempotency-Key.

Error codes

CodeStatusWhat to do
invalid_request400Check the JSON syntax and query string.
range_required400With an API key, List messages needs after, patient_id, or conversation_id. See Read messages.
patient_filter_required400Look patients up by phone or mrn. Bulk listing isn’t available; contact BloomText if you need a sync. See Patients.
org_id_required400The API key reaches more than one organization. Pass org_id, from GET /orgs. See Organizations a key reaches.
invalid_query400The q search query can’t be parsed. detail points at the problem. See Search.
invalid_token401API key: check you’re sending the whole key. With OAuth: refresh the access token. If the refresh fails with invalid_grant, the admin must reconnect your app. See When a connection ends.
key_revoked401An Owner or IT person revoked this API key. Ask them for a new one. See API keys.
key_expired401The API key’s expiry has passed. An Owner or IT person can extend it under Settings → Account → API keys, or you can ask for a new one. See Expiry.
insufficient_scope403The credential lacks the scope listed on the endpoint’s reference page. Create a key with that scope.
api_access_disabled403API access isn’t turned on for your organization. It’s turned on once a BAA is signed. See API keys to request access.
plan_required403The organization’s plan doesn’t include patient messaging, so it can’t send to patients. Contact BloomText to add it. Everything else, like patient lookups, still works.
org_not_reachable403The API key can’t reach the organization in org_id. GET /orgs lists the ones it can.
accounts_not_enabled403The members, teams, and organizations endpoints work once BloomText turns on accounts for your account. Contact BloomText.
oauth_required403API keys can’t call this endpoint. Everything under /me, and the staff directory, requires an OAuth token.
not_found404Check the ID, and that the key reaches its organization.
method_not_allowed405Use a method from the Allow header.
idempotency_key_reused409Use a new Idempotency-Key for a different request.
idempotency_request_in_progress409The original request is still running. Retry shortly.
ambiguous_recipient409The phone number belongs to several patients. Pick one from candidates and send with patient_id. See Send messages to patients.
recipient_mismatch409patient.mrn belongs to a patient with a different phone number, or the number’s only patient has a different MRN. Nothing was sent. Update the patient in candidates, or send with patient_id. See Send messages to patients.
already_member409The person is already a member of that organization.
patient_account409The email belongs to a patient’s BloomText account, which can’t be a staff member.
managed_by_admin409People in BloomText manage this membership or put this person on the team, so the API can’t change it. See Who manages a membership.
managed_by_account409This is an Owner or IT person’s membership, set on the Account page in BloomText.
managed_by_identity_provider409The account’s Okta rules manage this membership or team placement. Change it in Okta or in the rules. See SSO and Directory Sync.
confirmation_required409With reason: would_delete_user: removing this person deletes their BloomText user. Repeat with confirm_delete_user=true to do that. See Remove a member.
campaign_not_editable409The campaign’s status doesn’t allow that change. See Campaigns.
campaign_not_startable409The campaign is already running, completed, stopped, or archived.
campaign_not_running409Only a running campaign can be paused. Only a running or paused campaign can be stopped.
campaign_not_deletable409Only a draft campaign can be deleted. Archive a started one instead.
validation_failed422Fix each field listed in field_errors.
unknown_field422The body has a field the endpoint doesn’t take. Each one is in field_errors, and the message says where it goes when it belongs elsewhere. See Unknown fields are rejected.
campaign_empty422Add recipients before starting the campaign.
from_required422The organization has several phone numbers and no default. detail and numbers list them; set from to one. See Which number it comes from.
channel_required422Set channel to sms or secure. There’s no default. See Secure or plain text.
too_long422The body is over max characters (1,600 for SMS). length says how long it was. Shorten it, split it yourself, or send it secure.
patient_has_no_phone422An SMS to a patient with no phone number. Add one, or send secure if they have an email address.
no_contact_method422A secure message to a patient with neither phone nor email. Update the patient.
contact_cap_reached422The organization has texted as many new patients as it can this billing period until BloomText verifies it. Contact support to get verified.
patient_opted_out422The patient replied STOP to your organization, or staff recorded their opt-out (since says when), so no number can text them until they reply START. Stop texting them; a secure message still reaches them by email. See Opt-outs and blocked numbers.
carrier_blocked422The carrier refused an earlier text to the patient, so none of your organization’s numbers text them. Stop texting them; they can text START to one of your numbers.
number_blocked422An admin in your organization blocked the patient’s number, so none of its numbers text them. Stop texting them; only an admin can unblock it, in the app.
number_unreachable422An earlier text failed because the patient’s number can’t receive texts: a landline, or a carrier that couldn’t be reached. None of your organization’s numbers text it until the patient texts one of your numbers, their phone number is changed, or an admin clears it in the app. Update the patient’s mobile number, or send secure.
rate_limited429Wait Retry-After seconds, then retry.
internal_error500Retry with backoff. If it persists, contact support with the request_id.
service_unavailable503Retry with backoff.

Unknown fields are rejected

A POST or PATCH body may only contain the fields its reference page lists. Any other field, such as a typo or a field in the wrong place, returns 422 unknown_field before anything runs. Nothing is sent or changed, and the Idempotency-Key isn’t used up, so fix the body and send it again with the same key. Each unknown field gets an entry in field_errors, with its JSON pointer and where it belongs, if anywhere:

Response · 422 Unprocessable Entity
{ "type": "https://www.bloomtext.com/developers/api/errors/#unknown_field", "title": "Unprocessable Entity", "status": 422, "code": "unknown_field", "detail": "The body has fields this endpoint doesn't take. Unknown fields are rejected rather than ignored, so a typo or a misplaced field never goes unnoticed. Fix each one in field_errors.", "request_id": "0b6c2d1e-5f4a-4c3b-9a8d-7e6f5a4b3c2d", "field_errors": [ { "path": "/patient", "code": "unknown_field", "message": "'patient' isn't a top-level field; put it under 'to'." } ] }

Responses work the other way: they may gain new fields within v1, so ignore fields you don’t recognize. See the Changelog.

Handle errors

const response = await fetch(url, options) if (!response.ok) { const problem = await response.json() switch (problem.code) { case 'invalid_token': // Refresh the access token and retry once. If refreshing fails, ask the user to reconnect. break case 'rate_limited': await new Promise((r) => setTimeout(r, Number(response.headers.get('Retry-After')) * 1000)) break default: throw new Error(`${problem.status} ${problem.code}: ${problem.detail} (request ${problem.request_id})`) } }

The OAuth token endpoint, https://app.bloomtext.com/oauth/token, is the one exception. It returns standard OAuth errors like invalid_grant instead of problem details. See Token endpoint errors.

Every response, success or error, includes an X-Request-Id header with the same value as request_id. Log it alongside your own request logs.

Last updated on