Skip to main content
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 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).
  • 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.

Participants

The participants array on the message.inbound webhook lists the group’s participants other than your iBubbl line:
For a 1:1 conversation the array holds the one contact.
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:
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:
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), 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:

Existing group

Send into a group you already know by chat_guid (see Group identity for how to get it).

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 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, 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.
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). 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.