<!-- VanceTel docs · /docs/group-sms -->

# Group SMS

Group SMS lets you open one conversation with several recipients from a single business number. Every reply threads back into that same conversation, addressable by a stable `conversationId`, so your software — and the softphone inbox — sees one thread instead of a scatter of one-to-one messages.

  Group conversations follow the same write- and event-oriented model as a single SMS: you create
  the conversation and send into it, then subscribe to [Webhooks](/developers/docs/webhooks) for inbound
  replies and per-participant delivery.

## Create a group

Open a group conversation by sending the first message with more than one recipient in `to`. The `from` number must be an [E.164](/developers/glossary/e164) number you own; each recipient is also E.164. The response returns a `conversationId` — store it. Everything that follows in this thread is keyed to it.

**curl**

```bash
curl https://api.netexem.com/v1/messages \
  -H "Authorization: Bearer $NETEXEM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+15551234567",
    "to": ["+15557654321", "+15557654322", "+15557654323"],
    "body": "Kickoff call moved to 3pm — works for everyone?"
  }'
```

**Node**

```ts
const res = await fetch("https://api.netexem.com/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NETEXEM_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from: "+15551234567",
    to: ["+15557654321", "+15557654322", "+15557654323"],
    body: "Kickoff call moved to 3pm — works for everyone?",
  }),
});
const message = await res.json();
const conversationId = message.conversationId;
```

**Python**

```python
import os, requests

res = requests.post(
    "https://api.netexem.com/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['NETEXEM_API_KEY']}"},
    json={
        "from": "+15551234567",
        "to": ["+15557654321", "+15557654322", "+15557654323"],
        "body": "Kickoff call moved to 3pm — works for everyone?",
    },
)
message = res.json()
conversation_id = message["conversationId"]
```

  All numbers use [E.164 format](/developers/glossary/e164) — a leading `+` and country code, e.g.
  `+15557654321`. A single recipient (a plain string `to`) opens a one-to-one thread instead; see
  [Send an SMS](/developers/docs/sms).

To send another message into an existing group, target the conversation by its id rather than re-listing recipients:

```json
{
  "conversationId": "cv_01h…",
  "body": "Confirmed — invite updated."
}
```

## Replies & threading

When any participant texts back, the reply threads into the same conversation. We fire a signed `message.received` webhook carrying the originating `conversationId`, so you can correlate it without guessing. The softphone surfaces the same thread in real time.

A group conversation object collects the participants, the originating number, and message status. Look it up with `GET /messages/{id}` for an individual message, or read the `conversationId` carried on every related message and webhook to stitch the thread together.

```json
{
  "conversationId": "cv_01h…",
  "from": "+15551234567",
  "participants": [
    { "phone": "+15557654321", "status": "delivered" },
    { "phone": "+15557654322", "status": "delivered" },
    { "phone": "+15557654323", "status": "queued" }
  ],
  "messages": [
    {
      "id": "msg_01h…",
      "from": "+15551234567",
      "body": "Kickoff call moved to 3pm — works for everyone?",
      "direction": "outbound",
      "status": "sent",
      "createdAt": "2026-05-31T18:04:21Z"
    },
    {
      "id": "msg_01h…",
      "from": "+15557654321",
      "body": "Works for me.",
      "direction": "inbound",
      "status": "delivered",
      "createdAt": "2026-05-31T18:05:02Z"
    }
  ],
  "createdAt": "2026-05-31T18:04:21Z"
}
```

  Each inbound reply arrives as its own `message.received` event tagged with the `conversationId`.
  Acknowledge with a `2xx`; non-`2xx` responses are retried with backoff. See
  [Webhooks](/developers/docs/webhooks).

## Participants

Add or remove participants without losing the thread — the `conversationId` stays stable across changes.

- **Add** a participant by including their E.164 number when you send into the conversation; new participants join the existing thread.
- **Remove** a participant to stop including them on subsequent messages. History already delivered to them is unaffected.

```json
{
  "conversationId": "cv_01h…",
  "addParticipants": ["+15557654324"],
  "removeParticipants": ["+15557654323"],
  "body": "Adding Priya, dropping the old thread."
}
```

Delivery is tracked **per participant**: each entry in `participants` carries its own `status` (`queued`, `sent`, `delivered`, `failed`), so one unreachable number never blocks the rest of the group. Watch delivery transitions through delivery-receipt [Webhooks](/developers/docs/webhooks), each keyed to the conversation and the participant it concerns.

  A participant who replies STOP is opted out and removed from future sends to the group
  automatically. Opt-out is honored per number, account-wide — see
  [Opt-out & compliance](/developers/docs/opt-out).

## Next steps

- [Send an SMS](/developers/docs/sms) — the full message object, MMS and delivery receipts
- [Webhooks](/developers/docs/webhooks) — subscribe to inbound replies and per-participant delivery
- [Opt-out & compliance](/developers/docs/opt-out) — STOP handling and A2P registration
