# Group chats

> Find a group chat, text into it with chat_id, and read what its members send. BlueBot can text into a group that already exists but can’t start a new one.

BlueBot can text into any group chat that already exists in Messages on your Mac, and read what everyone in it sends. It can’t start a new group: Messages offers no reliable way for an app to do that.

Dana is selling 412 Oak St, and she has a group chat in Messages called “Oak St closing” with the buyers and their lender. Her code finds the chat once, then posts updates into it as the closing moves along.

## Find the chat

`GET /v1/chats` lists the chats your Mac has copied, newest first. `is_group=true` leaves out the one-to-one chats:

```bash
curl "https://usebluebot.com/api/v1/chats?is_group=true" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const page = await client.chats.list({
  isGroup: true,
});
console.log(page.data);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

page = client.chats.list(is_group=True)
print(page.data)
```

The answer, `200`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "chat_1Hq2LxW9cVbN3mKpRtYs0a",
      "object": "chat",
      "name": "Oak St closing",
      "is_group": true,
      "participants": ["+15555550123", "+15555550187"],
      "service": "imessage",
      "last_message_at": "2026-11-13T19:41:00.000Z",
      "created_at": "2026-11-02T14:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

| Field          | What it tells you                                                     |
| -------------- | --------------------------------------------------------------------- |
| `id`           | The chat’s id (`chat_…`). This is what `chat_id` takes on a send.     |
| `name`         | The group’s name in Messages, or `null` when nobody named it.         |
| `participants` | Everyone in the chat except you.                                      |
| `service`      | `imessage` for an iMessage group, `sms` for a group of regular texts. |

To find a group somebody is in, add `person`: `GET /v1/chats?is_group=true&person=+15555550187`. A chat’s id stays the same for as long as the group exists, so look it up once and keep it.

A group appears in the list once your Mac has copied it. Under the default **Which chats to copy** setting, that means a group in which you’ve already texted every other member through BlueBot. A new group of people you’ve never texted that way won’t show until you set **Which chats to copy** to **Everything**. [Receive texts](https://usebluebot.com/docs/sending/receiving) explains the setting. When the Mac copies a group BlueBot didn’t know, `chat.created` fires.

## Text into it

Send `chat_id` in place of `to`:

```bash
curl -X POST "https://usebluebot.com/api/v1/messages" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: oak-st-closing-appraisal" \
  -d '{
    "chat_id": "chat_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Good news: the appraisal came back at the asking price. Closing is still on for the 24th."
  }'
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const message = await client.messages.send({
  chatId: 'chat_1Hq2LxW9cVbN3mKpRtYs0a',
  text: 'Good news: the appraisal came back at the asking price. Closing is still on for the 24th.',
}, { idempotencyKey: 'oak-st-closing-appraisal' });
console.log(message);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

message = client.messages.send(
    chat_id="chat_1Hq2LxW9cVbN3mKpRtYs0a",
    text="Good news: the appraisal came back at the asking price. Closing is still on for the 24th.",
    idempotency_key="oak-st-closing-appraisal",
)
print(message)
```

The answer, `201`:

```json
{
  "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
  "object": "message",
  "direction": "out",
  "state": "queued",
  "to": null,
  "chat_id": "chat_1Hq2LxW9cVbN3mKpRtYs0a",
  "contact_id": null,
  "hold": null
}
```

Everyone in the group gets it, as if you had typed it in Messages. A group text has `"to": null` and `"contact_id": null`, since it goes to the chat rather than one person. Files, `send_at`, `expires_at` and `metadata` work as they do on any send.

Send `to` or `chat_id`, never both, or the send is `400 invalid_request`. A `chat_id` that isn’t on your account is `404 not_found`.

The id of a one-to-one chat works in `chat_id` too. BlueBot then sends to that person as if you had used `to`, so their stop list and their conversation apply.

## How groups differ

|                                    | One-to-one                                                           | Group                                                        |
| ---------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------ |
| Service with `auto`                | The newest chat’s, else iMessage, with one SMS try if iMessage fails | The group’s own service. No SMS fallback.                    |
| A failed text                      | `failed`, or sent again as SMS once with `auto`                      | `failed` with “Messages couldn’t send it to this group.”     |
| The stop list                      | A text to somebody on it is canceled                                 | Doesn’t apply: BlueBot can’t leave one person out of a group |
| New people a day                   | Counts the first text to somebody                                    | Never counts                                                 |
| Pacing, quiet hours, daily ceiling | Apply                                                                | Apply                                                        |

The stop list covers one-to-one texts. If somebody in a group asks you to stop, take them out of the group on your phone, or stop texting the group. A reply of STOP inside a group doesn’t put anyone on your stop list.

## Read what the group sends

Every text a member sends into a copied group comes in as a message with the group’s `chat_id`. `from` and `contact_id` are the member who sent it, and `to` is `null`:

```json title="A text in a group, as message.received carries it"
{
  "id": "msg_3Lp3VsC7hGqE5tZyKbWn2d",
  "object": "message",
  "direction": "in",
  "state": "received",
  "to": null,
  "from": "+15555550187",
  "chat_id": "chat_1Hq2LxW9cVbN3mKpRtYs0a",
  "contact_id": "ct_2Bf8QzD4kJmA6nXwEuTr1c",
  "text": "Thanks Dana! Do we need to bring anything to closing?",
  "service": "imessage",
  "received_at": "2026-11-13T20:02:00.000Z"
}
```

To read one group’s history:

```bash
curl "https://usebluebot.com/api/v1/messages?chat_id=chat_1Hq2LxW9cVbN3mKpRtYs0a" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const page = await client.messages.list({
  chatId: 'chat_1Hq2LxW9cVbN3mKpRtYs0a',
});
console.log(page.data);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

page = client.messages.list(chat_id="chat_1Hq2LxW9cVbN3mKpRtYs0a")
print(page.data)
```

## Starting a group

BlueBot can’t make a new group chat. To text a new group from your code, start it once by hand:

1. In Messages on your Mac or iPhone, start the group with everyone in it and send the first text.
2. If you haven’t texted them all through BlueBot, set **Which chats to copy** to **Everything**, at least until the group shows up.
3. Find the group with `GET /v1/chats?is_group=true` and keep its `id`.

From then on your code can text into it whenever it needs to.

## What else BlueBot can’t do in a group

BlueBot can’t add or remove people, rename the group, leave it, or send a tapback in it. Those all need Apple’s private frameworks. [Capabilities](https://usebluebot.com/docs/concepts/capabilities) lists what a Mac can and can’t do.
