WhatsApp groups
A group is a WhatsApp group or community your agent is a member of and that you chose to track in the dashboard. The API exposes tracked groups read-only: the group itself, its members, its messages and its membership events.
Endpoints
Section titled “Endpoints”| Method | Path | Scope |
|---|---|---|
| GET | /groups |
groups:read |
| GET | /groups/{id} |
groups:read |
| GET | /groups/{id}/members |
groups:read |
| GET | /groups/{id}/messages |
groups:read |
| GET | /groups/{id}/events |
groups:read |
What “tracked” means
Section titled “What “tracked” means”WhatSetter only stores what happens in the groups you track from the dashboard’s groups page. A tracked group is a group with status active: its messages are recorded, its members are synced, and the agent can reply in it according to its mode. Paused, archived or left groups keep their history but stop being counted.
A workspace can track up to 500 active groups. Tracking more from the dashboard is refused until you pause or archive some.
List groups
Section titled “List groups”curl "https://app.whatsetter.com/api/v1/groups?status=active&limit=25" \ -H "Authorization: Bearer ws_live_…"const res = await fetch('https://app.whatsetter.com/api/v1/groups?status=active&limit=25', { headers: { Authorization: 'Bearer ws_live_…' },});const { data: groups, pagination } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/groups", params={"status": "active", "limit": 25}, headers={"Authorization": "Bearer ws_live_…"},)groups = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c101", "whatsapp_id": "120363012345678901@g.us", "name": "Webinar 24 Sept", "description": "Questions before the live session", "participants_count": 148, "messages_count": 912, "status": "active", "ai_enabled": true, "invite_url": "https://chat.whatsapp.com/…", "campaign_id": "acme-community-1-cd34", "created_at": "2026-09-01T09:00:00.000Z" } ], "pagination": { "has_more": false, "next_cursor": "66f1a2b3c4d5e6f7a8b9c101" }}Filters: status (active, paused, archived, left) and community_id (only groups of one WhatsApp Community, the community.id of a group). Newest first.
Get one group
Section titled “Get one group”GET /groups/{id} returns the same fields plus the details:
{ "data": { "id": "66f1a2b3c4d5e6f7a8b9c101", "whatsapp_id": "120363012345678901@g.us", "name": "Webinar 24 Sept", "description": "Questions before the live session", "participants_count": 148, "messages_count": 912, "status": "active", "ai_enabled": true, "invite_url": "https://chat.whatsapp.com/…", "campaign_id": "acme-community-1-cd34", "created_at": "2026-09-01T09:00:00.000Z", "is_admin": true, "ai_reply_mode": "mentions_only", "intent": "webinar", "community": { "id": "120363098765432101@g.us", "name": "Acme Community", "role": "sub" }, "sync_status": "ready", "synced_at": "2026-09-18T22:00:00.000Z", "picture_url": "https://pps.whatsapp.net/…", "updated_at": "2026-09-18T22:00:00.000Z" }}| Field | Meaning |
|---|---|
is_admin |
Whether the connected number is an admin of the group. |
ai_reply_mode |
mentions_only or all_messages. |
intent |
community, webinar or broadcast. |
community |
The WhatsApp Community the group belongs to, null for a standalone group. role: "announce" is the community’s announcements group, sub a regular sub-group. |
sync_status |
State of the message-history import: idle, pending, syncing, ready, error. |
picture_url |
An expiring WhatsApp CDN link to the group picture. Fetch it when you need it, do not store it. |
Members
Section titled “Members”curl "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/members?status=active&limit=100" \ -H "Authorization: Bearer ws_live_…"const res = await fetch( 'https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/members?status=active&limit=100', { headers: { Authorization: 'Bearer ws_live_…' } },);const { data: members, pagination } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/members", params={"status": "active", "limit": 100}, headers={"Authorization": "Bearer ws_live_…"},)members = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c111", "phone": "33612345678", "name": "Julien", "role": "member", "status": "active", "joined_at": "2026-09-02T10:15:00.000Z", "left_at": null, "joined_source": "event", "messages_count": 12 } ], "pagination": { "has_more": false, "next_cursor": "66f1a2b3c4d5e6f7a8b9c111" }}role is superadmin, admin or member. status becomes left once the person leaves. phone is null when WhatsApp only exposed an anonymous id for that member.
Messages
Section titled “Messages”The group transcript, newest first. since and until bound the window, sender keeps one member’s messages (international digits), from_agent=true keeps what WhatSetter sent through the connected number, from_agent=false keeps only members’ messages.
curl "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/messages?since=2026-09-18T00:00:00Z&from_agent=false" \ -H "Authorization: Bearer ws_live_…"const res = await fetch( 'https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/messages?since=2026-09-18T00:00:00Z&from_agent=false', { headers: { Authorization: 'Bearer ws_live_…' } },);const { data: messages, pagination } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/messages", params={"since": "2026-09-18T00:00:00Z", "from_agent": "false"}, headers={"Authorization": "Bearer ws_live_…"},)messages = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c121", "whatsapp_message_id": "false_120363012345678901@g.us_3EB0C8F2A1D4B5E6F7A8", "sender": { "phone": "33612345678", "name": "Julien" }, "from_agent": false, "ai_generated": false, "text": "Will the replay be available?", "type": "USER_MESSAGE", "is_mention": true, "has_media": false, "media_type": null, "sent_at": "2026-09-18T18:02:11.000Z" } ], "pagination": { "has_more": false, "next_cursor": "66f1a2b3c4d5e6f7a8b9c121" }}sender is null when neither a phone nor a name is known. ai_generated is a subset of from_agent: true only for AI replies, false for manual replies sent from the dashboard. Media is flagged with has_media and media_type (image, video, audio, document…) but never linked.
Events
Section titled “Events”Joins and leaves, as observed from live WhatsApp events and sync passes. Filters: type (join, leave), since, until.
curl "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/events?type=join&since=2026-09-18T00:00:00Z" \ -H "Authorization: Bearer ws_live_…"const res = await fetch( 'https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/events?type=join&since=2026-09-18T00:00:00Z', { headers: { Authorization: 'Bearer ws_live_…' } },);const { data: events, pagination } = await res.json();import requests
r = requests.get( "https://app.whatsetter.com/api/v1/groups/66f1a2b3c4d5e6f7a8b9c101/events", params={"type": "join", "since": "2026-09-18T00:00:00Z"}, headers={"Authorization": "Bearer ws_live_…"},)events = r.json()["data"]{ "data": [ { "id": "66f1a2b3c4d5e6f7a8b9c131", "type": "join", "phone": "33612345678", "name": "Julien", "occurred_at": "2026-09-18T09:30:00.000Z", "source": "event", "actor_phone": "33698765432" } ], "pagination": { "has_more": false, "next_cursor": "66f1a2b3c4d5e6f7a8b9c131" }}source says how the event was observed: event (live), sync_detected, backfill or webhook_replay. actor_phone is the admin who added or removed the member, when WhatsApp reported one.
Errors you will meet
Section titled “Errors you will meet”| HTTP | code |
When |
|---|---|---|
| 401 | missing_api_key, invalid_api_key |
Key absent, unknown or revoked. |
| 403 | insufficient_scope |
The key lacks groups:read. |
| 404 | not_found |
Unknown group, or a group of another workspace. |
| 422 | validation_error |
Unknown status or type, bad since or until, sender not a phone, from_agent not true or false, invalid cursor. |
| 429 | rate_limited |
Too many requests this minute. Honor Retry-After. |

