Chats

Channel-scoped threads with opaque chat_ ids — create, send, and reply without using phone numbers as ids.

In v4, a chat is a messaging thread on a specific channel (sender). Ids look like chat_... — opaque and stable. Do not treat the recipient's phone number as the chat id (that was a common v2 pattern).

Mental model

Channel Your side of the wire (ch_... — a Blooio number, Twilio line, RCS Business sender, …)
Chat The thread between that channel and a peer (chat_...)
Contact The person, with one or more identities (ct_...)

The same contact can have multiple chats — one per channel (for example SMS on Twilio and iMessage on Blooio are different chats).

Two ways to send

1. Agnostic send (find-or-create)

POST /messages takes to + content fields like text. Blooio picks a channel via priorities / hybrid, finds or creates the chat, and returns chat_id on the message.

Use this for cold outreach and simple bots.

2. Send into an existing chat

When you already have chat_id (from a webhook, a previous send, or create-chat):

curl -X POST https://api.blooio.com/v4/chats/chat_.../messages \
  -H "Authorization: Bearer bl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Following up"
  }'
Try it

No from or to — the chat already knows the channel and peer.

Create a chat explicitly

Use this when you need the chat_id before the first message, or must pin a channel:

curl -X POST https://api.blooio.com/v4/chats \
  -H "Authorization: Bearer bl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "ch_...",
    "to": "+15551234567"
  }'
Try it

Response:

{
  "id": "chat_...",
  "channel_id": "ch_...",
  "channel_type": "blooio",
  "contact_id": "ct_...",
  "identity_id": "cid_...",
  "state": "open",
  "created": true
}

If the thread already exists, you get the same chat with "created": false (HTTP 200).

Chat-scoped actions

Once you have chat_id, these stay on the chat:

  • List / send messages
  • Typing indicators and read receipts (where the channel supports them)
  • Reactions on a message
  • Share contact card
  • Focus status and Notify Anyway (direct Blooio chats)
  • Polls (also available as the top-level poll field on a send)
  • Participants (group-capable channels only)

Focus

On a direct Blooio chat, GET /chats/{chatId}/focus reports whether the other person has notifications silenced by a Focus: silenced, none, or unknown. When they are silenced, POST /chats/{chatId}/messages/{messageId}/notify breaks through for an iMessage you sent, like tapping Notify Anyway in Messages. Notify Anyway cannot be undone, and no API can turn someone else's Focus on or off.

curl https://api.blooio.com/v4/chats/chat_.../focus \
  -H "Authorization: Bearer bl_live_..."

curl -X POST https://api.blooio.com/v4/chats/chat_.../messages/msg_.../notify \
  -H "Authorization: Bearer bl_live_..."

State

Chats are typically open or closed. Closed chats (for example closed by the user) reject new sends with a conflict such as 409 chat_closed_by_user. Patch state with PATCH /chats/{chatId} when your product needs to mark a thread closed.

Webhooks

Inbound and lifecycle events include chat_id (and often a hydrated message or chat in data). Persist chat_id from the first event or send response and use it for all follow-ups.