Send and receive iMessage, SMS, RCS, and WhatsApp, and manage contacts, chats, and numbers.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Attach an identity Attaches a phone/email identity (on a channel type) to a contact.
Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint.
Required when channel_type is amb.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
claude mcp add --transport http mcp https://mcp.blooio.com/v4
Attach an identity Attaches a phone/email identity (on a channel type) to a contact.
| Argument | Type | Description |
|---|---|---|
| channel_id | string | Required when channel_type is amb. |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
| identifier* | string | |
| channel_type | string |
{
"type": "object",
"required": [
"contact_id",
"identifier"
],
"properties": {
"channel_id": {
"type": "string",
"description": "Required when channel_type is amb."
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
},
"identifier": {
"type": "string"
},
"channel_type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string"
}
},
"additionalProperties": false
}Add contact tags
| Argument | Type | Description |
|---|---|---|
| tag | string | |
| tags | array | |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"tag": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}React to a message Adds or removes a tapback reaction on any message in the chat — inbound (received) or outbound — addressed by the message `id` from the List messages endpoint. Use a `+` prefix to add and `-` to remove (e.g. `+love`, `-love`). Returns 404 if the message isn't in the chat and 409 if it hasn't been dispatched to the device yet. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| reaction* | string | e.g. '+love' to add, '-love' to remove. |
| message_id* | string | Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable. |
{
"type": "object",
"required": [
"chat_id",
"message_id",
"reaction"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"reaction": {
"type": "string",
"description": "e.g. '+love' to add, '-love' to remove."
},
"message_id": {
"type": "string",
"description": "Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable."
}
},
"additionalProperties": false
}Reply to a ticket Adds a reply. A ticket waiting on you moves back to `in_progress`. Closed tickets and tickets whose `can_comment` is false return `403`. OAuth apps need `tickets:write`.
| Argument | Type | Description |
|---|---|---|
| content* | string | The reply. Leading and trailing whitespace is trimmed. |
| ticket_id* | string | Ticket id (`tkt_...`), returned when the ticket is opened. |
{
"type": "object",
"required": [
"ticket_id",
"content"
],
"properties": {
"content": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "The reply. Leading and trailing whitespace is trimmed."
},
"ticket_id": {
"type": "string",
"pattern": "^tkt_",
"description": "Ticket id (`tkt_...`), returned when the ticket is opened."
}
},
"additionalProperties": false
}Answer a call Answer an inbound call that's ringing, or take a call a Blooio agent handed off, with `handler`. The first answer wins; any later one gets `409 call_not_ringing`. OAuth apps need `calls:write`.
| Argument | Type | Description |
|---|---|---|
| call_id* | string | Call id (`call_...`). |
| handler* | object | Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d… |
{
"type": "object",
"required": [
"call_id",
"handler"
],
"properties": {
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
},
"handler": {
"type": "object",
"required": [
"type"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "`stream` only, required: a `wss://` URL."
},
"type": {
"enum": [
"stream",
"agent",
"softphone"
],
"type": "string"
},
"auth_token": {
"type": "string",
"maxLength": 4000,
"description": "`stream` only: sent as `Authorization: Bearer <auth_token>` when Blooio connects to `url`. Kept with the live call only and never returned."
}
},
"description": "Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d…"
}
},
"additionalProperties": false
}Appeal a campaign Ask for a rejected campaign (`review_failed` or `mno_rejected`) to be reviewed again, saying what you fixed. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| reason* | string | What changed since the rejection. |
| campaign_id* | string | 10DLC campaign id (`camp_...`). |
{
"type": "object",
"required": [
"campaign_id",
"reason"
],
"properties": {
"reason": {
"type": "string",
"description": "What changed since the rejection."
},
"campaign_id": {
"type": "string",
"pattern": "^camp_",
"description": "10DLC campaign id (`camp_...`)."
}
},
"additionalProperties": false
}Batch phone number lookup Looks up up to 100 phone numbers. Requires an enterprise plan.
| Argument | Type | Description |
|---|---|---|
| numbers* | array |
{
"type": "object",
"required": [
"numbers"
],
"properties": {
"numbers": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 100
}
},
"additionalProperties": false
}Buy numbers Buy 1 to 10 US local numbers found with `GET /numbers/available`, with `products` turned on. The purchase finishes asynchronously: the response is a `provisioning` purchase, and `number.purchase.completed` or `number.purchase.failed` fires when it settles (or poll `GET /numbers/purchases/{purchaseId}`). Retrying with the same `Idempotency-Key` and body returns the same purchase. An SMS number sends texts once it's assigned to a provisioned 10DLC campaign, which Blooio does automatically when the organization has one. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| products* | array | Products to turn on for every number in the purchase. |
| phone_numbers* | array | US local numbers in E.164 format, as returned by `GET /numbers/available`. |
| idempotencyKey* | string | Unique key that makes the purchase safe to retry. |
{
"type": "object",
"required": [
"idempotencyKey",
"phone_numbers",
"products"
],
"properties": {
"products": {
"type": "array",
"items": {
"enum": [
"sms",
"voice"
],
"type": "string",
"description": "A product you can buy a number for and turn on and off: `sms` (Blooio SMS) or `voice` (Blooio Voice)."
},
"minItems": 1,
"description": "Products to turn on for every number in the purchase."
},
"phone_numbers": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\+1[2-9]\\d{2}[2-9]\\d{6}$"
},
"maxItems": 10,
"minItems": 1,
"description": "US local numbers in E.164 format, as returned by `GET /numbers/available`."
},
"idempotencyKey": {
"type": "string",
"description": "Unique key that makes the purchase safe to retry."
}
},
"additionalProperties": false
}Check if a phone number or email is reachable via iMessage / SMS / RCS. Resolves (or creates) the contact for that identifier, then returns its capabilities. Creating the contact is a side effect.
| Argument | Type | Description |
|---|---|---|
| contact* | string | Phone number (E.164, e.g. +15551234567) or email. |
| channel_type | string | Channel type for a newly created contact (default 'blooio'). |
{
"type": "object",
"required": [
"contact"
],
"properties": {
"contact": {
"type": "string",
"description": "Phone number (E.164, e.g. +15551234567) or email."
},
"channel_type": {
"type": "string",
"description": "Channel type for a newly created contact (default 'blooio')."
}
},
"additionalProperties": false
}Find or create a chat Finds or creates a 1:1 chat with a recipient on a channel. Returns the chat (with `created` indicating whether it was newly created).
| Argument | Type | Description |
|---|---|---|
| to* | string | Recipient identifier (phone/email/opaque provider id). |
| channel_id* | string |
{
"type": "object",
"required": [
"channel_id",
"to"
],
"properties": {
"to": {
"type": "string",
"description": "Recipient identifier (phone/email/opaque provider id)."
},
"channel_id": {
"type": "string"
}
},
"additionalProperties": false
}Create a contact Creates a contact, optionally with one identity (phone/email on a channel type).
| Argument | Type | Description |
|---|---|---|
| name | string | null | |
| channel_id | string | Required when channel_type is amb. |
| identifier | string | Phone (E.164) or email to attach as the first identity. |
| channel_type | string |
{
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"channel_id": {
"type": "string",
"description": "Required when channel_type is amb."
},
"identifier": {
"type": "string",
"description": "Phone (E.164) or email to attach as the first identity."
},
"channel_type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string"
}
},
"additionalProperties": false
}Create a group Creates a group chat on a group-capable channel (blooio/whatsapp) with one or more members. No iMessage conversation exists yet: the first message sent to the group opens it, and `chat_linked` becomes `true` once it does. There is no separate linking step.
| Argument | Type | Description |
|---|---|---|
| name | string | |
| members* | array | Member phone numbers (E.164) or emails, each given as a string or an object `{ "identifier": "..." }`. Every identifier is validated; invalid members 422 `invalid_members` instead of being dropped. |
| channel_id* | string | Must be a group-capable channel (blooio/whatsapp). |
{
"type": "object",
"required": [
"channel_id",
"members"
],
"properties": {
"name": {
"type": "string"
},
"members": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"identifier"
],
"properties": {
"identifier": {
"type": "string"
}
}
}
]
},
"minItems": 1,
"description": "Member phone numbers (E.164) or emails, each given as a string or an object `{ \"identifier\": \"...\" }`. Every identifier is validated; invalid members 422 `invalid_members` instead of being dropped."
},
"channel_id": {
"type": "string",
"description": "Must be a group-capable channel (blooio/whatsapp)."
}
},
"additionalProperties": false
}Create a priority Creates a channel priority. Channels sharing a `priority` (and type) form a pool; ascending priority is the send-time waterfall. The first priority created for a key becomes its default unless `is_default: false` is set.
| Argument | Type | Description |
|---|---|---|
| name | string | |
| channels* | array | Channels in the priority. Each item is a channel id string or `{ channel_id, priority }`. Channels sharing a priority must be the same type. |
| settings | object | Settings to change. A setting set to null returns to the owner's default; unknown keys are rejected with `422 invalid_settings`. |
| is_default | boolean | Make this the key's default priority. Defaults to true for the key's first priority. |
{
"type": "object",
"required": [
"channels"
],
"properties": {
"name": {
"type": "string"
},
"channels": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"channel_id"
],
"properties": {
"priority": {
"type": "integer",
"minimum": 1
},
"channel_id": {
"type": "string"
}
}
}
]
},
"minItems": 1,
"description": "Channels in the priority. Each item is a channel id string or `{ channel_id, priority }`. Channels sharing a priority must be the same type."
},
"settings": {
"type": "object",
"properties": {
"steps": {
"type": [
"object",
"null"
],
"description": "Replaces every step rule; null clears them. A rule must name a step the priority's channels have, so send `steps` together with `channels` when renumbering steps; otherwise `422 invalid_settings`.",
"additionalProperties": {
"type": "object",
"description": "`outreach_only` marks a step for contacts who haven't replied. Once a contact has replied on a channel in the priority, the step goes last (tried only when every other step passes the send over) and the contact's history on it doesn't choose the channel. `transition` is a message sent with the first message a contact reached on this step gets from the next step: `pre` sends it first, `post` right…"
}
},
"on_banned_sticky": {
"enum": [
"switch_number",
"error",
null
],
"type": [
"string",
"null"
]
}
},
"description": "Settings to change. A setting set to null returns to the owner's default; unknown keys are rejected with `422 invalid_settings`.",
"additionalProperties": false
},
"is_default": {
"type": "boolean",
"description": "Make this the key's default priority. Defaults to true for the key's first priority."
}
},
"additionalProperties": false
}Create a campaign Register a campaign under the organization's registered brand. The registry and carriers review it asynchronously; `registration.campaign.updated` fires as its `status` changes. Once a campaign reaches `mno_provisioned`, Blooio assigns the organization's unassigned SMS numbers to its oldest provisioned campaign. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| samples* | array | Example messages, as recipients will see them. |
| usecase* | string | Use case code; one of the `use_cases` values from `GET /10dlc/options`, e.g. `MARKETING`. |
| age_gated | boolean | Content is age-gated (alcohol, for example). |
| description* | string | What the campaign sends and why. |
| number_pool | boolean | The campaign sends from a pool of more than 49 numbers. |
| help_message | string | The reply to HELP. |
| message_flow* | string | How recipients opt in: where they give consent and what they're told. |
| sub_usecases | array |
Open a ticket Opens a support ticket for the Blooio team. Every ticket opens at `medium` priority; only Blooio support changes it, so sending `priority` returns `422 priority_not_allowed`. To request call forwarding, prefer `POST /me/numbers/{number}/call-forwarding`, which takes the destination as a field. OAuth apps need `tickets:write`.
| Argument | Type | Description |
|---|---|---|
| type* | string | |
| content* | string | What you need. A `call_forwarding` ticket must read `Please forward <source> to <destination>` with two US numbers. |
{
"type": "object",
"required": [
"type",
"content"
],
"properties": {
"type": {
"enum": [
"support",
"billing",
"technical",
"feature_request",
"call_forwarding"
],
"type": "string"
},
"content": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "What you need. A `call_forwarding` ticket must read `Please forward <source> to <destination>` with two US numbers."
}
},
"additionalProperties": false
}Create a webhook Subscribes an HTTPS endpoint to events. Returns the signing secret once, on creation.
| Argument | Type | Description |
|---|---|---|
| url* | string | HTTPS endpoint. |
| api_key | string | Scope the subscription to the lines this API key owns. Omit `api_key` and `integration_id` for an organization-wide subscription that receives events from every line. Must belong to your organization; sending both is rejected with 422 `ambiguous_scope`. |
| channel_id | string | |
| api_version | any | The payload version to deliver. Defaults to the latest. Anything not listed by `GET /webhooks/versions` is rejected with 422 `invalid_api_version`, whose `details.supported_versions` lists the accepted values. |
| event_types | array | Retired. Every webhook receives every event; filter by `type` in your handler. Omit this field, or send `["*"]`. Any narrower value is rejected with 422 `event_types_retired`. Subscriptions created before the retirement keep the list they were registered with. |
| channel_type | string | |
| integration_id | string | Scope the subscription to the lines this integration owns. Mutually exclusive with `api_key`. |
Decide policies against a conversation Decides every policy you send against one conversation with Bloobability v2. Each result carries two calibrated numbers in [0, 1]: `probability` (the policy holds) and `answerable` (the conversation contains enough to judge it). There is no verdict and no threshold: choose your own. A low `answerable` never changes `probability`.
| Argument | Type | Description |
|---|---|---|
| tier* | string | Which model decides. `instant` is fastest, for short questions with the deciding facts stated; `full` handles reversals, conditions and missing information. There is no `auto`. |
| messages* | array | The conversation in chronological order. Every message is in scope; none are dropped. |
| policies* | array | Independent policies. Probabilities do not sum to one. |
| assessment_time | string | Optional "now" for time-relative policies, RFC 3339 with an offset. Never defaulted to the request time, and it does not filter messages. |
{
"type": "object",
"required": [
"tier",
"messages",
"policies"
],
"properties": {
"tier": {
"enum": [
"instant",
"full"
],
"type": "string",
"description": "Which model decides. `instant` is fastest, for short questions with the deciding facts stated; `full` handles reversals, conditions and missing information. There is no `auto`."
},
"messages": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"text"
],
"properties": {
"id": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "Unique within the request. The model never reads it."
},
"role": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "Optional free-text role such as `customer`, `agent`, `manager` or `tool`. Custom roles are allowed; `system` grants no authority."
},
"text": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "The full message text, sent unaltered and never cropped. Instructions inside it are judged as conversation, not followed."
},
"timestamp": {
"type": "string",
"format": "date-time",
"pattern": "(?:[Zz]|[+-]\\d{2}:\\d{2})$",
"description": "Optional real send time, RFC 3339 with an offset (`-00:00` is rejected). Must not decrease across `messages`; ties are allowed. Never invent one from array position."
},
"speaker_id": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "Optional participant identity, consistent within the conversation. Two people never share one, though they may share a role. Omit when unknown."
}
},
"additionalProperties": false
},
"maxItems": 2048,
"minItems": 1,
"description": "The conversation in chronological order. Every message is in scope; none are dropped."
},
"policies": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"definition"
],
"properties": {
"id": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "Unique within the request, echoed unchanged. The model never reads it."
},
"definition": {
"type": "string",
"pattern": "\\S",
"minLength": 1,
"description": "A natural-language statement that is true or false of the conversation. This is the whole policy: no registration, roster or per-policy calibration."
}
},
"additionalProperties": false
},
"maxItems": 128,
"minItems": 1,
"description": "Independent policies. Probabilities do not sum to one."
},
"assessment_time": {
"type": "string",
"format": "date-time",
"pattern": "(?:[Zz]|[+-]\\d{2}:\\d{2})$",
"description": "Optional \"now\" for time-relative policies, RFC 3339 with an offset. Never defaulted to the request time, and it does not filter messages."
}
},
"additionalProperties": false
}Delete a contact Soft-deletes a contact and its identities.
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}Delete a group
| Argument | Type | Description |
|---|---|---|
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}Delete a priority
| Argument | Type | Description |
|---|---|---|
| priority_id* | string | Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint. |
{
"type": "object",
"required": [
"priority_id"
],
"properties": {
"priority_id": {
"type": "string",
"description": "Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint."
}
},
"additionalProperties": false
}Delete a webhook
| Argument | Type | Description |
|---|---|---|
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
{
"type": "object",
"required": [
"webhook_id"
],
"properties": {
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
}
},
"additionalProperties": false
}Get purchase status Poll the status of an asynchronous number purchase by its `purchase_id`. Returns `pending`/`provisioning`, `completed` (with the provisioned allocations), or `failed`. Requires the `numbers:read` scope for OAuth apps.
| Argument | Type | Description |
|---|---|---|
| purchase_id* | string |
{
"type": "object",
"required": [
"purchase_id"
],
"properties": {
"purchase_id": {
"type": "string"
}
},
"additionalProperties": false
}Get a call One of the organization's calls. OAuth apps need `calls:read`.
| Argument | Type | Description |
|---|---|---|
| call_id* | string | Call id (`call_...`). |
{
"type": "object",
"required": [
"call_id"
],
"properties": {
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
}
},
"additionalProperties": false
}Get a call transcript What was said on a call while a Blooio agent had it, in order. Empty for calls no agent took. Lines are added while the call is up. OAuth apps need `calls:read`.
| Argument | Type | Description |
|---|---|---|
| call_id* | string | Call id (`call_...`). |
{
"type": "object",
"required": [
"call_id"
],
"properties": {
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
}
},
"additionalProperties": false
}Get a channel
| Argument | Type | Description |
|---|---|---|
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
}
},
"additionalProperties": false
}Get channel capabilities Returns supported protocols, content types, actions, and interactive features for a channel.
| Argument | Type | Description |
|---|---|---|
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
}
},
"additionalProperties": false
}Get line health Messaging health for one dedicated or inbound Blooio line: its live safety state plus reply, delivery, and risk metrics over the trailing `days`. Built for polling.
| Argument | Type | Description |
|---|---|---|
| days | integer | Trailing window in days, 1 to 30. Anything else returns `400 invalid_window`. |
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"days": {
"type": "integer",
"default": 7,
"maximum": 30,
"minimum": 1,
"description": "Trailing window in days, 1 to 30. Anything else returns `400 invalid_window`."
},
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
}
},
"additionalProperties": false
}Get channel settings Per-channel settings for channel types that support them. `settings` and `available` are per channel type: Blooio (P2P numbers) exposes `auto_mark_read`, `auto_share_contact`, and `imessage_only`; Apple Messages for Business and WhatsApp Business expose `opener`; Blooio Voice exposes `inbound`, who answers the number's calls and how long they ring. `available[key]` says whether THIS channel may turn `key` on (type-gated). A channel whose type has no settings yet returns `403 settings_unsupported_for_channel_type`.
| Argument | Type | Description |
|---|---|---|
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
}
},
"additionalProperties": false
}Get a chat The chat of a group that was merged into another group on its first send returns the surviving group's chat on the same number.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Get chat background Reads the chat's background image (Blooio channels). Reads live from the device.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Read Focus status Reads whether the other person in the chat has notifications silenced by a Focus, as their device shares it over iMessage. `silenced` means new messages arrive quietly; to break through for a message you sent, use Notify Anyway. `unknown` means the device has no status for this person (for example, a handle Messages has not seen yet, or someone who does not share Focus status). Apple does not expose a way to turn another person's Focus on or off. Returns 409 for group chats and non-Blooio channels.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Get a contact
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}Get contact capabilities Returns per-identity reachability/capabilities (iMessage/SMS/RCS, etc.) for a contact. For iMessage (blooio) identities this is a LIVE per-number lookup performed by an active iMessage channel — the request is rejected with 409 if the API key has no active iMessage (blooio) channel provisioned.
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}Get a number's contact card
| Argument | Type | Description |
|---|---|---|
| number* | string | Sender phone number in E.164 format, e.g. `+15551234567`. |
{
"type": "object",
"required": [
"number"
],
"properties": {
"number": {
"type": "string",
"description": "Sender phone number in E.164 format, e.g. `+15551234567`."
}
},
"additionalProperties": false
}Get contact timeline A single, chronological cross-channel activity feed for a contact, unifying every conversation the contact takes part in — both 1:1 chats keyed on the contact's identities and group chats where the contact is a current member — across all channel types. After a merge, the survivor's timeline includes the absorbed contact's history automatically. Each entry is a polymorphic envelope tagged by `type`; ordered newest-first by `occurred_at`. By default only `message` entries are returned; pass `include_events=true` to interleave lifecycle and chat events.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
| include_events | boolean | When true, interleaves non-message activity (delivery/read receipts, reactions, chat/group/typing changes) from the events ledger into the feed as `message_event` / `chat_event` entries. Defaults to false (messages only). |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
},
"include_events": {
"type": "boolean",
"default": false,
"description": "When true, interleaves non-message activity (delivery/read receipts, reactions, chat/group/typing changes) from the events ledger into the feed as `message_event` / `chat_event` entries. Defaults to false (messages only)."
}
},
"additionalProperties": false
}Get an event
| Argument | Type | Description |
|---|---|---|
| event_id* | string | Unique identifier of the event, prefixed with `evt_`. Returned by the List events endpoint. |
{
"type": "object",
"required": [
"event_id"
],
"properties": {
"event_id": {
"type": "string",
"description": "Unique identifier of the event, prefixed with `evt_`. Returned by the List events endpoint."
}
},
"additionalProperties": false
}Get a group A group id that was merged into another group on its first send (see Create a group) returns the surviving group. Compare the returned `id` with the one you asked for to pick up the canonical id.
| Argument | Type | Description |
|---|---|---|
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}Get one Find My contact
| Argument | Type | Description |
|---|---|---|
| handle* | string | Contact handle to resolve — a phone number in E.164 format, an email address, or an Apple ID. URL-encode the value. |
{
"type": "object",
"required": [
"handle"
],
"properties": {
"handle": {
"type": "string",
"description": "Contact handle to resolve — a phone number in E.164 format, an email address, or an Apple ID. URL-encode the value."
}
},
"additionalProperties": false
}Get a message
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| message_id* | string | Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable. |
{
"type": "object",
"required": [
"chat_id",
"message_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"message_id": {
"type": "string",
"description": "Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable."
}
},
"additionalProperties": false
}Get message status Lightweight delivery status of a message.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| message_id* | string | Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable. |
{
"type": "object",
"required": [
"chat_id",
"message_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"message_id": {
"type": "string",
"description": "Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable."
}
},
"additionalProperties": false
}Get the key's default priority Returns the calling API key's default channel priority, or `{ "data": null }` when none is configured (in which case the agnostic send falls back to the implicit Blooio pool of the key's own numbers).
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Get a number One of the organization's numbers, with its products and channels. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| number* | string | The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`). |
{
"type": "object",
"required": [
"number"
],
"properties": {
"number": {
"type": "string",
"description": "The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`)."
}
},
"additionalProperties": false
}Get a number purchase A purchase made with `POST /numbers`. Its numbers appear in `GET /numbers` once it's `completed`. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| purchase_id* | string | Purchase id (`pur_...`). |
{
"type": "object",
"required": [
"purchase_id"
],
"properties": {
"purchase_id": {
"type": "string",
"pattern": "^pur_",
"description": "Purchase id (`pur_...`)."
}
},
"additionalProperties": false
}Get poll results
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| poll_id* | string | Unique identifier of the poll, prefixed with `msg_` (a poll shares the id of its underlying message). |
{
"type": "object",
"required": [
"chat_id",
"poll_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"poll_id": {
"type": "string",
"description": "Unique identifier of the poll, prefixed with `msg_` (a poll shares the id of its underlying message)."
}
},
"additionalProperties": false
}Get a priority
| Argument | Type | Description |
|---|---|---|
| priority_id* | string | Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint. |
{
"type": "object",
"required": [
"priority_id"
],
"properties": {
"priority_id": {
"type": "string",
"description": "Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint."
}
},
"additionalProperties": false
}Get the brand The organization's 10DLC brand. OAuth apps need `numbers:read`.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Get a campaign One of the organization's 10DLC campaigns. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| campaign_id* | string | 10DLC campaign id (`camp_...`). |
{
"type": "object",
"required": [
"campaign_id"
],
"properties": {
"campaign_id": {
"type": "string",
"pattern": "^camp_",
"description": "10DLC campaign id (`camp_...`)."
}
},
"additionalProperties": false
}List registration options The entity types, verticals, and campaign use cases a brand and campaign can name. OAuth apps need `numbers:read`.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Check a use case Whether the organization's brand qualifies for a campaign use case, and how many sub use cases it takes. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| usecase* | string |
{
"type": "object",
"required": [
"usecase"
],
"properties": {
"usecase": {
"type": "string"
}
},
"additionalProperties": false
}Get a ticket Returns one ticket. Poll this to check a call-forwarding request: its `forwarding.state` reads `pending`, `in_progress`, `completed`, or `failed`, and a closed ticket always reads `completed`. OAuth apps need `tickets:read`.
| Argument | Type | Description |
|---|---|---|
| ticket_id* | string | Ticket id (`tkt_...`), returned when the ticket is opened. |
{
"type": "object",
"required": [
"ticket_id"
],
"properties": {
"ticket_id": {
"type": "string",
"pattern": "^tkt_",
"description": "Ticket id (`tkt_...`), returned when the ticket is opened."
}
},
"additionalProperties": false
}Get a webhook
| Argument | Type | Description |
|---|---|---|
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
{
"type": "object",
"required": [
"webhook_id"
],
"properties": {
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
}
},
"additionalProperties": false
}Hang up a call End a call. It ends once the carrier confirms, and `call.ended` fires. OAuth apps need `calls:write`.
| Argument | Type | Description |
|---|---|---|
| call_id* | string | Call id (`call_...`). |
{
"type": "object",
"required": [
"call_id"
],
"properties": {
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
}
},
"additionalProperties": false
}List available Blooio numbers Browse Blooio number inventory available to purchase. `type=shared` returns available shared lines; `type=dedicated` returns unassigned dedicated inventory. When one or more `area_code` values are supplied with `type=dedicated` or `type=inbound`, the response is an area-code quote: each requested code is reported as either in stock (provisioned free) or requiring a custom order (a custom area-code fee applies and a provisioning ticket is opened at purchase). Requires the number purchase API feature to be enabled for the organization, and the `numbers:read` scope for OAuth apps.
| Argument | Type | Description |
|---|---|---|
| type | string | Plan family to browse. |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| country | string | Filter inventory by ISO country code (e.g. `US`). |
| area_code | string | A desired 3-digit US area code. Repeat the parameter (or pass a comma-separated `area_codes`) to quote several. Only meaningful for `dedicated`/`inbound`. |
{
"type": "object",
"properties": {
"type": {
"enum": [
"shared",
"dedicated",
"inbound"
],
"type": "string",
"default": "shared",
"description": "Plan family to browse."
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"country": {
"type": "string",
"description": "Filter inventory by ISO country code (e.g. `US`)."
},
"area_code": {
"type": "string",
"description": "A desired 3-digit US area code. Repeat the parameter (or pass a comma-separated `area_codes`) to quote several. Only meaningful for `dedicated`/`inbound`."
}
},
"additionalProperties": false
}List calls The organization's calls, newest first. OAuth apps need `calls:read`.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
}
},
"additionalProperties": false
}List channels Lists messaging channels for the organization. Ordinary sends do not require a channel id; use this endpoint to inspect capabilities or obtain an exact channel id for advanced integrations.
| Argument | Type | Description |
|---|---|---|
| type | string | Filter by channel type. |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| status | string | Filter by channel status. |
{
"type": "object",
"properties": {
"type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string",
"description": "Filter by channel type."
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"status": {
"enum": [
"pending_verification",
"active",
"suspended",
"banned",
"deprecated"
],
"type": "string",
"description": "Filter by channel status."
}
},
"additionalProperties": false
}List chat messages Lists messages in a chat, newest first by default. Use `order=asc` for oldest first.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| order | string | |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"order": {
"enum": [
"asc",
"desc"
],
"type": "string",
"default": "desc"
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}List chats Lists conversations, most recent first. Filter by channel type, state, channel, or contact.
| Argument | Type | Description |
|---|---|---|
| type | string | |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| state | string | |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| channel_id | string | |
| contact_id | string |
{
"type": "object",
"properties": {
"type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string"
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"state": {
"enum": [
"open",
"closed",
"blocked",
"deprecated"
],
"type": "string"
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"channel_id": {
"type": "string"
},
"contact_id": {
"type": "string"
}
},
"additionalProperties": false
}List contact identities
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}List contact tags
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}List contacts Lists contacts. Cursor pagination is the default. Supplying `offset`, `q`, `tag`, `sort`, or `filter` switches to offset pagination and includes `pagination.total`.
| Argument | Type | Description |
|---|---|---|
| q | string | Case-insensitive search across contact names, identities, and tags. |
| tag | string | Case-insensitive tag filter. |
| sort | string | |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| filter | string | |
| offset | integer | Zero-based offset. Cannot be combined with cursor. |
| identifier | string | Filter to the contact owning this phone/email. |
List events Unified activity feed (message lifecycle, polls, groups, reactions, typing, payments, `safety.state_changed`, `safety.number_banned`). Filter by type, chat, or message.
| Argument | Type | Description |
|---|---|---|
| type | string | Event type or wildcard, e.g. `message.received` or `message.*`. |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| chat_id | string | |
| message_id | string |
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "Event type or wildcard, e.g. `message.received` or `message.*`."
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"chat_id": {
"type": "string"
},
"message_id": {
"type": "string"
}
},
"additionalProperties": false
}List group members For a merged group id, lists the members of the surviving group.
| Argument | Type | Description |
|---|---|---|
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}List groups
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
}
},
"additionalProperties": false
}List Find My contacts Lists Find My friends sharing their location with the linked Apple account.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}List message events Lifecycle events for a message (sent, delivered, read, reactions, ...).
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| message_id* | string | Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable. |
{
"type": "object",
"required": [
"chat_id",
"message_id"
],
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"message_id": {
"type": "string",
"description": "Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable."
}
},
"additionalProperties": false
}List sender numbers Lists the phone numbers / sender addresses available to this API key. Banned and suspended numbers stay in the list. `status` is `banned`, `suspended`, or `active`; a ban takes precedence when both apply. `is_active` is false when the line is banned, suspended, or the underlying account is blocked.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}List numbers Every number the organization rents from Blooio, newest first: iMessage lines and Blooio SMS and Blooio Voice numbers alike, one entry per number. `products` says what each does and `channels` lists the channel behind each product. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| products | string | Comma-separated `imessage`, `sms`, `voice`. Returns numbers carrying any of them; omit for every number. |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"products": {
"type": "string",
"description": "Comma-separated `imessage`, `sms`, `voice`. Returns numbers carrying any of them; omit for every number."
}
},
"additionalProperties": false
}List priorities Lists channel priorities owned by the calling API key.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
}
},
"additionalProperties": false
}List campaigns The organization's 10DLC campaigns, newest first. OAuth apps need `numbers:read`.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}List ticket comments Lists a ticket's public comments, oldest first: the request itself, replies from Blooio support, and your replies. OAuth apps need `tickets:read`.
| Argument | Type | Description |
|---|---|---|
| ticket_id* | string | Ticket id (`tkt_...`), returned when the ticket is opened. |
{
"type": "object",
"required": [
"ticket_id"
],
"properties": {
"ticket_id": {
"type": "string",
"pattern": "^tkt_",
"description": "Ticket id (`tkt_...`), returned when the ticket is opened."
}
},
"additionalProperties": false
}List tickets Lists the organization's support tickets, newest first. Includes call-forwarding requests opened with `POST /me/numbers/{number}/call-forwarding`. OAuth apps need `tickets:read`.
| Argument | Type | Description |
|---|---|---|
| type | string | Only tickets of this type, e.g. `call_forwarding`. |
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| status | string | Only tickets in this status. |
{
"type": "object",
"properties": {
"type": {
"enum": [
"purchase",
"purchase_failure",
"support",
"billing",
"technical",
"feature_request",
"call_forwarding",
"system"
],
"type": "string",
"description": "Only tickets of this type, e.g. `call_forwarding`."
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"status": {
"enum": [
"open",
"in_progress",
"waiting_on_customer",
"closed"
],
"type": "string",
"description": "Only tickets in this status."
}
},
"additionalProperties": false
}List webhook deliveries Recent delivery attempts for a webhook. Also available at `/webhooks/{webhookId}/logs`.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
{
"type": "object",
"required": [
"webhook_id"
],
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
}
},
"additionalProperties": false
}List webhook payload versions Every payload version a subscription can be set to, newest first, with what each one changed. New subscriptions default to the version marked `latest`. Set a subscription's version with `api_version` on create or update.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}List webhooks
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate. |
| cursor | string | Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request. |
{
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
}
},
"additionalProperties": false
}Look up a phone number Returns parsed info / geocoding for a phone number. Requires an enterprise plan.
| Argument | Type | Description |
|---|---|---|
| number* | string | Phone number in E.164. |
{
"type": "object",
"required": [
"number"
],
"properties": {
"number": {
"type": "string",
"description": "Phone number in E.164."
}
},
"additionalProperties": false
}Mark chat as read Sends a read receipt. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Get the authenticated account Returns the authenticated organization, linked devices/numbers, usage, and API key validity.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Merge a contact Collapses two auto-created contacts for the same person into one. The survivor is the `{contactId}` in the path; the `source_contact_id` in the body is absorbed into it. Every identity on the source is re-parented onto the survivor, tags are unioned, the survivor keeps its own name (falling back to the source's), and the source becomes a deprecated tombstone stamped with `merged_into`. Because chats and messages reference identities (not contacts), all conversations and timeline entries follow the moved identities automatically — nothing is rewritten or lost, and reads such as the survivor's timeline immediately reflect the merge. Idempotent: re-merging the same source into the same survivor returns 200; a source already merged into a different contact returns 409. Emits a `contact.merged` webhook event.
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
| source_contact_id* | string | The contact to merge into the survivor, prefixed with `ct_`. Must differ from the path contact. |
{
"type": "object",
"required": [
"contact_id",
"source_contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
},
"source_contact_id": {
"type": "string",
"description": "The contact to merge into the survivor, prefixed with `ct_`. Must differ from the path contact."
}
},
"additionalProperties": false
}Notify Anyway Breaks through the recipient's Focus for a message you sent, the same as tapping Notify Anyway in Messages. Use it when Read Focus status reports `silenced`. Calling it again for a message that was already notified succeeds. It cannot be undone. Returns 404 if the message isn't in the chat. Returns 409 for an inbound message, an SMS or RCS message, a message that hasn't been dispatched to the device yet, a group chat, or a non-Blooio channel.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| message_id* | string | Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable. |
{
"type": "object",
"required": [
"chat_id",
"message_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"message_id": {
"type": "string",
"description": "Unique identifier of the message — the `id` returned when you send a message or by the List messages endpoint. Outbound messages use a `msg_` id; inbound (received) messages use the id the List endpoint exposes for that row. Both are addressable."
}
},
"additionalProperties": false
}Place a call Call `to` from one of the organization's Blooio Voice numbers. The call starts `ringing`; when the callee answers, `handler` takes its audio and `call.answered` fires. With an `agent` handler, the Blooio agent that owns `from` talks to the callee. OAuth apps need `calls:write`.
| Argument | Type | Description |
|---|---|---|
| to* | string | The number to call, in E.164 format. |
| from* | string | One of the organization's Blooio Voice numbers, in E.164 format. |
| handler* | object | Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d… |
{
"type": "object",
"required": [
"from",
"to",
"handler"
],
"properties": {
"to": {
"type": "string",
"description": "The number to call, in E.164 format."
},
"from": {
"type": "string",
"description": "One of the organization's Blooio Voice numbers, in E.164 format."
},
"handler": {
"type": "object",
"required": [
"type"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "`stream` only, required: a `wss://` URL."
},
"type": {
"enum": [
"stream",
"agent",
"softphone"
],
"type": "string"
},
"auth_token": {
"type": "string",
"maxLength": 4000,
"description": "`stream` only: sent as `Authorization: Bearer <auth_token>` when Blooio connects to `url`. Kept with the live call only and never returned."
}
},
"description": "Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d…"
}
},
"additionalProperties": false
}Purchase Blooio numbers Purchase one or more Blooio lines. Purchases are asynchronous and billable: the call charges the organization's default payment method and returns a `purchase_id`; the lines are provisioned when Stripe confirms the invoice, at which point a `number.purchase.completed` webhook fires (or `number.purchase.failed`). A card requiring 3DS/SCA returns `status: action_required` with an `action_url`, and also emits `number.purchase.action_required`.
| Argument | Type | Description |
|---|---|---|
| plan* | string | Plan id to purchase (determines shared / dedicated / inbound). Use the specific id, not the tier name — e.g. `dedicated_com` or `dedicated_ent`, not `dedicated` (which returns `invalid_plan`). |
| quantity | integer | Number of new lines (dedicated/inbound). Shared is always 1. |
| zip_codes | array | Preferred ZIP codes (dedicated/inbound), used when an area code is not specified. |
| area_codes | array | Preferred 3-digit US area codes (dedicated/inbound). Out-of-stock codes incur a custom fee and open a ticket. |
| idempotencyKey* | string | Unique key that makes the billable purchase safe to retry. |
{
"type": "object",
"required": [
"idempotencyKey",
"plan"
],
"properties": {
"plan": {
"enum": [
"shared_nc",
"shared_com",
"dedicated_com",
"dedicated_ent",
"inbound_basic"
],
"type": "string",
"description": "Plan id to purchase (determines shared / dedicated / inbound). Use the specific id, not the tier name — e.g. `dedicated_com` or `dedicated_ent`, not `dedicated` (which returns `invalid_plan`)."
},
"quantity": {
"type": "integer",
"default": 1,
"minimum": 1,
"description": "Number of new lines (dedicated/inbound). Shared is always 1."
},
"zip_codes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Preferred ZIP codes (dedicated/inbound), used when an area code is not specified."
},
"area_codes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Preferred 3-digit US area codes (dedicated/inbound). Out-of-stock codes incur a custom fee and open a ticket."
},
"idempotencyKey": {
"type": "string",
"description": "Unique key that makes the billable purchase safe to retry."
}
},
"additionalProperties": false
}Register the brand Register the organization's brand, or resubmit it with corrected details. The registry reviews it asynchronously; `registration.brand.updated` fires as its `status` changes. A `SOLE_PROPRIETOR` brand must then verify its mobile number (`requires_otp`). OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| ein | string | US Employer Identification Number. Required for every entity type but `SOLE_PROPRIETOR`. |
| city | string | City. |
| email* | string | Contact email for the registration. |
| phone | string | Business phone number. |
| state | string | State or region code. |
| street | string | Street address. |
| country* | string | Two-letter country code, e.g. `US`. |
| website | string | The brand's website. |
| vertical* | string | Industry vertical; one of the `verticals` values from `GET /10dlc/options`. |
Refresh Find My locations Forces a refresh of Find My location data from the device.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Release a number Give a number up. A Blooio SMS or Blooio Voice number is released to the carrier at once and its channels retired; `number.removed` fires for each channel. An iMessage line is removed the same way as `DELETE /channels/{channel}`. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| number* | string | The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`). |
{
"type": "object",
"required": [
"number"
],
"properties": {
"number": {
"type": "string",
"description": "The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`)."
}
},
"additionalProperties": false
}Remove (unsubscribe) a Blooio number Removes/unsubscribes an owned Blooio line, cancelling its subscription — the same flow as the dashboard unsubscribe button. Accepts either the E.164 number or the `ch_` channel id as `{channel}`. A `reasons` array (why the customer is unsubscribing) is required; the same reason handling updates the CRM, posts to Slack, and emits a `number.removed` webhook. Requires the `numbers:manage` scope for OAuth apps.
| Argument | Type | Description |
|---|---|---|
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
| reasons* | array | One or more churn reason codes/labels for the removal. |
{
"type": "object",
"required": [
"channel",
"reasons"
],
"properties": {
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
},
"reasons": {
"type": "array",
"items": {
"type": "string"
},
"description": "One or more churn reason codes/labels for the removal."
}
},
"additionalProperties": false
}Remove chat background
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Detach an identity
| Argument | Type | Description |
|---|---|---|
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
| identity_id* | string | Unique identifier of the contact identity (a phone/email tied to the contact), prefixed with `cid_`. Returned by the List contact identities endpoint. |
{
"type": "object",
"required": [
"contact_id",
"identity_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
},
"identity_id": {
"type": "string",
"description": "Unique identifier of the contact identity (a phone/email tied to the contact), prefixed with `cid_`. Returned by the List contact identities endpoint."
}
},
"additionalProperties": false
}Remove a contact tag
| Argument | Type | Description |
|---|---|---|
| tag* | string | The tag to remove from the contact. URL-encode values that contain spaces or special characters. |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id",
"tag"
],
"properties": {
"tag": {
"type": "string",
"description": "The tag to remove from the contact. URL-encode values that contain spaces or special characters."
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}Remove group icon
| Argument | Type | Description |
|---|---|---|
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}Replay a webhook delivery Re-sends a past delivery. Also available at `/webhooks/{webhookId}/logs/{deliveryId}/replay`.
| Argument | Type | Description |
|---|---|---|
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
| delivery_id* | string | Unique identifier of the webhook delivery attempt, prefixed with `wdel_`. Returned by the List webhook deliveries endpoint. |
{
"type": "object",
"required": [
"webhook_id",
"delivery_id"
],
"properties": {
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
},
"delivery_id": {
"type": "string",
"description": "Unique identifier of the webhook delivery attempt, prefixed with `wdel_`. Returned by the List webhook deliveries endpoint."
}
},
"additionalProperties": false
}Request call forwarding Opens a support ticket to forward calls from an owned dedicated or inbound Blooio number. The destination must be a US E.164 number. Shared or foreign source numbers are rejected. Forwarding isn't instant: check its progress with `GET /tickets/{ticket_id}` using the returned `ticket_id`, whose `forwarding.state` reaches `completed` when calls forward. OAuth apps need `numbers:manage` to open the request and `tickets:read` to check it.
| Argument | Type | Description |
|---|---|---|
| number* | string | Sender phone number in E.164 format, e.g. `+15551234567`. |
| forward_to* | string | US E.164 number to forward calls to. |
{
"type": "object",
"required": [
"number",
"forward_to"
],
"properties": {
"number": {
"type": "string",
"description": "Sender phone number in E.164 format, e.g. `+15551234567`."
},
"forward_to": {
"type": "string",
"pattern": "^\\+1[2-9]\\d{9}$",
"description": "US E.164 number to forward calls to."
}
},
"additionalProperties": false
}Rotate webhook signing secret Rotates and returns a new signing secret (once).
| Argument | Type | Description |
|---|---|---|
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
{
"type": "object",
"required": [
"webhook_id"
],
"properties": {
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
}
},
"additionalProperties": false
}Search available numbers US local numbers you can buy that support every product in `products`. Results are live inventory: a number can be taken between the search and the purchase. OAuth apps need `numbers:read`.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Maximum numbers to return. |
| region | string | Two-letter US state code. |
| contains | string | Digits the number contains. |
| locality | string | City. |
| products* | string | Comma-separated `sms`, `voice`. |
| area_code | string | Three-digit US area code. |
{
"type": "object",
"required": [
"products"
],
"properties": {
"limit": {
"type": "integer",
"default": 20,
"maximum": 50,
"minimum": 1,
"description": "Maximum numbers to return."
},
"region": {
"type": "string",
"pattern": "^[A-Z]{2}$",
"description": "Two-letter US state code."
},
"contains": {
"type": "string",
"pattern": "^\\d{1,10}$",
"description": "Digits the number contains."
},
"locality": {
"type": "string",
"description": "City."
},
"products": {
"type": "string",
"description": "Comma-separated `sms`, `voice`."
},
"area_code": {
"type": "string",
"pattern": "^[2-9]\\d{2}$",
"description": "Three-digit US area code."
}
},
"additionalProperties": false
}Send DTMF Play keypad tones into a connected call, to navigate a phone menu for example. OAuth apps need `calls:write`.
| Argument | Type | Description |
|---|---|---|
| digits* | string | Keypad digits to play into the call. `w` pauses half a second, `W` a second. |
| call_id* | string | Call id (`call_...`). |
{
"type": "object",
"required": [
"call_id",
"digits"
],
"properties": {
"digits": {
"type": "string",
"pattern": "^[0-9A-D*#wW]{1,64}$",
"description": "Keypad digits to play into the call. `w` pauses half a second, `W` a second."
},
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
}
},
"additionalProperties": false
}Send a message to a chat Sends a message into an existing chat. Both the sender channel and recipient are inferred from the chat, so `from` and `to` must not be supplied. Returns the message object at the top level (not wrapped in `data`).
| Argument | Type | Description |
|---|---|---|
| poll | object | A native Blooio poll. Routed sends automatically consider only poll-capable channels. |
| text | string | Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: "markdown"` to interpret Markdown styling in this field (and in `parts[].text`). |
| badge | string | Optional attribution badge shown under the bubble: `sent_with_siri` renders "Sent with Siri" and `sent_with_facetime` renders "Sent with FaceTime", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B… |
| parts | array | Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: "markdown"`, each part's `text` is parsed for styling independently. |
| effect | string | iMessage screen/bubble effect (Blooio, text only). |
| format |
Send a message The primary endpoint for starting a message. The common send is entirely scalar: `{ "from": "+15551230001", "to": "+15551234567", "text": "Hello" }`.
| Argument | Type | Description |
|---|---|---|
| to* | any | A recipient: a raw identifier string (phone/email/opaque provider id), an array of identifier strings (multiple recipients), an existing `{ group_id }` with an exact sender, or (for routed sends) a `{ contact_id }`. A `contact_id` enables cross-channel-type routing via the contact's identities; a bare identifier reaches phone/email-addressable channels only. |
| from | string | The sender as a single string: a phone number (any common format; matched to your exact numbered channel), a channel alias (organization-wide name of a non-numbered channel), or an exact channel id (ch_...). Omit it for automatic routing. If a phone number ever matches more than one active channel type, the send fails with `409 ambiguous_from` and the exact `ch_...` id must be used instead. |
| poll | object | A native Blooio poll. Routed sends automatically consider only poll-capable channels. |
| text | string | Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: "markdown"` to interpret Markdown styling in this field (and in `parts[].text`). |
| badge | string | Optional attribution badge shown under the bubble: `sent_with_siri` renders "Sent with Siri" and `sent_with_facetime` renders "Sent with FaceTime", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B… |
Send a message on a specific channel Channel-scoped equivalent of `POST /messages` with an explicit `from`: `:channel` accepts the same phone number (URL-encode `+` as `%2B`), alias, or `ch_...` value `from` accepts, and the body omits `from`. Multiple recipients on a group-capable channel (blooio/whatsapp) form a single group thread; on other channels they fan out to individual sends (max 100).
| Argument | Type | Description |
|---|---|---|
| to* | any | A recipient: a raw identifier string (phone/email/opaque provider id), an array of identifier strings (multiple recipients), an existing `{ group_id }` with an exact sender, or (for routed sends) a `{ contact_id }`. A `contact_id` enables cross-channel-type routing via the contact's identities; a bare identifier reaches phone/email-addressable channels only. |
| poll | object | A native Blooio poll. Routed sends automatically consider only poll-capable channels. |
| text | string | Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: "markdown"` to interpret Markdown styling in this field (and in `parts[].text`). |
| badge | string | Optional attribution badge shown under the bubble: `sent_with_siri` renders "Sent with Siri" and `sent_with_facetime` renders "Sent with FaceTime", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B… |
| parts |
Send a poll Sends a native iMessage poll to a chat. Requires a title and 2+ options. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| title* | string | |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| options* | array |
{
"type": "object",
"required": [
"chat_id",
"title",
"options"
],
"properties": {
"title": {
"type": "string"
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"options": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 2
}
},
"additionalProperties": false
}Send the brand verification PIN Text a verification PIN to a `SOLE_PROPRIETOR` brand's `mobile_phone`. OAuth apps need `numbers:manage`.
No arguments.
{
"type": "object",
"properties": {},
"additionalProperties": false
}Set chat background Uploads a chat background image. Max 10MB; image/jpeg|png|gif|webp|heic|heif. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| background* | string | Public URL of the file to upload. |
{
"type": "object",
"required": [
"chat_id",
"background"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"background": {
"type": "string",
"description": "Public URL of the file to upload."
}
},
"additionalProperties": false
}Set group icon Uploads a group icon. Max 10MB; image/jpeg|png|gif|webp|heic|heif. Requires the group chat to be linked on a device.
| Argument | Type | Description |
|---|---|---|
| icon* | string | Public URL of the file to upload. |
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id",
"icon"
],
"properties": {
"icon": {
"type": "string",
"description": "Public URL of the file to upload."
},
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}Start/stop typing indicator Shows or clears a business-to-customer typing indicator. Supported on Blooio channels and Apple Messages for Business.
| Argument | Type | Description |
|---|---|---|
| state | string | |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"state": {
"enum": [
"started",
"stopped"
],
"type": "string",
"default": "started"
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Share contact card Shares the sender's contact card into a chat. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Stop typing indicator Clears the business-to-customer typing indicator. Supported on Blooio channels and Apple Messages for Business.
| Argument | Type | Description |
|---|---|---|
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Transfer a call Move a connected call to another handler, or to the phone number `to`, which takes it off Blooio once that number answers. A call a Blooio agent handed off can be transferred too. A transfer that fails partway, or a number that doesn't answer, leaves the call waiting for a teammate, as a handed-off call does. OAuth apps need `calls:write`.
| Argument | Type | Description |
|---|---|---|
| to | string | Transfer the call to this phone number (E.164). It leaves Blooio's handlers once the number answers; if it doesn't, the call waits for a teammate. |
| call_id* | string | Call id (`call_...`). |
| handler | object | Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d… |
{
"type": "object",
"required": [
"call_id"
],
"properties": {
"to": {
"type": "string",
"description": "Transfer the call to this phone number (E.164). It leaves Blooio's handlers once the number answers; if it doesn't, the call waits for a teammate."
},
"call_id": {
"type": "string",
"pattern": "^call_",
"description": "Call id (`call_...`)."
},
"handler": {
"type": "object",
"required": [
"type"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "`stream` only, required: a `wss://` URL."
},
"type": {
"enum": [
"stream",
"agent",
"softphone"
],
"type": "string"
},
"auth_token": {
"type": "string",
"maxLength": 4000,
"description": "`stream` only: sent as `Authorization: Bearer <auth_token>` when Blooio connects to `url`. Kept with the live call only and never returned."
}
},
"description": "Who takes the call's audio once it's answered. `stream`: Blooio opens a WebSocket to `url` and speaks the Blooio media stream protocol (base64 PCMU at 8 kHz both ways; see the Blooio Voice guide); a socket that closes or sends a frame the protocol doesn't define ends the call with `handler_disconnected`. `agent`: the Blooio agent that owns the call's number talks to the caller. `softphone`: the d…"
}
},
"additionalProperties": false
}Update channel profile Partial update of the channel profile (`display_name`, `about`, `email`, `avatar`). Stored under `metadata.profile` and returned on `GET /channels/{channel}`. Null or empty string clears a field. Unknown keys are rejected. This writes Blooio metadata only; it does not push a display name to the device.
| Argument | Type | Description |
|---|---|---|
| about | string | null | |
| string | null | ||
| avatar | string | null | |
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
| display_name | string | null |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"about": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
},
"avatar": {
"type": [
"string",
"null"
]
},
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
},
"display_name": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}Update channel settings Partial update of a channel's settings (send only the keys you want to change). Keys are per channel type. Blooio (P2P numbers): `auto_mark_read` is available on dedicated and inbound lines; `auto_share_contact` is dedicated-only AND the line must have a contact card (name or photo) set up; `imessage_only` is available on every line. Apple Messages for Business and WhatsApp Business: `opener`, a partial update of the channel's opener (send only the fields you want to change). Blooio Voice: `inbound`, with `handler` (`softphone`, `agent`, or `api`) and `ring_timeout_seconds` (5 to 120); `agent` needs a live Blooio agent that owns the number. Turning a setting OFF is always allowed. Errors return a machine-readable `code`: `settings_unsupported_for_channel_type` (403, a channel type without settings), `auto_mark_read_not_allowed` / `auto_share_contact_not_allowed` (403, line type can't enable it), `contact_card_not_set_up` (403, enable auto_share_contact with no contact card), `agent_unavailable` (409, the `agent` handler on a number no live Blooio agent owns), `no_settings_provided` (422, empty update), `invalid_settings` (422, unknown key or field, a value of the wrong type, or an…
| Argument | Type | Description |
|---|---|---|
| opener | any | Apple Messages for Business or WhatsApp Business: a partial update of the channel's opener, merged into the saved one. Turning it on validates the template. |
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
| inbound | object | Who answers a Blooio Voice number's inbound calls. |
| imessage_only | boolean | Blooio: a routed send (`POST /messages` without `from`) starts a conversation on this line only with a contact on iMessage, checked on the line's device; a contact who isn't, or a device that can't answer, moves the send to the next channel in the priority. Conversations the line already has are unaffected. Off by default, when the device sends SMS to a contact without iMessage. |
Update a chat Sets chat state (`open`/`closed`) on an Apple Messages for Business chat. Chats on every other channel return 422 `state_not_writable`: `closed` reflects the customer ending an Apple Messages for Business conversation, and no other protocol has an equivalent.
| Argument | Type | Description |
|---|---|---|
| state | string | Apple Messages for Business chats only. `closed` blocks further sends to the chat with 409 `chat_closed_by_user`; an Apple Messages for Business chat also closes itself when the customer ends the conversation, and reopens when they message again. |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"state": {
"enum": [
"open",
"closed"
],
"type": "string",
"description": "Apple Messages for Business chats only. `closed` blocks further sends to the chat with 409 `chat_closed_by_user`; an Apple Messages for Business chat also closes itself when the customer ends the conversation, and reopens when they message again."
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
}
},
"additionalProperties": false
}Update a contact
| Argument | Type | Description |
|---|---|---|
| name* | string | |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
{
"type": "object",
"required": [
"contact_id",
"name"
],
"properties": {
"name": {
"type": "string"
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
}
},
"additionalProperties": false
}Update a number's contact card Updates the contact card (name, avatar, sharing settings) shared from this number. At least one field is required.
| Argument | Type | Description |
|---|---|---|
| avatar | string | null | Base64 image or data URI (`data:image/png;base64,...`). `null` removes the photo; lines that cannot clear a photo show a plain black image instead. |
| number* | string | Sender phone number in E.164 format, e.g. `+15551234567`. |
| sharing | object | |
| last_name | string | |
| first_name | string |
{
"type": "object",
"required": [
"number"
],
"properties": {
"avatar": {
"type": [
"string",
"null"
],
"description": "Base64 image or data URI (`data:image/png;base64,...`). `null` removes the photo; lines that cannot clear a photo show a plain black image instead."
},
"number": {
"type": "string",
"description": "Sender phone number in E.164 format, e.g. `+15551234567`."
},
"sharing": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"audience": {
"enum": [
0,
1
],
"type": "integer",
"description": "0 = Contacts Only, 1 = Always Ask"
},
"name_format": {
"enum": [
0,
1
],
"type": "integer",
"description": "0 = First & Last, 1 = First Only"
}
}
},
"last_name": {
"type": "string"
},
"first_name": {
"type": "string"
}
},
"additionalProperties": false
}Update an identity Renames a contact identity in place. An optional name updates the parent contact in the same request.
| Argument | Type | Description |
|---|---|---|
| name | string | null | |
| contact_id* | string | Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint. |
| identifier* | string | |
| identity_id* | string | Unique identifier of the contact identity, prefixed with `cid_`. |
{
"type": "object",
"required": [
"contact_id",
"identity_id",
"identifier"
],
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"contact_id": {
"type": "string",
"description": "Unique identifier of the contact, prefixed with `ct_`. Returned when you create a contact or by the List contacts endpoint."
},
"identifier": {
"type": "string"
},
"identity_id": {
"type": "string",
"description": "Unique identifier of the contact identity, prefixed with `cid_`."
}
},
"additionalProperties": false
}Update a group
| Argument | Type | Description |
|---|---|---|
| name* | string | |
| group_id* | string | Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint. |
{
"type": "object",
"required": [
"group_id",
"name"
],
"properties": {
"name": {
"type": "string"
},
"group_id": {
"type": "string",
"description": "Unique identifier of the group, prefixed with `grp_`. Returned by the List groups endpoint."
}
},
"additionalProperties": false
}Update a number Turn a Blooio SMS or Blooio Voice number's products on and off, or assign its SMS channel to a 10DLC campaign. Turning `sms` off takes the number off its campaign. iMessage lines can't be changed here. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| number* | string | The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`). |
| products | array | The products the number should carry from now on. A product you leave out is turned off and its channel retired; one you add gets a new channel. |
| campaign_id | string | Assign the number's SMS channel to this 10DLC campaign (`camp_...`). The campaign must be provisioned by carriers (`mno_provisioned`). |
{
"type": "object",
"required": [
"number"
],
"properties": {
"number": {
"type": "string",
"description": "The number in E.164 format, with `+` URL-encoded as `%2B` (e.g. `%2B15551234567`)."
},
"products": {
"type": "array",
"items": {
"enum": [
"sms",
"voice"
],
"type": "string",
"description": "A product you can buy a number for and turn on and off: `sms` (Blooio SMS) or `voice` (Blooio Voice)."
},
"minItems": 1,
"description": "The products the number should carry from now on. A product you leave out is turned off and its channel retired; one you add gets a new channel."
},
"campaign_id": {
"type": "string",
"description": "Assign the number's SMS channel to this 10DLC campaign (`camp_...`). The campaign must be provisioned by carriers (`mno_provisioned`)."
}
},
"additionalProperties": false
}Update a priority Updates a priority's name, default flag, and/or channel set. When `channels` is supplied it replaces the priority's channels wholesale.
| Argument | Type | Description |
|---|---|---|
| name | string | |
| channels | array | |
| settings | object | Settings to change. A setting set to null returns to the owner's default; unknown keys are rejected with `422 invalid_settings`. |
| is_default | boolean | |
| priority_id* | string | Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint. |
{
"type": "object",
"required": [
"priority_id"
],
"properties": {
"name": {
"type": "string"
},
"channels": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"channel_id"
],
"properties": {
"priority": {
"type": "integer",
"minimum": 1
},
"channel_id": {
"type": "string"
}
}
}
]
},
"minItems": 1
},
"settings": {
"type": "object",
"properties": {
"steps": {
"type": [
"object",
"null"
],
"description": "Replaces every step rule; null clears them. A rule must name a step the priority's channels have, so send `steps` together with `channels` when renumbering steps; otherwise `422 invalid_settings`.",
"additionalProperties": {
"type": "object",
"description": "`outreach_only` marks a step for contacts who haven't replied. Once a contact has replied on a channel in the priority, the step goes last (tried only when every other step passes the send over) and the contact's history on it doesn't choose the channel. `transition` is a message sent with the first message a contact reached on this step gets from the next step: `pre` sends it first, `post` right…"
}
},
"on_banned_sticky": {
"enum": [
"switch_number",
"error",
null
],
"type": [
"string",
"null"
]
}
},
"description": "Settings to change. A setting set to null returns to the owner's default; unknown keys are rejected with `422 invalid_settings`.",
"additionalProperties": false
},
"is_default": {
"type": "boolean"
},
"priority_id": {
"type": "string",
"description": "Unique identifier of the priority, prefixed with `priority_`. Returned when you create a priority or by the List priorities endpoint."
}
},
"additionalProperties": false
}Update campaign samples Replace a campaign's sample messages, the field carriers most often ask to change. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| samples* | array | Example messages, as recipients will see them. |
| campaign_id* | string | 10DLC campaign id (`camp_...`). |
{
"type": "object",
"required": [
"campaign_id",
"samples"
],
"properties": {
"samples": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 5,
"minItems": 2,
"description": "Example messages, as recipients will see them."
},
"campaign_id": {
"type": "string",
"pattern": "^camp_",
"description": "10DLC campaign id (`camp_...`)."
}
},
"additionalProperties": false
}Update a ticket's status Changes a ticket's status, for example to close a request you no longer need. Only `status` can change: `priority` is set by Blooio support and returns `422 priority_not_allowed`. Purchase, system, and billing tickets are managed by Blooio and return `403`. OAuth apps need `tickets:write`.
| Argument | Type | Description |
|---|---|---|
| status* | string | `open`: not picked up yet. `in_progress`: Blooio support is working on it. `waiting_on_customer`: support needs a reply from you. `closed`: resolved. |
| ticket_id* | string | Ticket id (`tkt_...`), returned when the ticket is opened. |
{
"type": "object",
"required": [
"ticket_id",
"status"
],
"properties": {
"status": {
"enum": [
"open",
"in_progress",
"waiting_on_customer",
"closed"
],
"type": "string",
"description": "`open`: not picked up yet. `in_progress`: Blooio support is working on it. `waiting_on_customer`: support needs a reply from you. `closed`: resolved."
},
"ticket_id": {
"type": "string",
"pattern": "^tkt_",
"description": "Ticket id (`tkt_...`), returned when the ticket is opened."
}
},
"additionalProperties": false
}Update a webhook Updates url, status (`active`/`disabled`), or the payload `api_version`. A version change applies to the next event delivered; deliveries already made, and replays of them, keep the version they were sent with.
| Argument | Type | Description |
|---|---|---|
| url | string | |
| status | string | |
| webhook_id* | string | Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint. |
| api_version | any | Move the subscription to another payload version, for example to upgrade after updating your handler. Takes effect from the next event. Unsupported values are rejected with 422 `invalid_api_version`. |
| event_types | array | Retired. Omit this field to leave an existing subscription's frozen list untouched; sending anything narrower than `["*"]` is rejected with 422 `event_types_retired`. |
{
"type": "object",
"required": [
"webhook_id"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"status": {
"enum": [
"active",
"disabled"
],
"type": "string"
},
"webhook_id": {
"type": "string",
"description": "Unique identifier of the webhook subscription, prefixed with `wh_`. Returned when you create a webhook or by the List webhooks endpoint."
},
"api_version": {
"allOf": [
{
"enum": [
"2026-10-01",
"2026-09-01"
],
"type": "string",
"description": "A webhook payload version, as a release date. `2026-10-01` is the latest."
}
],
"description": "Move the subscription to another payload version, for example to upgrade after updating your handler. Takes effect from the next event. Unsupported values are rejected with 422 `invalid_api_version`."
},
"event_types": {
"type": "array",
"items": {
"type": "string"
},
"deprecated": true,
"description": "Retired. Omit this field to leave an existing subscription's frozen list untouched; sending anything narrower than `[\"*\"]` is rejected with 422 `event_types_retired`."
}
},
"additionalProperties": false
}Upload a contact card avatar Uploads an avatar image for the number's contact card. Max 10MB.
| Argument | Type | Description |
|---|---|---|
| avatar* | string | Public URL of the file to upload. |
| number* | string | Sender phone number in E.164 format, e.g. `+15551234567`. |
| last_name | string | Optional. See first_name. |
| first_name | string | Optional. Sent to the device with the photo so the write is not photo-only. Recommended: without it the device keeps whatever name it currently has. |
{
"type": "object",
"required": [
"number",
"avatar"
],
"properties": {
"avatar": {
"type": "string",
"description": "Public URL of the file to upload."
},
"number": {
"type": "string",
"description": "Sender phone number in E.164 format, e.g. `+15551234567`."
},
"last_name": {
"type": "string",
"description": "Optional. See first_name."
},
"first_name": {
"type": "string",
"description": "Optional. Sent to the device with the photo so the write is not photo-only. Recommended: without it the device keeps whatever name it currently has."
}
},
"additionalProperties": false
}Verify the brand PIN Submit the PIN texted by `POST /10dlc/brand/otp`. OAuth apps need `numbers:manage`.
| Argument | Type | Description |
|---|---|---|
| pin* | string |
{
"type": "object",
"required": [
"pin"
],
"properties": {
"pin": {
"type": "string",
"pattern": "^\\d{4,8}$"
}
},
"additionalProperties": false
}Vote on a poll Casts or toggles a vote by `option_index` (0-based) or `option` text. Blooio channels only.
| Argument | Type | Description |
|---|---|---|
| option | string | Option text. |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| poll_id* | string | Unique identifier of the poll, prefixed with `msg_` (a poll shares the id of its underlying message). |
| option_index | integer | 0-based option index. |
{
"type": "object",
"required": [
"chat_id",
"poll_id"
],
"properties": {
"option": {
"type": "string",
"description": "Option text."
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"poll_id": {
"type": "string",
"description": "Unique identifier of the poll, prefixed with `msg_` (a poll shares the id of its underlying message)."
},
"option_index": {
"type": "integer",
"description": "0-based option index."
}
},
"additionalProperties": false
}We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Oct 31, 2026.
Takes a password, API key or token as an argument, so the secret passes through the model's context and chat logs.
Fix: Read credentials from the server's own configuration (environment, OAuth) instead of a tool argument.
| Sub use case codes, for use cases that take them (`MIXED`, for one). `GET /10dlc/usecases/{usecase}/qualification` says how many. |
| embedded_link | boolean | Messages contain links. |
| help_keywords | array | Keywords that get the HELP reply. |
| optin_message | string | The reply when someone opts in. |
| direct_lending | boolean | The campaign is about direct lending or loans. |
| embedded_phone | boolean | Messages contain phone numbers. |
| optin_keywords | array | Keywords that opt a recipient in. |
| optout_message | string | The reply to STOP. |
| optout_keywords | array | Keywords that opt a recipient out. |
| subscriber_help* | boolean | Recipients can get help by replying HELP. |
| subscriber_optin* | boolean | Recipients opt in before they're messaged. |
| subscriber_optout* | boolean | Recipients can opt out. |
| privacy_policy_link | string | URL of the privacy policy. |
| embedded_link_sample | string | A sample of the links messages contain, when `embedded_link` is true. |
| terms_and_conditions* | boolean | You accept the carriers' 10DLC terms. Must be `true`. |
| terms_and_conditions_link | string | URL of the terms and conditions. |
{
"type": "object",
"required": [
"usecase",
"samples",
"description",
"message_flow",
"subscriber_optin",
"subscriber_optout",
"subscriber_help",
"terms_and_conditions"
],
"properties": {
"samples": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 5,
"minItems": 2,
"description": "Example messages, as recipients will see them."
},
"usecase": {
"type": "string",
"description": "Use case code; one of the `use_cases` values from `GET /10dlc/options`, e.g. `MARKETING`."
},
"age_gated": {
"type": "boolean",
"description": "Content is age-gated (alcohol, for example)."
},
"description": {
"type": "string",
"description": "What the campaign sends and why."
},
"number_pool": {
"type": "boolean",
"description": "The campaign sends from a pool of more than 49 numbers."
},
"help_message": {
"type": "string",
"description": "The reply to HELP."
},
"message_flow": {
"type": "string",
"description": "How recipients opt in: where they give consent and what they're told."
},
"sub_usecases": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 5,
"minItems": 1,
"description": "Sub use case codes, for use cases that take them (`MIXED`, for one). `GET /10dlc/usecases/{usecase}/qualification` says how many."
},
"embedded_link": {
"type": "boolean",
"description": "Messages contain links."
},
"help_keywords": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[A-Z0-9]{1,20}$"
},
"maxItems": 10,
"minItems": 1,
"description": "Keywords that get the HELP reply."
},
"optin_message": {
"type": "string",
"description": "The reply when someone opts in."
},
"direct_lending": {
"type": "boolean",
"description": "The campaign is about direct lending or loans."
},
"embedded_phone": {
"type": "boolean",
"description": "Messages contain phone numbers."
},
"optin_keywords": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[A-Z0-9]{1,20}$"
},
"maxItems": 10,
"minItems": 1,
"description": "Keywords that opt a recipient in."
},
"optout_message": {
"type": "string",
"description": "The reply to STOP."
},
"optout_keywords": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[A-Z0-9]{1,20}$"
},
"maxItems": 10,
"minItems": 1,
"description": "Keywords that opt a recipient out."
},
"subscriber_help": {
"type": "boolean",
"description": "Recipients can get help by replying HELP."
},
"subscriber_optin": {
"type": "boolean",
"description": "Recipients opt in before they're messaged."
},
"subscriber_optout": {
"type": "boolean",
"description": "Recipients can opt out."
},
"privacy_policy_link": {
"type": "string",
"description": "URL of the privacy policy."
},
"embedded_link_sample": {
"type": "string",
"description": "A sample of the links messages contain, when `embedded_link` is true."
},
"terms_and_conditions": {
"type": "boolean",
"description": "You accept the carriers' 10DLC terms. Must be `true`."
},
"terms_and_conditions_link": {
"type": "string",
"description": "URL of the terms and conditions."
}
},
"additionalProperties": false
}{
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "HTTPS endpoint."
},
"api_key": {
"type": "string",
"description": "Scope the subscription to the lines this API key owns. Omit `api_key` and `integration_id` for an organization-wide subscription that receives events from every line. Must belong to your organization; sending both is rejected with 422 `ambiguous_scope`."
},
"channel_id": {
"type": "string"
},
"api_version": {
"allOf": [
{
"enum": [
"2026-10-01",
"2026-09-01"
],
"type": "string",
"description": "A webhook payload version, as a release date. `2026-10-01` is the latest."
}
],
"description": "The payload version to deliver. Defaults to the latest. Anything not listed by `GET /webhooks/versions` is rejected with 422 `invalid_api_version`, whose `details.supported_versions` lists the accepted values."
},
"event_types": {
"type": "array",
"items": {
"type": "string"
},
"deprecated": true,
"description": "Retired. Every webhook receives every event; filter by `type` in your handler. Omit this field, or send `[\"*\"]`. Any narrower value is rejected with 422 `event_types_retired`. Subscriptions created before the retirement keep the list they were registered with."
},
"channel_type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string"
},
"integration_id": {
"type": "string",
"description": "Scope the subscription to the lines this integration owns. Mutually exclusive with `api_key`."
}
},
"additionalProperties": false
}{
"type": "object",
"properties": {
"q": {
"type": "string",
"description": "Case-insensitive search across contact names, identities, and tags."
},
"tag": {
"type": "string",
"description": "Case-insensitive tag filter."
},
"sort": {
"enum": [
"recent",
"oldest",
"name_asc",
"name_desc"
],
"type": "string"
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of items to return per page. Must be between 1 and 200; defaults to 50. Combine with `cursor` to paginate."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor. Pass the `next_cursor` value from a previous response to fetch the next page; omit it on the first request."
},
"filter": {
"enum": [
"none",
"has_tags",
"no_tags",
"inbound_last",
"outbound_last"
],
"type": "string"
},
"offset": {
"type": "integer",
"minimum": 0,
"description": "Zero-based offset. Cannot be combined with cursor."
},
"identifier": {
"type": "string",
"description": "Filter to the contact owning this phone/email."
}
},
"additionalProperties": false
}| last_name | string | Required for `SOLE_PROPRIETOR`. |
| first_name | string | Required for `SOLE_PROPRIETOR`. |
| entity_type* | string |
| postal_code | string | Postal code. |
| company_name | string | Legal company name. Required for every entity type but `SOLE_PROPRIETOR`. |
| display_name* | string | The brand name recipients know you by. |
| mobile_phone | string | Required for `SOLE_PROPRIETOR`: the mobile number that receives the verification PIN. |
| stock_symbol | string | Required for `PUBLIC_PROFIT`. |
| stock_exchange | string | Required for `PUBLIC_PROFIT`, e.g. `NASDAQ`. |
| business_contact_email | string | Required for `PUBLIC_PROFIT`: the email the registry verifies the company through. |
{
"type": "object",
"required": [
"entity_type",
"display_name",
"email",
"country",
"vertical"
],
"properties": {
"ein": {
"type": "string",
"description": "US Employer Identification Number. Required for every entity type but `SOLE_PROPRIETOR`."
},
"city": {
"type": "string",
"description": "City."
},
"email": {
"type": "string",
"description": "Contact email for the registration."
},
"phone": {
"type": "string",
"description": "Business phone number."
},
"state": {
"type": "string",
"description": "State or region code."
},
"street": {
"type": "string",
"description": "Street address."
},
"country": {
"type": "string",
"description": "Two-letter country code, e.g. `US`."
},
"website": {
"type": "string",
"description": "The brand's website."
},
"vertical": {
"type": "string",
"description": "Industry vertical; one of the `verticals` values from `GET /10dlc/options`."
},
"last_name": {
"type": "string",
"description": "Required for `SOLE_PROPRIETOR`."
},
"first_name": {
"type": "string",
"description": "Required for `SOLE_PROPRIETOR`."
},
"entity_type": {
"enum": [
"PRIVATE_PROFIT",
"PUBLIC_PROFIT",
"NON_PROFIT",
"GOVERNMENT",
"SOLE_PROPRIETOR"
],
"type": "string"
},
"postal_code": {
"type": "string",
"description": "Postal code."
},
"company_name": {
"type": "string",
"description": "Legal company name. Required for every entity type but `SOLE_PROPRIETOR`."
},
"display_name": {
"type": "string",
"description": "The brand name recipients know you by."
},
"mobile_phone": {
"type": "string",
"description": "Required for `SOLE_PROPRIETOR`: the mobile number that receives the verification PIN."
},
"stock_symbol": {
"type": "string",
"description": "Required for `PUBLIC_PROFIT`."
},
"stock_exchange": {
"type": "string",
"description": "Required for `PUBLIC_PROFIT`, e.g. `NASDAQ`."
},
"business_contact_email": {
"type": "string",
"description": "Required for `PUBLIC_PROFIT`: the email the registry verifies the company through."
}
},
"additionalProperties": false
}| string |
| How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given. |
| chat_id* | string | Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint. |
| dry_run | boolean |
| app_clip | object | An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve… |
| carousel | boolean | Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli… |
| reply_to | string | Message id to reply to. Applies to the whole outgoing message. |
| template | object | Template content (WhatsApp Business). |
| rich_link | object | A tappable rich link bubble (Blooio / Apple Messages for Business). |
| invitation | object | Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in. |
| attachments | array | Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles. |
| interactive | object | Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim… |
| imessage_app | object | Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card… |
| link_preview | object |
| idempotencyKey | string | Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request. |
{
"type": "object",
"required": [
"chat_id"
],
"properties": {
"poll": {
"type": "object",
"required": [
"title",
"options"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"options": {
"type": "array"
}
},
"description": "A native Blooio poll. Routed sends automatically consider only poll-capable channels."
},
"text": {
"type": "string",
"description": "Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: \"markdown\"` to interpret Markdown styling in this field (and in `parts[].text`)."
},
"badge": {
"enum": [
"sent_with_siri",
"sent_with_facetime"
],
"type": "string",
"description": "Optional attribution badge shown under the bubble: `sent_with_siri` renders \"Sent with Siri\" and `sent_with_facetime` renders \"Sent with FaceTime\", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B…"
},
"parts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"text": {
"type": "string"
}
}
},
"minItems": 1,
"description": "Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: \"markdown\"`, each part's `text` is parsed for styling independently."
},
"effect": {
"type": "string",
"description": "iMessage screen/bubble effect (Blooio, text only)."
},
"format": {
"enum": [
"plain",
"markdown"
],
"type": "string",
"default": "plain",
"description": "How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given."
},
"chat_id": {
"type": "string",
"description": "Unique identifier of the chat, prefixed with `chat_`. Returned by the List chats endpoint."
},
"dry_run": {
"type": "boolean"
},
"app_clip": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "The App Clip launch URL (https). Mutually exclusive with `bundle_id`; if both are given, `url` wins."
},
"title": {
"type": "string",
"description": "Optional preview title override."
},
"bundle_id": {
"type": "string",
"description": "App Clip bundle identifier (e.g. `com.example.app.Clip`), expanded to `https://appclip.apple.com/id?p=<bundle_id>`. Used when `url` is absent."
}
},
"description": "An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve…"
},
"carousel": {
"type": "boolean",
"description": "Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli…"
},
"reply_to": {
"type": "string",
"description": "Message id to reply to. Applies to the whole outgoing message."
},
"template": {
"type": "object",
"properties": {
"template_id": {
"type": "string"
}
},
"description": "Template content (WhatsApp Business).",
"additionalProperties": true
},
"rich_link": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
}
},
"description": "A tappable rich link bubble (Blooio / Apple Messages for Business)."
},
"invitation": {
"type": "object",
"required": [
"template_id",
"reference_id"
],
"properties": {
"locale": {
"type": "string",
"description": "BCP-47 locale for the template. Defaults to `en-us`."
},
"parameters": {
"type": "object",
"description": "Template parameter values required by the chosen template (e.g. `brandName`, and `brandLogo` as a base64 PNG). For known templates the required parameters are enforced before sending — e.g. `binaryChoice.engage.withImage` requires `brandName` + `brandLogo` — and a missing one is rejected with `422 invalid_invitation` naming the field (rather than being accepted and then rejected by Apple with `40…",
"additionalProperties": true
},
"template_id": {
"type": "string",
"description": "The Apple-managed notification template id authorized for your business (e.g. `binaryChoice.engage.withImage`)."
},
"reference_id": {
"type": "string",
"maxLength": 1000,
"description": "Your business context id for this invitation (order number, case id, etc.). Required by Apple and echoed back on the CloseSession webhook. Max 1000 characters; must not contain quotation marks or apostrophes."
}
},
"description": "Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in.",
"additionalProperties": true
},
"attachments": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"minItems": 1,
"description": "Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles."
},
"interactive": {
"type": "object",
"required": [
"kind"
],
"properties": {
"app": {
"type": "object",
"description": "Custom iMessage app metadata (`kind` = imessage_app). These App Store fallback fields (shown by Messages when the extension isn't installed) may also be supplied flat on the interactive object as `app_id` / `app_name` / `app_icon`; both forms reach the wire."
},
"bid": {
"type": "string",
"description": "iMessage extension bundle id. Required for `kind` = imessage_app (or supply it under `app.bid`); rejected with `422 invalid_imessage_app` otherwise."
},
"url": {
"type": "string",
"description": "Custom app URL / query string (`kind` = imessage_app)."
},
"form": {
"type": "object",
"description": "Alias for `dynamic` (`kind` = form).",
"additionalProperties": true
},
"kind": {
"enum": [
"quick_reply",
"list_picker",
"time_picker",
"form",
"apple_pay",
"authenticate",
"imessage_app"
],
"type": "string",
"description": "Which interactive experience to render."
},
"list": {
"type": "object",
"description": "Alias for `sections` (`kind` = list_picker). Accepts `{ \"sections\": [...] }` (or a bare array of sections). Same validation and normalization as `sections`.",
"additionalProperties": true
},
"text": {
"type": "string",
"description": "Alias for `summary_text`."
},
"event": {
"type": "object",
"description": "Time picker event (`kind` = time_picker). Required: at least one `timeslots` entry, each with a `startTime` (ISO-8601) and a positive `duration` (seconds). Rejected with `422 invalid_time_picker` otherwise."
},
"items": {
"type": "array",
"description": "Quick reply options (`kind` = quick_reply). Required: 1–5 items, each with a non-empty `id` and `title`. Rejected with `422 invalid_quick_reply` otherwise."
},
"app_id": {
"type": [
"integer",
"string"
],
"description": "App Store id for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_id`."
},
"images": {
"type": "array",
"description": "Inline PNG assets referenced by `imageIdentifier` elsewhere in the payload. Supply each as base64 `data` OR a `url` (fetched server-side). Every image — fetched or inline — is validated from its MAGIC BYTES (not the Content-Type): it must be a real PNG (`422 amb_image_not_png` / `code` on the failed send otherwise), within Apple's 200 KB per-image cap (`amb_image_too_large`) and 5 MB aggregate ca…"
},
"oauth2": {
"type": "object",
"description": "Shorthand for `authenticate.oauth2` (`kind` = authenticate). Requires `responseType`, `scope`, and `redirectURI`.",
"additionalProperties": true
},
"dynamic": {
"type": "object",
"description": "Apple dynamic interactive message (multi-page form) object, forwarded verbatim (`kind` = form). Required: at least one page under `pages` (or `data.pages`); also carries `startPageIdentifier`, `requestIdentifier`, `showSummary`, etc. Rejected with `422 invalid_form` otherwise. May also be supplied under `form`.",
"additionalProperties": true
},
"payment": {
"type": "object",
"description": "Apple Pay payment request object, forwarded verbatim (`kind` = apple_pay). Required: a `paymentRequest` object with `total` (`label` + numeric `amount`), `currencyCode` (ISO-4217), and `countryCode` (ISO-3166). Rejected with `422 invalid_apple_pay` otherwise. Apple additionally gates delivery on the merchant configuration.",
"additionalProperties": true
},
"app_icon": {
"type": "string",
"description": "Base64 PNG icon for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_icon`."
},
"app_name": {
"type": "string",
"description": "App Store name for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_name`."
},
"sections": {
"type": "array",
"description": "List picker sections (`kind` = list_picker). Required: at least one section, each with a non-empty `title` and at least one item; every item needs a non-empty `identifier` and `title`. Rejected with `422 invalid_list_picker` otherwise. Blooio normalizes the input into Apple's reliably-rendering wire shape (`listPicker.sections[].items[]` with a per-item `style`, under a live-layout envelope) — th…"
},
"authenticate": {
"type": "object",
"description": "OAuth2 authentication request object, forwarded verbatim (`kind` = authenticate). Required: an `oauth2` object with `responseType`, `scope`, and `redirectURI`. Rejected with `422 invalid_authenticate` otherwise. Sent as interactive data version 2.0.",
"additionalProperties": true
},
"summary_text": {
"type": "string",
"description": "Prompt / fallback line shown where the interactive UI can't render. Used as the quick reply prompt."
},
"reply_message": {
"type": "object",
"description": "Bubble shown after the customer replies."
},
"use_live_layout": {
"type": "boolean"
},
"received_message": {
"type": "object",
"description": "Bubble shown to the customer before they interact. Not allowed for `quick_reply` (send a plain text bubble first instead)."
},
"request_identifier": {
"type": "string",
"description": "Optional stable id echoed back on the customer's reply. Defaults to the message id."
},
"session_identifier": {
"type": "string"
}
},
"description": "Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim…",
"additionalProperties": true
},
"imessage_app": {
"type": "object",
"required": [
"bundle_id",
"team_id",
"url"
],
"properties": {
"url": {
"type": "string",
"description": "The app-state URL your extension reads on tap (its `MSMessage.url`). Carries the state to reconstruct on the recipient device."
},
"caption": {
"type": "string",
"description": "Template-card caption shown to everyone (including recipients without the app)."
},
"team_id": {
"type": "string",
"description": "Your Apple Developer Team ID. Combined with `bundle_id` to form the balloon plugin id."
},
"app_name": {
"type": "string",
"description": "Display name shown for the app (the `an` field). Defaults to a generic label."
},
"bundle_id": {
"type": "string",
"description": "Your iMessage app extension's bundle identifier (e.g. `com.acme.app.MessagesExtension`)."
},
"image_url": {
"type": "string",
"format": "uri",
"description": "Optional https image used as the fallback template card thumbnail. Fetched best-effort (≤256KB); a fetch failure never fails the send."
},
"subcaption": {
"type": "string",
"description": "Optional template-card subcaption."
},
"app_store_id": {
"type": "integer",
"minimum": 1,
"description": "Optional App Store id (adam id) for your app. When the recipient doesn't have the extension installed, Messages uses it to deep-link the App Store \"get this app\" fallback to the correct listing. Omitting it leaves the send unchanged."
}
},
"description": "Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card…"
},
"link_preview": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"imageUrl": {
"type": "string",
"format": "uri"
}
}
},
"idempotencyKey": {
"type": "string",
"description": "Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request."
}
},
"additionalProperties": false
}| parts | array | Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: "markdown"`, each part's `text` is parsed for styling independently. |
| effect | string | iMessage screen/bubble effect (Blooio, text only). |
| format | string | How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given. |
| hybrid | any | Deprecated: Twilio-first, Blooio-after-reply routing is now an `outreach_only` step rule on the priority (`settings.steps`). `true` routes like an omitted `from`. A phone number string routes as that number's owner, an API key or integration in your organization (an API key may only name its own numbers); `409 hybrid_unavailable` when none you can send for owns it. Mutually exclusive with `from`… |
| dry_run | boolean | Validate and route only; do not send. |
| app_clip | object | An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve… |
| carousel | boolean | Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli… |
| reply_to | string | Message id to reply to. Applies to the whole outgoing message. |
| template | object | Template content (WhatsApp Business). |
| rich_link | object | A tappable rich link bubble (Blooio / Apple Messages for Business). |
| invitation | object | Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in. |
| attachments | array | Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles. |
| interactive | object | Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim… |
| priority_id | string | Route through an explicit priority (priority_...). Mutually exclusive with `from`. |
| channel_type | string |
| imessage_app | object | Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card… |
| link_preview | object |
| idempotencyKey | string | Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request. |
{
"type": "object",
"required": [
"to"
],
"properties": {
"to": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Contact id (ct_...) — routed sends only."
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Existing group id (grp_...) — an exact sender, or the deprecated `hybrid` control when its owner holds the group's channel."
}
},
"additionalProperties": false
}
],
"description": "A recipient: a raw identifier string (phone/email/opaque provider id), an array of identifier strings (multiple recipients), an existing `{ group_id }` with an exact sender, or (for routed sends) a `{ contact_id }`. A `contact_id` enables cross-channel-type routing via the contact's identities; a bare identifier reaches phone/email-addressable channels only."
},
"from": {
"type": "string",
"description": "The sender as a single string: a phone number (any common format; matched to your exact numbered channel), a channel alias (organization-wide name of a non-numbered channel), or an exact channel id (ch_...). Omit it for automatic routing. If a phone number ever matches more than one active channel type, the send fails with `409 ambiguous_from` and the exact `ch_...` id must be used instead."
},
"poll": {
"type": "object",
"required": [
"title",
"options"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"options": {
"type": "array"
}
},
"description": "A native Blooio poll. Routed sends automatically consider only poll-capable channels."
},
"text": {
"type": "string",
"description": "Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: \"markdown\"` to interpret Markdown styling in this field (and in `parts[].text`)."
},
"badge": {
"enum": [
"sent_with_siri",
"sent_with_facetime"
],
"type": "string",
"description": "Optional attribution badge shown under the bubble: `sent_with_siri` renders \"Sent with Siri\" and `sent_with_facetime` renders \"Sent with FaceTime\", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B…"
},
"parts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"text": {
"type": "string"
}
}
},
"minItems": 1,
"description": "Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: \"markdown\"`, each part's `text` is parsed for styling independently."
},
"effect": {
"type": "string",
"description": "iMessage screen/bubble effect (Blooio, text only)."
},
"format": {
"enum": [
"plain",
"markdown"
],
"type": "string",
"default": "plain",
"description": "How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given."
},
"hybrid": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "string"
}
],
"deprecated": true,
"description": "Deprecated: Twilio-first, Blooio-after-reply routing is now an `outreach_only` step rule on the priority (`settings.steps`). `true` routes like an omitted `from`. A phone number string routes as that number's owner, an API key or integration in your organization (an API key may only name its own numbers); `409 hybrid_unavailable` when none you can send for owns it. Mutually exclusive with `from`…"
},
"dry_run": {
"type": "boolean",
"description": "Validate and route only; do not send."
},
"app_clip": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "The App Clip launch URL (https). Mutually exclusive with `bundle_id`; if both are given, `url` wins."
},
"title": {
"type": "string",
"description": "Optional preview title override."
},
"bundle_id": {
"type": "string",
"description": "App Clip bundle identifier (e.g. `com.example.app.Clip`), expanded to `https://appclip.apple.com/id?p=<bundle_id>`. Used when `url` is absent."
}
},
"description": "An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve…"
},
"carousel": {
"type": "boolean",
"description": "Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli…"
},
"reply_to": {
"type": "string",
"description": "Message id to reply to. Applies to the whole outgoing message."
},
"template": {
"type": "object",
"properties": {
"template_id": {
"type": "string"
}
},
"description": "Template content (WhatsApp Business).",
"additionalProperties": true
},
"rich_link": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
}
},
"description": "A tappable rich link bubble (Blooio / Apple Messages for Business)."
},
"invitation": {
"type": "object",
"required": [
"template_id",
"reference_id"
],
"properties": {
"locale": {
"type": "string",
"description": "BCP-47 locale for the template. Defaults to `en-us`."
},
"parameters": {
"type": "object",
"description": "Template parameter values required by the chosen template (e.g. `brandName`, and `brandLogo` as a base64 PNG). For known templates the required parameters are enforced before sending — e.g. `binaryChoice.engage.withImage` requires `brandName` + `brandLogo` — and a missing one is rejected with `422 invalid_invitation` naming the field (rather than being accepted and then rejected by Apple with `40…",
"additionalProperties": true
},
"template_id": {
"type": "string",
"description": "The Apple-managed notification template id authorized for your business (e.g. `binaryChoice.engage.withImage`)."
},
"reference_id": {
"type": "string",
"maxLength": 1000,
"description": "Your business context id for this invitation (order number, case id, etc.). Required by Apple and echoed back on the CloseSession webhook. Max 1000 characters; must not contain quotation marks or apostrophes."
}
},
"description": "Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in.",
"additionalProperties": true
},
"attachments": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"minItems": 1,
"description": "Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles."
},
"interactive": {
"type": "object",
"required": [
"kind"
],
"properties": {
"app": {
"type": "object",
"description": "Custom iMessage app metadata (`kind` = imessage_app). These App Store fallback fields (shown by Messages when the extension isn't installed) may also be supplied flat on the interactive object as `app_id` / `app_name` / `app_icon`; both forms reach the wire."
},
"bid": {
"type": "string",
"description": "iMessage extension bundle id. Required for `kind` = imessage_app (or supply it under `app.bid`); rejected with `422 invalid_imessage_app` otherwise."
},
"url": {
"type": "string",
"description": "Custom app URL / query string (`kind` = imessage_app)."
},
"form": {
"type": "object",
"description": "Alias for `dynamic` (`kind` = form).",
"additionalProperties": true
},
"kind": {
"enum": [
"quick_reply",
"list_picker",
"time_picker",
"form",
"apple_pay",
"authenticate",
"imessage_app"
],
"type": "string",
"description": "Which interactive experience to render."
},
"list": {
"type": "object",
"description": "Alias for `sections` (`kind` = list_picker). Accepts `{ \"sections\": [...] }` (or a bare array of sections). Same validation and normalization as `sections`.",
"additionalProperties": true
},
"text": {
"type": "string",
"description": "Alias for `summary_text`."
},
"event": {
"type": "object",
"description": "Time picker event (`kind` = time_picker). Required: at least one `timeslots` entry, each with a `startTime` (ISO-8601) and a positive `duration` (seconds). Rejected with `422 invalid_time_picker` otherwise."
},
"items": {
"type": "array",
"description": "Quick reply options (`kind` = quick_reply). Required: 1–5 items, each with a non-empty `id` and `title`. Rejected with `422 invalid_quick_reply` otherwise."
},
"app_id": {
"type": [
"integer",
"string"
],
"description": "App Store id for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_id`."
},
"images": {
"type": "array",
"description": "Inline PNG assets referenced by `imageIdentifier` elsewhere in the payload. Supply each as base64 `data` OR a `url` (fetched server-side). Every image — fetched or inline — is validated from its MAGIC BYTES (not the Content-Type): it must be a real PNG (`422 amb_image_not_png` / `code` on the failed send otherwise), within Apple's 200 KB per-image cap (`amb_image_too_large`) and 5 MB aggregate ca…"
},
"oauth2": {
"type": "object",
"description": "Shorthand for `authenticate.oauth2` (`kind` = authenticate). Requires `responseType`, `scope`, and `redirectURI`.",
"additionalProperties": true
},
"dynamic": {
"type": "object",
"description": "Apple dynamic interactive message (multi-page form) object, forwarded verbatim (`kind` = form). Required: at least one page under `pages` (or `data.pages`); also carries `startPageIdentifier`, `requestIdentifier`, `showSummary`, etc. Rejected with `422 invalid_form` otherwise. May also be supplied under `form`.",
"additionalProperties": true
},
"payment": {
"type": "object",
"description": "Apple Pay payment request object, forwarded verbatim (`kind` = apple_pay). Required: a `paymentRequest` object with `total` (`label` + numeric `amount`), `currencyCode` (ISO-4217), and `countryCode` (ISO-3166). Rejected with `422 invalid_apple_pay` otherwise. Apple additionally gates delivery on the merchant configuration.",
"additionalProperties": true
},
"app_icon": {
"type": "string",
"description": "Base64 PNG icon for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_icon`."
},
"app_name": {
"type": "string",
"description": "App Store name for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_name`."
},
"sections": {
"type": "array",
"description": "List picker sections (`kind` = list_picker). Required: at least one section, each with a non-empty `title` and at least one item; every item needs a non-empty `identifier` and `title`. Rejected with `422 invalid_list_picker` otherwise. Blooio normalizes the input into Apple's reliably-rendering wire shape (`listPicker.sections[].items[]` with a per-item `style`, under a live-layout envelope) — th…"
},
"authenticate": {
"type": "object",
"description": "OAuth2 authentication request object, forwarded verbatim (`kind` = authenticate). Required: an `oauth2` object with `responseType`, `scope`, and `redirectURI`. Rejected with `422 invalid_authenticate` otherwise. Sent as interactive data version 2.0.",
"additionalProperties": true
},
"summary_text": {
"type": "string",
"description": "Prompt / fallback line shown where the interactive UI can't render. Used as the quick reply prompt."
},
"reply_message": {
"type": "object",
"description": "Bubble shown after the customer replies."
},
"use_live_layout": {
"type": "boolean"
},
"received_message": {
"type": "object",
"description": "Bubble shown to the customer before they interact. Not allowed for `quick_reply` (send a plain text bubble first instead)."
},
"request_identifier": {
"type": "string",
"description": "Optional stable id echoed back on the customer's reply. Defaults to the message id."
},
"session_identifier": {
"type": "string"
}
},
"description": "Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim…",
"additionalProperties": true
},
"priority_id": {
"type": "string",
"description": "Route through an explicit priority (priority_...). Mutually exclusive with `from`."
},
"channel_type": {
"enum": [
"blooio",
"twilio",
"whatsapp",
"whatsapp_business",
"rcs_business",
"amb",
"sms",
"voice"
],
"type": "string"
},
"imessage_app": {
"type": "object",
"required": [
"bundle_id",
"team_id",
"url"
],
"properties": {
"url": {
"type": "string",
"description": "The app-state URL your extension reads on tap (its `MSMessage.url`). Carries the state to reconstruct on the recipient device."
},
"caption": {
"type": "string",
"description": "Template-card caption shown to everyone (including recipients without the app)."
},
"team_id": {
"type": "string",
"description": "Your Apple Developer Team ID. Combined with `bundle_id` to form the balloon plugin id."
},
"app_name": {
"type": "string",
"description": "Display name shown for the app (the `an` field). Defaults to a generic label."
},
"bundle_id": {
"type": "string",
"description": "Your iMessage app extension's bundle identifier (e.g. `com.acme.app.MessagesExtension`)."
},
"image_url": {
"type": "string",
"format": "uri",
"description": "Optional https image used as the fallback template card thumbnail. Fetched best-effort (≤256KB); a fetch failure never fails the send."
},
"subcaption": {
"type": "string",
"description": "Optional template-card subcaption."
},
"app_store_id": {
"type": "integer",
"minimum": 1,
"description": "Optional App Store id (adam id) for your app. When the recipient doesn't have the extension installed, Messages uses it to deep-link the App Store \"get this app\" fallback to the correct listing. Omitting it leaves the send unchanged."
}
},
"description": "Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card…"
},
"link_preview": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"imageUrl": {
"type": "string",
"format": "uri"
}
}
},
"idempotencyKey": {
"type": "string",
"description": "Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request."
}
},
"additionalProperties": false
}| array |
| Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: "markdown"`, each part's `text` is parsed for styling independently. |
| effect | string | iMessage screen/bubble effect (Blooio, text only). |
| format | string | How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given. |
| channel* | string | The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`). |
| dry_run | boolean | Validate and route only; do not send. |
| app_clip | object | An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve… |
| carousel | boolean | Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli… |
| reply_to | string | Message id to reply to. Applies to the whole outgoing message. |
| template | object | Template content (WhatsApp Business). |
| rich_link | object | A tappable rich link bubble (Blooio / Apple Messages for Business). |
| invitation | object | Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in. |
| attachments | array | Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles. |
| interactive | object | Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim… |
| imessage_app | object | Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card… |
| link_preview | object |
| idempotencyKey | string | Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request. |
{
"type": "object",
"required": [
"channel",
"to"
],
"properties": {
"to": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "object",
"required": [
"contact_id"
],
"properties": {
"contact_id": {
"type": "string",
"description": "Contact id (ct_...) — routed sends only."
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"group_id"
],
"properties": {
"group_id": {
"type": "string",
"description": "Existing group id (grp_...) — an exact sender, or the deprecated `hybrid` control when its owner holds the group's channel."
}
},
"additionalProperties": false
}
],
"description": "A recipient: a raw identifier string (phone/email/opaque provider id), an array of identifier strings (multiple recipients), an existing `{ group_id }` with an exact sender, or (for routed sends) a `{ contact_id }`. A `contact_id` enables cross-channel-type routing via the contact's identities; a bare identifier reaches phone/email-addressable channels only."
},
"poll": {
"type": "object",
"required": [
"title",
"options"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"options": {
"type": "array"
}
},
"description": "A native Blooio poll. Routed sends automatically consider only poll-capable channels."
},
"text": {
"type": "string",
"description": "Plain text message. May be combined with `attachments` (sent as media with a caption) — except a lone audio file, which is sent as a standalone voice memo and cannot carry a caption. Set `format: \"markdown\"` to interpret Markdown styling in this field (and in `parts[].text`)."
},
"badge": {
"enum": [
"sent_with_siri",
"sent_with_facetime"
],
"type": "string",
"description": "Optional attribution badge shown under the bubble: `sent_with_siri` renders \"Sent with Siri\" and `sent_with_facetime` renders \"Sent with FaceTime\", the way a message dictated to Siri or sent during a FaceTime call appears. Omit for no badge. Any other value is rejected with `422 invalid_content`. Applies to `text`, `attachments` (media), `parts` (multipart), `rich_link`, and `app_clip` sends on B…"
},
"parts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"text": {
"type": "string"
}
}
},
"minItems": 1,
"description": "Ordered text/media parts sent as one multipart message (Blooio only). When every part is an image/video (two or more, no text parts) Messages renders them as a photo/video carousel/collage by default; set `carousel: false` to opt out. With `format: \"markdown\"`, each part's `text` is parsed for styling independently."
},
"effect": {
"type": "string",
"description": "iMessage screen/bubble effect (Blooio, text only)."
},
"format": {
"enum": [
"plain",
"markdown"
],
"type": "string",
"default": "plain",
"description": "How to interpret `text` (and each `parts[].text`). Defaults to `plain`, which sends the string exactly as given."
},
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
},
"dry_run": {
"type": "boolean",
"description": "Validate and route only; do not send."
},
"app_clip": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "The App Clip launch URL (https). Mutually exclusive with `bundle_id`; if both are given, `url` wins."
},
"title": {
"type": "string",
"description": "Optional preview title override."
},
"bundle_id": {
"type": "string",
"description": "App Clip bundle identifier (e.g. `com.example.app.Clip`), expanded to `https://appclip.apple.com/id?p=<bundle_id>`. Used when `url` is absent."
}
},
"description": "An App Clip bubble (Blooio p2p iMessage only). Sends an App Clip launch URL that Messages renders as a native App Clip card (app icon + name + Open button); tapping it launches the instant App Clip experience without an install. Provide either a ready-made `url` (Apple's `https://appclip.apple.com/id?p=<bundleID>` launcher, or an app's own associated-domain App Clip link) or the `bundle_id` conve…"
},
"carousel": {
"type": "boolean",
"description": "Group image/video attachments into ONE message that Messages renders as a swipeable photo/video carousel/collage, instead of separate bubbles (Blooio p2p iMessage only). DEFAULTS ON: a Blooio send whose attachments (via `attachments` or `parts`) are two or more image/video URLs is grouped automatically — set `carousel: false` to send them as independent bubbles instead. Set `carousel: true` expli…"
},
"reply_to": {
"type": "string",
"description": "Message id to reply to. Applies to the whole outgoing message."
},
"template": {
"type": "object",
"properties": {
"template_id": {
"type": "string"
}
},
"description": "Template content (WhatsApp Business).",
"additionalProperties": true
},
"rich_link": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
}
},
"description": "A tappable rich link bubble (Blooio / Apple Messages for Business)."
},
"invitation": {
"type": "object",
"required": [
"template_id",
"reference_id"
],
"properties": {
"locale": {
"type": "string",
"description": "BCP-47 locale for the template. Defaults to `en-us`."
},
"parameters": {
"type": "object",
"description": "Template parameter values required by the chosen template (e.g. `brandName`, and `brandLogo` as a base64 PNG). For known templates the required parameters are enforced before sending — e.g. `binaryChoice.engage.withImage` requires `brandName` + `brandLogo` — and a missing one is rejected with `422 invalid_invitation` naming the field (rather than being accepted and then rejected by Apple with `40…",
"additionalProperties": true
},
"template_id": {
"type": "string",
"description": "The Apple-managed notification template id authorized for your business (e.g. `binaryChoice.engage.withImage`)."
},
"reference_id": {
"type": "string",
"maxLength": 1000,
"description": "Your business context id for this invitation (order number, case id, etc.). Required by Apple and echoed back on the CloseSession webhook. Max 1000 characters; must not contain quotation marks or apostrophes."
}
},
"description": "Apple Messages for Business invitation. Sends an Apple-managed notification template (Live Layout) that invites the customer into a business chat. Addressed to a phone number (`tel:+E164`) rather than an opaque Apple Messages for Business id. Requires prior Invitations approval from Apple and explicit customer opt-in.",
"additionalProperties": true
},
"attachments": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"minItems": 1,
"description": "Public https media URLs. May be combined with `text`. On Blooio iMessage, two or more image/video URLs are grouped into one photo/video carousel/collage bubble by default; set `carousel: false` to send them as separate bubbles."
},
"interactive": {
"type": "object",
"required": [
"kind"
],
"properties": {
"app": {
"type": "object",
"description": "Custom iMessage app metadata (`kind` = imessage_app). These App Store fallback fields (shown by Messages when the extension isn't installed) may also be supplied flat on the interactive object as `app_id` / `app_name` / `app_icon`; both forms reach the wire."
},
"bid": {
"type": "string",
"description": "iMessage extension bundle id. Required for `kind` = imessage_app (or supply it under `app.bid`); rejected with `422 invalid_imessage_app` otherwise."
},
"url": {
"type": "string",
"description": "Custom app URL / query string (`kind` = imessage_app)."
},
"form": {
"type": "object",
"description": "Alias for `dynamic` (`kind` = form).",
"additionalProperties": true
},
"kind": {
"enum": [
"quick_reply",
"list_picker",
"time_picker",
"form",
"apple_pay",
"authenticate",
"imessage_app"
],
"type": "string",
"description": "Which interactive experience to render."
},
"list": {
"type": "object",
"description": "Alias for `sections` (`kind` = list_picker). Accepts `{ \"sections\": [...] }` (or a bare array of sections). Same validation and normalization as `sections`.",
"additionalProperties": true
},
"text": {
"type": "string",
"description": "Alias for `summary_text`."
},
"event": {
"type": "object",
"description": "Time picker event (`kind` = time_picker). Required: at least one `timeslots` entry, each with a `startTime` (ISO-8601) and a positive `duration` (seconds). Rejected with `422 invalid_time_picker` otherwise."
},
"items": {
"type": "array",
"description": "Quick reply options (`kind` = quick_reply). Required: 1–5 items, each with a non-empty `id` and `title`. Rejected with `422 invalid_quick_reply` otherwise."
},
"app_id": {
"type": [
"integer",
"string"
],
"description": "App Store id for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_id`."
},
"images": {
"type": "array",
"description": "Inline PNG assets referenced by `imageIdentifier` elsewhere in the payload. Supply each as base64 `data` OR a `url` (fetched server-side). Every image — fetched or inline — is validated from its MAGIC BYTES (not the Content-Type): it must be a real PNG (`422 amb_image_not_png` / `code` on the failed send otherwise), within Apple's 200 KB per-image cap (`amb_image_too_large`) and 5 MB aggregate ca…"
},
"oauth2": {
"type": "object",
"description": "Shorthand for `authenticate.oauth2` (`kind` = authenticate). Requires `responseType`, `scope`, and `redirectURI`.",
"additionalProperties": true
},
"dynamic": {
"type": "object",
"description": "Apple dynamic interactive message (multi-page form) object, forwarded verbatim (`kind` = form). Required: at least one page under `pages` (or `data.pages`); also carries `startPageIdentifier`, `requestIdentifier`, `showSummary`, etc. Rejected with `422 invalid_form` otherwise. May also be supplied under `form`.",
"additionalProperties": true
},
"payment": {
"type": "object",
"description": "Apple Pay payment request object, forwarded verbatim (`kind` = apple_pay). Required: a `paymentRequest` object with `total` (`label` + numeric `amount`), `currencyCode` (ISO-4217), and `countryCode` (ISO-3166). Rejected with `422 invalid_apple_pay` otherwise. Apple additionally gates delivery on the merchant configuration.",
"additionalProperties": true
},
"app_icon": {
"type": "string",
"description": "Base64 PNG icon for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_icon`."
},
"app_name": {
"type": "string",
"description": "App Store name for the iMessage app fallback (`kind` = imessage_app). Flat alias for `app.app_name`."
},
"sections": {
"type": "array",
"description": "List picker sections (`kind` = list_picker). Required: at least one section, each with a non-empty `title` and at least one item; every item needs a non-empty `identifier` and `title`. Rejected with `422 invalid_list_picker` otherwise. Blooio normalizes the input into Apple's reliably-rendering wire shape (`listPicker.sections[].items[]` with a per-item `style`, under a live-layout envelope) — th…"
},
"authenticate": {
"type": "object",
"description": "OAuth2 authentication request object, forwarded verbatim (`kind` = authenticate). Required: an `oauth2` object with `responseType`, `scope`, and `redirectURI`. Rejected with `422 invalid_authenticate` otherwise. Sent as interactive data version 2.0.",
"additionalProperties": true
},
"summary_text": {
"type": "string",
"description": "Prompt / fallback line shown where the interactive UI can't render. Used as the quick reply prompt."
},
"reply_message": {
"type": "object",
"description": "Bubble shown after the customer replies."
},
"use_live_layout": {
"type": "boolean"
},
"received_message": {
"type": "object",
"description": "Bubble shown to the customer before they interact. Not allowed for `quick_reply` (send a plain text bubble first instead)."
},
"request_identifier": {
"type": "string",
"description": "Optional stable id echoed back on the customer's reply. Defaults to the message id."
},
"session_identifier": {
"type": "string"
}
},
"description": "Interactive content. On Apple Messages for Business this renders as a native interactive message: a quick reply, list picker, time picker, dynamic form, Apple Pay request, authentication (Sign in) request, or a custom iMessage app. Select the variant with `kind` and populate that kind's required fields; fields not relevant to the chosen kind are ignored. Each `kind` is validated against the minim…",
"additionalProperties": true
},
"imessage_app": {
"type": "object",
"required": [
"bundle_id",
"team_id",
"url"
],
"properties": {
"url": {
"type": "string",
"description": "The app-state URL your extension reads on tap (its `MSMessage.url`). Carries the state to reconstruct on the recipient device."
},
"caption": {
"type": "string",
"description": "Template-card caption shown to everyone (including recipients without the app)."
},
"team_id": {
"type": "string",
"description": "Your Apple Developer Team ID. Combined with `bundle_id` to form the balloon plugin id."
},
"app_name": {
"type": "string",
"description": "Display name shown for the app (the `an` field). Defaults to a generic label."
},
"bundle_id": {
"type": "string",
"description": "Your iMessage app extension's bundle identifier (e.g. `com.acme.app.MessagesExtension`)."
},
"image_url": {
"type": "string",
"format": "uri",
"description": "Optional https image used as the fallback template card thumbnail. Fetched best-effort (≤256KB); a fetch failure never fails the send."
},
"subcaption": {
"type": "string",
"description": "Optional template-card subcaption."
},
"app_store_id": {
"type": "integer",
"minimum": 1,
"description": "Optional App Store id (adam id) for your app. When the recipient doesn't have the extension installed, Messages uses it to deep-link the App Store \"get this app\" fallback to the correct listing. Omitting it leaves the send unchanged."
}
},
"description": "Bring-your-own iMessage App Extension bubble (Blooio p2p iMessage only). Blooio is the transport, NOT the renderer: you point at YOUR OWN signed iMessage app extension and we assemble the MSMessage app balloon and send it. Recipients who have your app installed render its interactive overlay (its `MSMessagesAppViewController` reads `url` on tap); recipients who don't see the native template card…"
},
"link_preview": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"imageUrl": {
"type": "string",
"format": "uri"
}
}
},
"idempotencyKey": {
"type": "string",
"description": "Optional key for safe retries. Replaying the same key with an identical body returns the original result; a different body returns 409. Use a unique value (such as a UUID) per logical request."
}
},
"additionalProperties": false
}| auto_mark_read | boolean | Blooio: mark a chat read on the device as soon as a message arrives. Dedicated + inbound lines only. |
| auto_share_contact | boolean | Blooio: share the number's Name & Photo card with people who message it. Dedicated lines only, and the line must have a contact card set up. |
{
"type": "object",
"required": [
"channel"
],
"properties": {
"opener": {
"oneOf": [
{
"type": "object",
"properties": {
"locale": {
"type": [
"string",
"null"
]
},
"enabled": {
"type": "boolean"
},
"parameters": {
"type": [
"object",
"null"
],
"description": "Template parameters. An image parameter such as `brandLogo` may be an https URL; it is inlined when the invitation is sent.",
"additionalProperties": true
},
"template_id": {
"type": [
"string",
"null"
]
}
},
"description": "The business invitation a routed send uses to start a conversation with a contact who has no Apple Messages for Business identity on this channel yet. Turning it on requires `template_id` and the template's parameters (`binaryChoice.engage.withImage` needs `brandName` and `brandLogo`; `binaryChoice.engage.withoutImage` needs `brandName`).",
"additionalProperties": false
},
{
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"enabled": {
"type": "boolean"
},
"language": {
"type": [
"string",
"null"
]
},
"variables": {
"description": "Body variables: an array for positional (`{{1}}`) variables or an object for named ones."
}
},
"description": "The approved message template a routed send uses to start a conversation on this WhatsApp Business channel outside the 24-hour customer service window. Turning it on requires `name` to be an approved template on the channel; `language` is set to the approved template's language.",
"additionalProperties": false
}
],
"description": "Apple Messages for Business or WhatsApp Business: a partial update of the channel's opener, merged into the saved one. Turning it on validates the template."
},
"channel": {
"type": "string",
"description": "The channel reference — the same three forms `from` accepts: a phone number (URL-encode `+` as `%2B`), a channel alias, or the exact channel id (`ch_...`)."
},
"inbound": {
"type": "object",
"properties": {
"handler": {
"enum": [
"softphone",
"agent",
"api"
],
"type": "string",
"description": "`softphone` rings the organization's dashboard softphones. `agent` has the Blooio agent that owns the number answer; calls with a withheld caller ID are refused. `api` leaves the call ringing for you to answer with `POST /calls/{call_id}/answer` after the `call.ringing` webhook."
},
"ring_timeout_seconds": {
"type": "integer",
"default": 30,
"maximum": 120,
"minimum": 5,
"description": "How long a call rings before it ends `missed`. Also how long a call a Blooio agent hands off waits for a teammate."
}
},
"description": "Who answers a Blooio Voice number's inbound calls."
},
"imessage_only": {
"type": "boolean",
"description": "Blooio: a routed send (`POST /messages` without `from`) starts a conversation on this line only with a contact on iMessage, checked on the line's device; a contact who isn't, or a device that can't answer, moves the send to the next channel in the priority. Conversations the line already has are unaffected. Off by default, when the device sends SMS to a contact without iMessage."
},
"auto_mark_read": {
"type": "boolean",
"description": "Blooio: mark a chat read on the device as soon as a message arrives. Dedicated + inbound lines only."
},
"auto_share_contact": {
"type": "boolean",
"description": "Blooio: share the number's Name & Photo card with people who message it. Dedicated lines only, and the line must have a contact card set up."
}
},
"additionalProperties": false
}