> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ibubbl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Group Conversations

> How iBubbl represents and routes iMessage group conversations.

iBubbl supports iMessage group conversations — threads with 2 or more participants in addition to your iBubbl line. Groups work alongside 1:1 conversations and share the same [`/v1/messages`](https://docs.ibubbl.com/api-reference/messages/send) API surface, with additional fields for routing.

## Conversation kind

Messages carry a `conversation_kind` field — on the `message.inbound` webhook and on `GET /v1/messages/{id}` / `POST /v1/messages` responses:

* `one_to_one` — a single contact plus your iBubbl line
* `group` — your iBubbl line plus 2 or more contacts

Branch your integration on `conversation_kind`. The same message lifecycle applies to both kinds — only the addressing differs. (One exception: `message.queued` fires only for 1:1 sends.)

## Group identity

Each group conversation has an opaque `chat_guid`, for example `any;+;067ace6caf6c43aaa2f7d643975e15ea`. Treat it as an opaque string: don't parse it, and branch on `conversation_kind` rather than its prefix.

**No webhook event carries `chat_guid`.** To learn it:

* **A group that messaged you:** take the `message_id` from the `message.inbound` event and call `GET /v1/messages/{id}` — the response includes the group's `chat_guid`.
* **A group you created:** poll `GET /v1/messages/{id}` for your first message until `chat_guid` is non-null (see [Lifecycle of a new group](#lifecycle-of-a-new-group)).
* **A group you've sent to:** the `POST /v1/messages` response for an existing-group send includes it.

**`chat_guid` can change.** When a participant is added to a group (from the iBubbl dashboard), the group gets a new `chat_guid`, and a send to the old value returns `404 group_not_found`. If that happens, look up the current value again with `GET /v1/messages/{id}` on a recent message from the group.

Use `chat_guid` to send into an existing group — see [Sending messages](https://docs.ibubbl.com/api-reference/messages/send.md).

## Participants

The `participants` array on the `message.inbound` webhook lists the group's participants other than your iBubbl line:

```json theme={null}
{
  "participants": [
    {"phone": "+13477914509", "first_name": "Sarah", "last_name": "Smith"},
    {"phone": "+17187699436", "first_name": "Bob",   "last_name": "Jones"}
  ]
}
```

For a 1:1 conversation the array holds the one contact.

> [!WARNING]
>
> iBubbl does not currently see participants leaving or being removed from a group, so the list can include people who are no longer in the group. Treat it as "everyone who has been in this group", not the live roster.

## Sender attribution

On inbound webhook events for group conversations, `sender_phone` identifies which specific participant sent the message:

```json theme={null}
{
  "type": "message.inbound",
  "data": {
    "message_id": "5b6c7d8e-9f0a-1b2c-3d4e-5f6a7b8c9d0e",
    "from_number": "+13477914509",
    "sender_phone": "+13477914509",
    "conversation_kind": "group",
    "participants": [
      {"phone": "+13477914509", "first_name": "Sarah", "last_name": "Smith"},
      {"phone": "+17187699436", "first_name": "Bob",   "last_name": "Jones"}
    ],
    "body": "What time tomorrow?"
  }
}
```

`sender_phone` always equals `from_number`; both are kept so 1:1 integrations work unchanged. Either can be an Apple ID email address rather than a phone number when the sender uses one for iMessage.

## Suppression in groups

If **any** participant of a group is on your suppression list, iBubbl blocks **all** outbound to the group with `422 group_outbound_blocked_suppression`:

```json theme={null}
{
  "detail": {
    "error": "group_outbound_blocked_suppression",
    "message": "Cannot send to this group — 1 participant(s) have opted out."
  }
}
```

When you **create** a new group (`participant_phones`) and some of the numbers are opted out, the error also lists them in `blocked_phones` (as stored on your suppression list, so the format can differ from what you sent). A send into an existing group doesn't include `blocked_phones`.

This is deliberate: sending into a group where one participant opted out would deliver to that participant, defeating the opt-out. Because participant removals aren't seen (above), and an opt-out can't be undone (see [Suppression & Opt-Outs](https://docs.ibubbl.com/concepts/suppression.md)), a group with an opted-out participant stays blocked. To keep messaging the others, create a new group without that person.

## Sending to groups

Two of the four request shapes on `POST /v1/messages` are for groups:

> [card] Existing group
>
> Send into a group you already know by `chat_guid` (see [Group identity](#group-identity) for how to get it).

> [card] New group
>
> Pass `participant_phones` (2+ E.164 numbers) and an optional `group_name`. iBubbl creates the iMessage group and sends your first message in one operation.

See [`POST /v1/messages`](https://docs.ibubbl.com/api-reference/messages/send) for full examples.

## Lifecycle of a new group

When you create a new group via `participant_phones`:

1. iBubbl validates the request: at least 2 distinct people (`422 insufficient_participants` if the numbers resolve to fewer — for example the same number twice), and no opted-out numbers.
2. The first message is accepted as `pending`, and the response returns right away with `chat_guid: null`.
3. When the first message goes out, the iMessage group is created and the group's `chat_guid` is recorded. If the message is held for the contacts' [sending hours](https://docs.ibubbl.com/concepts/working-hours.md), that happens when the hold ends.
4. The message moves to `sent` and the `message.sent` webhook fires.

To address the group on later sends, poll `GET /v1/messages/{id}` until `chat_guid` is non-null, store it, and use the existing-group shape from then on.

> [!NOTE]
>
> The `message.sent` event for a new group's first message can occasionally be delivered twice. De-duplicate on `data.message_id` plus `type`.

## Limitations

These apply in v1:

* **No participant management.** The API can't add or remove participants, and removals made elsewhere aren't seen (see [Participants](#participants)). Adding a participant from the dashboard changes the group's `chat_guid`.
* **No renaming.** `group_name` can only be set when the group is created, and later renames aren't picked up.
* **No editing or unsending.** The v1 API can't edit or unsend a message you sent. When a contact edits a message they sent you, you receive `message.edited`; when a contact unsends one, no event fires.
* **No attachments.** `POST /v1/messages` sends text only, to 1:1 contacts and groups alike.
* **At least 2 participants.** Single-participant "groups" aren't a thing in iMessage; use the `to` or `contact_id` shape for 1:1 sends.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.