Administer WhatsApp channels
A channel — a newsletter in both engine libraries — is a one-way broadcast surface: the owner and the admins post, everyone else subscribes and reads. Channels live in their own JID domain, @newsletter, and their routes are nested under a session like every other resource.
This page documents the two administration routes added in v0.16.0: transferring ownership, and demoting an admin back to a subscriber. The rest of the channel family — listing, creating, reading, subscribing, unsubscribing, deleting, reading messages, and muting — is covered field by field in the API reference.
- A session that is started and connected. See Sessions and Connect your first session.
- An API key with the operator role. See Authentication.
- A session running the Baileys engine (
ENGINE_TYPE=baileys) — both routes on this page answer501on whatsapp-web.js. - The session's WhatsApp account must own the channel; both routes require it.
- A channel id in WhatsApp's
@newsletterformat, for example120363000000000000@newsletter.
Examples use the local base URL http://localhost:2785/api, a session id of 8f3c2b1a-9d4e-4c7a-8b2f-1e6d5a4c3b2a, a channel id of 120363000000000000@newsletter, and the header X-API-Key: YOUR_API_KEY. Replace YOUR_API_KEY with a key from your dashboard. In production, swap the base URL for your domain over TLS.
How channel routes work
Every channel route is nested under a session, so the session id is always in the path. There are ten in all — listing and creating, subscribing and unsubscribing, reading metadata and messages, muting, deleting the channel itself, and the two administration routes this page documents:
GET /api/sessions/{sessionId}/channels
POST /api/sessions/{sessionId}/channels
POST /api/sessions/{sessionId}/channels/subscribe
GET /api/sessions/{sessionId}/channels/{channelId}
DELETE /api/sessions/{sessionId}/channels/{channelId}
POST /api/sessions/{sessionId}/channels/{channelId}/delete
GET /api/sessions/{sessionId}/channels/{channelId}/messages
POST /api/sessions/{sessionId}/channels/{channelId}/mute
POST /api/sessions/{sessionId}/channels/{channelId}/owner/transfer
POST /api/sessions/{sessionId}/channels/{channelId}/admins/demote
Three rules apply to the two administration routes below:
- Identifiers. A channel is addressed by its
@newsletterjid; the person you are naming in the body by a phone number,<phone>@c.us, or<lid>@lid. A bare number is qualified for you. Anything that does not name an individual — a group jid, a bare@c.us, free text — is rejected with400before the value reaches WhatsApp:Not an individual user id: <userId> — pass a phone number, <phone>@c.us or <lid>@lid. - Roles. Both require an operator-role key and return
403otherwise. - Ownership. Both require this session's WhatsApp account to own the channel. An operator key authorizes the request; WhatsApp still decides whether the account may make the change.
The session must be started. Either route on a session that is not started returns 400; a started session whose engine is not connected yet returns 409.
Transfer channel ownership
POST /api/sessions/{sessionId}/channels/{channelId}/owner/transfer hands a channel you own to another account. newOwnerId is required.
Once the transfer lands, this session is no longer the owner and cannot take the channel back through this API. There is no undo route — recovering the channel means asking the new owner to transfer it back from their side.
The route is implemented on the Baileys engine only. A whatsapp-web.js session answers 501 with Operation not supported by the active engine: transferChannelOwnership: its page function rejects every call locally against a subscriber list the page cannot repopulate. Set ENGINE_TYPE=baileys for the session that administers channels.
curl -X POST "http://localhost:2785/api/sessions/8f3c2b1a-9d4e-4c7a-8b2f-1e6d5a4c3b2a/channels/120363000000000000@newsletter/owner/transfer" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "newOwnerId": "628123456789@c.us" }'
{ "success": true }
| Field | Type | Required | Meaning |
|---|---|---|---|
newOwnerId | string | Yes | The account that becomes the new owner — a phone number, <phone>@c.us, or <lid>@lid. A bare number is qualified for you; a value that does not name an individual is a local 400. |
success is always true on a 200 — a failure is reported as a non-2xx status, not as success: false.
Two behaviours to plan for:
- On whatsapp-web.js the
403documented for this route is unreachable, because the engine refuses with501first. On Baileys a403is a real refusal from WhatsApp — typically because this account does not own the channel. - A
503means WhatsApp did not answer within the request budget, so the transfer may or may not have applied. Read the channel back before retrying: a retry after a transfer that actually landed is refused, since the account no longer owns it.
The upstream option to dismiss yourself as an admin in the same call is not exposed. The WhatsApp Web function it depends on no longer exists and that branch swallows its own errors, so offering it would fail silently.
Demote a channel admin
POST /api/sessions/{sessionId}/channels/{channelId}/admins/demote returns an admin of a channel you own to an ordinary subscriber. userId is required.
curl -X POST "http://localhost:2785/api/sessions/8f3c2b1a-9d4e-4c7a-8b2f-1e6d5a4c3b2a/channels/120363000000000000@newsletter/admins/demote" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "628123456789@c.us" }'
{ "success": true }
| Field | Type | Required | Meaning |
|---|---|---|---|
userId | string | Yes | The admin to demote back to a subscriber — a phone number, <phone>@c.us, or <lid>@lid. A bare number is qualified for you; a value that does not name an individual is a local 400. |
A 403 means the engine refused: this account does not own the channel, or the named user is not an admin of it.
There is no promote route on either engine. Neither engine library exposes a promote call for channels, so none is published: an admin is promoted from the WhatsApp app and demoted here. If you arrived from Groups, note the difference — group participants have promote and demote as a pair, channels have demote only.
Demotion itself is implemented on the Baileys engine only. A whatsapp-web.js session answers 501 with Operation not supported by the active engine: demoteChannelAdmin, because the WhatsApp Web module its library method targets no longer exports the function.
Troubleshooting
| Status | Cause | Fix |
|---|---|---|
400 | The session is not started, or the body failed validation — a missing newOwnerId / userId, or a value that does not name an individual user. | Start the session first (see Sessions); pass a phone number, <phone>@c.us, or <lid>@lid. |
401 | Missing or invalid X-API-Key. | Send a valid key in the X-API-Key header. |
403 | The key's role is below operator, or WhatsApp refused — this account does not own the channel, or the user is not an admin. | Use an operator-role key (see Authentication); confirm the account owns the channel. |
409 | The session is started but its engine is not connected. | Wait for the session to reach ready, then retry. |
501 | The session runs on the whatsapp-web.js engine. Neither route is available there. | Run the administering session with ENGINE_TYPE=baileys. |
503 | WhatsApp did not answer within the request budget. The change may or may not have applied. | Read the channel back before retrying — do not replay blindly. |
Next steps
- Manage WhatsApp groups — the group counterpart, including the promote/demote pair channels do not have.
- Full channel endpoint reference — the other eight routes, every field, and every status code.
- Sessions & multi-session — session lifecycle and engine selection.