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

json
{
  "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
}
  • announce true means only admins can send.
  • locked true means only admins can edit group info.
  • member_add_mode is admin_add or all_member_add.
  • linked_parent_jid is present for a group linked to a community.
  • description, owner_jid, participants, phone_number and lid are left out when empty.
  • phone_number, when present, is a full phone JID such as [email protected], not bare digits.
  • phone_resolved is false when WAgate could not work out the person's phone number. owner_resolved says the same for the owner.

List groups

bash
curl "https://api-wagate.socialground.co/v1/sessions/<CHANNEL_ID>/groups" \
  -H "Authorization: Bearer <CHANNEL_TOKEN>"
json
{
  "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), or stale (WhatsApp is throttling this number, so the last good list is served).
  • stale: true exactly when cache is stale.

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

bash
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

bash
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]"]}'
json
{
  "results": [
    { "jid": "[email protected]", "status": "ok", "lid": "100000000000000@lid", "matched_by": "a" }
  ]
}
  • action is add, remove, promote or demote.
  • participants is required, 1 to 50 per call for every action. Naming the same person twice answers 400 invalid_request. Send each person once.
  • The answer has one entry per person, so one person failing does not fail the others. Each entry's jid is the string you sent.
  • status is ok, error_<code> or unknown. An error_<code> entry also has an error sentence. 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_by says how WAgate attached WhatsApp's answer to that person: a, c, single or unknown.
  • 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_reclaimed with ambiguous. See Errors.

Subject, description, invite link

bash
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

bash
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"}'
json
{
  "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:

json
{
  "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 order announce, 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 holds false, false and "", which are placeholders, not the group's state.
  • mismatch: the settings WhatsApp accepted but that did not take on the read-back. It is null unless that read-back ran and found a difference.
  • applied and mismatch are both null when WAgate could not report progress: when the request failed before any setting was tried (for example 409 not_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.