Groupes

Un groupe est une conversation à plus de deux personnes. Il se liste, se crée et se modifie ici, et on y écrit avec le point de terminaison d'envoi ordinaire.

Lister les groupes

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

C'est la liste des conversations filtrée sur les groupes : la règle de la page courte s'y applique donc. Le filtre s'exécute après le retour de la page, si bien qu'une page peut être courte ou vide alors que cursor n'est pas encore nul. Continuez de paginer jusqu'à ce que le curseur vaille null. Un Group est un Chat avec kind: "group" plus un champ, pictureUrl.

La lecture d'un groupe seul porte members. Demander une conversation en tête-à-tête sur une route de groupes donne 409 CONFLICT (« cette conversation n'est pas un groupe »), pas un 404 : la conversation existe, elle n'est simplement pas un groupe.

Créer un groupe

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 }
    ]
  }
}

Chaque membre est vérifié avant la création du groupe. WhatsApp ne refuse pas un membre injoignable, il l'écarte en silence : le groupe reviendrait donc avec une personne en moins et sans explication. Sendveo vérifie chacun d'abord et refuse la création entière avec 400 VALIDATION_FAILED, details[0].path = "members.N", en nommant le numéro. Rien n'est créé. Le même contrôle s'exécute à l'ajout d'un membre, avec le chemin phone.

Un groupe se crée en y démarrant une conversation : text devient donc son premier message. Omettez-le et le groupe est créé sans que rien n'ait été dit. Au plus 50 membres par appel, canonisés et dédupliqués ; un membre mal formé donne 400 en nommant son index.

Membres

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

Un membre porte un role : member, admin ou super_admin. Il vaut member tant que WhatsApp ne divulgue pas de marqueur d'administrateur, et la forme de participant qu'il publie n'en porte aucun : tenez donc un rôle autre que member pour fiable, et member pour « on ne nous a pas dit le contraire ». N'y adossez pas un contrôle de permission : WhatsApp refuse de toute façon une action que le numéro n'a pas le droit d'effectuer, et un contrôle fondé sur le rôle cacherait l'action à des gens qui en ont le droit.

leftAt est renseigné plutôt que la ligne supprimée. Un message de quelqu'un qui a quitté le groupe la semaine dernière doit toujours pouvoir être rattaché à un nom.

Retirer VOTRE propre numéro est refusé avec 409 CONFLICT : « pour retirer votre propre numéro d'un groupe, quittez plutôt le groupe ». Sans cela, un script qui parcourt une liste de membres quitterait le groupe par accident.

Quitter un groupe

POST/v1/groups/:chatId/leave

Le départ utilise le numéro vérifié au moment de la connexion, jamais un numéro venu de la requête. Un canal dont le numéro n'a jamais été relu ne peut pas quitter, et répond 409 CONFLICT.

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

Envoyer dans un groupe

POST/v1/messages

Envoyer dans un groupe, c'est POST /v1/messages avec le chatId du groupe. C'est un identifiant de conversation ordinaire : ni nouveau point de terminaison, ni nouvelle portée, messages:send comme toujours. Réactions, transferts, réponses, pièces jointes et les actions « lu » et « en train d'écrire » fonctionnent dans un groupe exactement comme dans une conversation en tête-à-tête.

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." }'

Messages de groupe

Deux champs s'ajoutent à chaque Message, ainsi qu'au webhook message.received. Tous deux sont purement additifs et valent null sur un message en tête-à-tête, ce que continue de voir un gestionnaire écrit avant les groupes.

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 identifie la conversation : group.id est l'identifiant de conversation Sendveo lorsque Sendveo détient la ligne, et null sinon, tandis que group.chatId et group.name ont toujours un sens. author est QUI a parlé dans le groupe. Il vaut null sur un message en tête-à-tête, parce que là l'expéditeur EST la conversation et que from le dit déjà, et null sur un message de groupe sortant, dit par le numéro connecté. from garde son sens de la V1 et porte l'auteur sur un message de groupe entrant, si bien qu'un gestionnaire qui ne connaît que from lit toujours un expéditeur.

Photos de groupe

GET/v1/groups/:chatId/picture

Le pictureUrl d'un groupe est toujours présent, et un groupe sans photo y répond 404. Cela coûte une requête plutôt qu'un appel amont supplémentaire pour chaque groupe d'une liste. C'est le même proxy que pour la photo de contact, avec les mêmes règles : type de contenu choisi, rien de stocké, plafond de 2 Mo.

Événements de groupe

Trois événements sont relayés vers votre webhook. Ils portent sur une conversation, donc ils portent chat là où les événements de message portent message, plus by. Être retiré et partir forment un seul événement, que member.removed permet de distinguer ; la création d'un groupe et son renommage sont un seul événement eux aussi.

ÉvénementDéclenché quandChamps supplémentaires
group.member_joinedQuelqu'un a été ajouté à un groupe.member, by
group.member_leftQuelqu'un est parti, ou a été retiré.member.removed, by
group.updatedUn groupe a été créé, ou son sujet a changé.subject, by

Portées

Lire les groupes et les modifier sont deux autorités distinctes. *:read accorde groups:read comme toute autre portée de lecture. Une clé émise avant l'existence de ces portées ne les porte pas et répond 403 ; émettez une nouvelle clé.

PortéeAccorde
groups:readLister et lire les groupes, et les photos de groupe.
groups:manageCréer un groupe, ajouter et retirer des membres, quitter.
API groupes WhatsApp · Docs Sendveo