Groups
List, create and manage groups: participants, subject, description, settings, invite link.
GET/v1/sessions/<CHANNEL_ID>/groups
List this channel's groups.
POST/v1/sessions/<CHANNEL_ID>/groups
Create a group.
GET/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>
Get one group.
POST/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>/participants
Add, remove, promote or demote people.
GET/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>/invite-link
Get the invite link.
PUT/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>/subject
Set the subject.
PUT/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>/description
Set or clear the description.
PUT/v1/sessions/<CHANNEL_ID>/groups/<GROUP_JID>/settings
Change settings.
A group is addressed by its group JID, for example [email protected].
The group object
{
"jid": "[email protected]",
"name": "Team",
"description": "Team updates",
"owner_jid": "[email protected]",
"created": "2026-09-01T03:00:00Z",
"participants": [
{
"jid": "[email protected]",
"phone_number": "[email protected]",
"lid": "100000000000000@lid",
"phone_resolved": true,
"is_admin": true,
"is_super_admin": true
}
],
"participant_count": 1,
"announce": false,
"locked": false,
"member_add_mode": "admin_add",
"is_community": false,
"is_default_subgroup": false,
"is_incognito": false,
"owner_resolved": true
}announcetrue means only admins can send.lockedtrue means only admins can edit group info.member_add_modeisadmin_addorall_member_add.linked_parent_jidis present for a group linked to a community.description,owner_jid,participants,phone_numberandlidare left out when empty.phone_number, when present, is a full phone JID such as[email protected], not bare digits.phone_resolvedis false when WAgate could not work out the person's phone number.owner_resolvedsays the same for the owner.
List groups
curl "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups" \
-H "Authorization: Bearer <CHANNEL_TOKEN>"{
"groups": [ { "jid": "[email protected]", "name": "Team", "participant_count": 12 } ],
"fetched_at": "2026-09-17T03:00:00.123456789Z",
"stale": false,
"cache": "hit"
}The list may be served from a recent copy. Every answer says how fresh it is:
fetched_at: when WhatsApp produced this list.cache:miss(WhatsApp was asked for this answer),hit(served from a recent copy), orstale(WhatsApp is throttling this number, so the last good list is served).stale:trueexactly whencacheisstale.
To force a list WhatsApp produced for this request, send the request header X-Wagate-Groups-Fresh: required. Any other value answers 400 invalid_request. A fresh read asks WhatsApp every time, so it can answer 429 whatsapp_rate_limited instead of a cached list. Use it only when you are about to act on the list.
Creating a group, renaming it, changing its description or participants, and leaving a group each drop the cached list for the channel.
Create a group
curl -X POST "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups" \
-H "Authorization: Bearer <CHANNEL_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"subject": "Team", "participants": ["66XXXXXXXXX"]}'Answers 201 with the group object.
subject: required, 1 to 25 characters.participants: optional, at most 50. Phone numbers or JIDs.parent_jid: optional. Creates the group inside that community.
A create counts as one group add for the group, one for each participant, and one more with parent_jid. On the sandbox channel these come out of the sandbox group-add allowance. Where warm-up protection is on, they come out of today's group-add allowance and can answer 429 daily_cap_group_add.
Change participants
curl -X POST "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups/[email protected]/participants" \
-H "Authorization: Bearer <CHANNEL_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"action": "add", "participants": ["[email protected]"]}'{
"results": [
{ "jid": "[email protected]", "status": "ok", "lid": "100000000000000@lid", "matched_by": "a" }
]
}actionisadd,remove,promoteordemote.participantsis required, 1 to 50 per call for every action. Naming the same person twice answers 400invalid_request. Send each person once.- The answer has one entry per person, so one person failing does not fail the others. Each entry's
jidis the string you sent. statusisok,error_<code>orunknown. Anerror_<code>entry also has anerrorsentence. The codes WhatsApp returns per person: 403 not allowed or the person's privacy blocks the add; 408 left recently; 409 already in the group; 401 the person blocked this number; 404 not on WhatsApp. Any other code reads "unspecified participant error".matched_bysays how WAgate attached WhatsApp's answer to that person:a,c,singleorunknown.- If WAgate cannot tell which person an answer belongs to, that result is
status: "unknown". The change may have applied. Read the group before you retry. - Each person added counts as one group add. Remove, promote and demote do not.
- An add can answer 503
lane_reclaimedwithambiguous. See Errors.
Subject, description, invite link
curl -X PUT "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups/[email protected]/subject" \
-H "Authorization: Bearer <CHANNEL_TOKEN>" -H "Content-Type: application/json" \
-d '{"subject": "New name"}'
# {"status":"renamed"}
curl -X PUT "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups/[email protected]/description" \
-H "Authorization: Bearer <CHANNEL_TOKEN>" -H "Content-Type: application/json" \
-d '{"description": "Updates, one a day"}'
# the updated group object
curl "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups/[email protected]/invite-link" \
-H "Authorization: Bearer <CHANNEL_TOKEN>"
# {"invite_link":"https://chat.whatsapp.com/XXXXXXXX"}- Subject: 1 to 25 characters. The answer is
{"status": "renamed"}. - Description: up to 2048 characters. An empty string removes it. WAgate reads the group back after the change, and the answer is the group object. If the read-back does not match, the call fails instead of answering 200.
- Invite link:
{"invite_link": "..."}.
Change settings
curl -X PUT "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups/[email protected]/settings" \
-H "Authorization: Bearer <CHANNEL_TOKEN>" -H "Content-Type: application/json" \
-d '{"announce": true, "locked": false, "member_add_mode": "admin_add"}'{
"jid": "[email protected]",
"applied": ["announce", "locked", "member_add_mode"],
"observed": { "announce": true, "locked": false, "member_add_mode": "admin_add" }
}A 200 always has exactly these three keys. Send at least one setting. Settings you leave out stay as they are. The settings are applied one at a time, then the group is read back. A 200 means every setting you sent was applied and the read-back matches.
Any failure is an error, never a 200 with a note. The error body is the usual code and error plus three keys that say how far it got:
{
"code": "invalid_request",
"error": "...",
"applied": ["announce", "locked"],
"observed": { "announce": false, "locked": true, "member_add_mode": "admin_add" },
"mismatch": ["announce"]
}applied: the settings WhatsApp accepted before the failure, in the orderannounce,locked,member_add_mode. A setting not in the list was not applied, and the ones after a failed setting were not attempted.observed: the group as read back. It is only meaningful when every setting was applied and the read-back ran. Before that, it holdsfalse,falseand"", which are placeholders, not the group's state.mismatch: the settings WhatsApp accepted but that did not take on the read-back. It isnullunless that read-back ran and found a difference.appliedandmismatchare bothnullwhen WAgate could not report progress: when the request failed before any setting was tried (for example 409not_linked), and also when the channel's state changed between applying the settings and reading them back (for example it was stood down). In that second case settings may have applied, so read the group before you retry.
If mismatch is a non-empty list, WhatsApp accepted those settings and did not act on them, so read the group before you retry. Otherwise, retry only the settings missing from applied.
The status and code are those of the underlying failure: a WhatsApp refusal or a read-back mismatch is 400 invalid_request, a WhatsApp throttle is 429 whatsapp_rate_limited, and channel states are the usual codes such as 409 not_linked.
Errors on these routes
409 not_linked, 409 stood_down, 403 blocked, 429 daily_cap_group_add (where warm-up protection is on), 429 sandbox_allowance_exceeded (sandbox group adds), 429 whatsapp_rate_limited, 503 lane_reclaimed. See Errors.