Groups

A group is a conversation with more than two people in it. It is listed, created and changed here, and messaged with the ordinary send endpoint.

List groups

GET/v1/groups?channelId=chn_sales01
GET/v1/groups/:chatId

This is the conversation list filtered to groups, so the short-page rule applies to it: the filter runs after the page comes back, so a page can be short or empty while cursor is still non-null. Keep paging until the cursor is null. A Group is a Chat with kind: "group" plus one field, pictureUrl.

A single group read carries members. Asking for a one-to-one conversation on a groups route is 409 CONFLICT ("that conversation is not a group"), not a 404 - the conversation exists, it is just not a group.

Create a group

POST/v1/groups
cURL
curl -X POST https://api.sendveo.com/v1/groups \
  -H "X-API-KEY: sv_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "subject": "Deliveries north",
        "members": ["+212670111222", "+212671333444"],
        "text": "Welcome to the deliveries group." }'
201 Created
{
  "group": {
    "id": "cht_m8k3x7q2a1b4",
    "chatId": "120363001122334455@g.us",
    "channelId": "chn_sales01",
    "kind": "group",
    "name": "Deliveries north",
    "pictureUrl": "https://api.sendveo.com/v1/groups/120363001122334455%40g.us/picture",
    "members": [
      { "id": "cmb_1", "phone": "+212661234567", "name": null, "role": "super_admin", "self": true },
      { "id": "cmb_2", "phone": "+212670111222", "name": "Khadija Alaoui", "role": "member", "self": false }
    ]
  }
}

Every member is checked before the group is created. WhatsApp does not refuse an unreachable member, it silently leaves them out - so a group would come back one person short with no explanation. Sendveo looks each one up first and refuses the whole create with 400 VALIDATION_FAILED, details[0].path = "members.N", naming the number. Nothing is created. The same check runs when adding a member, with the path phone.

A group is created by starting a conversation in it, so text becomes its first message. Omit it and the group is created with nothing said. At most 50 members per call, canonicalised and de-duplicated; a malformed one is 400 naming its index.

Members

POST/v1/groups/:chatId/members
DELETE/v1/groups/:chatId/members/:phone

A member carries role: member, admin or super_admin. It is member unless WhatsApp discloses an admin marker, and its published attendee shape carries none - so treat a non-member role as reliable and member as "we were not told otherwise". Do not build a permission check on it: WhatsApp refuses an action the number may not perform regardless, and a check built on the role would hide the action from people who can do it.

leftAt is set rather than the row deleted. A message from somebody who left the group last week still has to resolve to a name.

Removing your OWN number is refused with 409 CONFLICT: "to remove your own number from a group, leave the group instead". A script walking a member list would otherwise leave the group by accident.

Leaving

POST/v1/groups/:chatId/leave

Leaving uses the number verified at connect time, never one from the request. A channel whose number was never read back cannot leave, and answers 409 CONFLICT.

200 OK
{ "left": true, "chatId": "cht_m8k3x7q2a1b4" }

Sending to a group

POST/v1/messages

Sending to a group is POST /v1/messages with the group chatId. It is an ordinary chat id and needs no new endpoint and no new scope - messages:send, as always. Reactions, forwards, replies, attachments and the read and typing actions all work in a group exactly as they do in a one-to-one conversation.

cURL
curl -X POST https://api.sendveo.com/v1/messages \
  -H "X-API-KEY: sv_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "channelId": "chn_sales01",
        "chatId": "120363001122334455@g.us",
        "text": "The gate code is unchanged." }'

Group messages

Two fields are added to every Message, and to the message.received webhook. Both are additive and both are null on a one-to-one message, which is what a handler written before groups existed keeps seeing.

200 OK
{
  "id": "msg_8Rm5",
  "channelId": "chn_sales01",
  "chatId": "120363001122334455@g.us",
  "direction": "INBOUND",
  "from": "+212671333444",
  "senderName": "Omar Idrissi",
  "text": "The Rabat round leaves at 8am tomorrow.",
  "type": "text",
  "status": "RECEIVED",
  "group":  { "chatId": "120363001122334455@g.us", "id": "cht_m8k3x7q2a1b4", "name": "Atlas team - deliveries" },
  "author": { "phone": "+212671333444", "name": "Omar Idrissi" }
}

group identifies the conversation: group.id is the Sendveo chat id when Sendveo holds the row and null otherwise, while group.chatId and group.name are always meaningful. author is WHO said it inside the group. It is null on a one-to-one message, because there the sender IS the conversation and from already says so, and null on an outbound group message, which was said by the connected number. from keeps its V1 meaning and carries the author on an inbound group message, so a handler that only knows from still reads a sender.

Group pictures

GET/v1/groups/:chatId/picture

A group pictureUrl is always present, and a group with no picture answers 404 there. That is one request rather than an extra upstream call on every group in a list. It is the same proxy the contact picture uses, with the same rules: chosen content type, nothing stored, 2 MB cap.

Group events

Three events are relayed to your webhook. They are about a conversation, so they carry chat where the message events carry message, plus by. Being removed and leaving are one event with member.removed telling them apart; a group being created and a group being renamed are one event too.

EventFired whenExtra fields
group.member_joinedSomebody was added to a group.member, by
group.member_leftSomebody left, or was removed.member.removed, by
group.updatedA group was created, or its subject changed.subject, by

Scopes

Reading groups and changing them are separate authorities. *:read grants groups:read like every other read scope. A key issued before these scopes existed does not carry them and answers 403; issue a new key.

ScopeGrants
groups:readList and read groups, and group pictures.
groups:manageCreate a group, add and remove members, leave.
WhatsApp groups API · Sendveo docs