7.W WhatsApp Business — Labels, Notas de Chat, Perfil (§13.2)#
Recursos de WhatsApp Business nativos + render-safe (validados via
/baileys-reference: whatsmeow expõe os builders de app-state de label +
GetBusinessProfile). Leitura de catálogo/coleções de produtos foi
adicionada via fork patch #11 (port fiel das IQ queries do Baileys —
w:biz:catalog). As imagens de produto são proxy-cacheadas (R2), nunca URL
da CDN da Meta. send-product/catalog-message e CRUD de produto via API
ficam de fora por ora (o fork já tem os métodos de escrita prontos).
Mensagens de pedido recebidas já viram evento (order_received/product_received).
Labels (etiquetas do WhatsApp Business)#
Etiquetas são app-state: criar/editar/excluir e associar a chat/mensagem
propagam pelos devices da operadora e renderizam no app WhatsApp Business. O
servidor ecoa cada mudança de volta como evento label.* (que a Catcher
persiste); a API também persiste na hora pra leitura imediata.
| Método | Rota | Corpo / efeito |
|---|---|---|
POST |
/v1/instances/{id}/labels |
{ "name": "Lead Quente", "color": 3 } → cria etiqueta. label_id é auto-alocado (primeira vaga livre 1..20). color 0..19. Retorna 201 {label_id,name,color}. |
GET |
/v1/instances/{id}/labels |
Lista etiquetas ativas (inclui as sincronizadas do device). { "labels": [{label_id,name,color}] }. |
PATCH |
/v1/instances/{id}/labels/{labelId} |
{ "name", "color" } → renomeia/recolore. 404 se a etiqueta não existe. |
DELETE |
/v1/instances/{id}/labels/{labelId} |
Exclui a etiqueta e suas associações (consistente com o WhatsApp). 204. |
POST |
/v1/instances/{id}/chats/{chatId}/labels/{labelId} |
Aplica a etiqueta no chat. chatId é normalizado (BR). 200 {label_id,chat,associated:true}. 404 se a etiqueta não existe. |
DELETE |
/v1/instances/{id}/chats/{chatId}/labels/{labelId} |
Remove a etiqueta do chat. 200. |
GET |
/v1/instances/{id}/labels/{labelId}/chats |
Lista os chats com a etiqueta (DISTINCT, JIDs normalizados). { "label_id", "chats": [...] }. |
POST |
/v1/instances/{id}/messages/{messageId}/labels/{labelId} |
Aplica a etiqueta numa mensagem. messageId aceita UUID Catcher ou hex WhatsApp (resolvido pro chat+hex). 200. |
DELETE |
/v1/instances/{id}/messages/{messageId}/labels/{labelId} |
Remove a etiqueta da mensagem. 200. |
Limite WhatsApp: 20 etiquetas por conta.
POST /labelsretorna400 "label limit reached"quando as 20 vagas estão em uso. A listagemlabels/{id}/chatsreflete o estado sincronizado com o WhatsApp (eco do app-state, ~1s) — a Catcher também grava na hora pra leitura imediata; os dois convergem (JID normalizado + DISTINCT).
GET /v1/instances/{instanceId}/labels#
Lista etiquetas ativas da instância: { "labels": [{ "label_id": "1", "name": "Lead Quente", "color": 3 }] }.
POST /v1/instances/{instanceId}/labels#
Cria etiqueta. Corpo: { "name": "Lead Quente", "color": 3 }. color deve estar entre 0 e 19; retorna 201 {label_id,name,color}.
PATCH /v1/instances/{instanceId}/labels/{labelId}#
Renomeia/recolore etiqueta. Corpo: { "name": "...", "color": 3 }. Retorna 200; 404 NOT_FOUND se não existir.
DELETE /v1/instances/{instanceId}/labels/{labelId}#
Exclui etiqueta e remove suas associações. Retorna 204.
GET /v1/instances/{instanceId}/labels/{labelId}/chats#
Lista chats associados a etiqueta: { "label_id": "1", "chats": ["554137984905@s.whatsapp.net"] }.
POST /v1/instances/{instanceId}/chats/{chatId}/labels/{labelId}#
Aplica etiqueta ao chat. Retorna 200 { "label_id": "1", "chat": "554137984905@s.whatsapp.net", "associated": true }.
DELETE /v1/instances/{instanceId}/chats/{chatId}/labels/{labelId}#
Remove etiqueta do chat. Retorna 200 { "label_id": "1", "chat": "554137984905@s.whatsapp.net", "associated": false }.
POST /v1/instances/{instanceId}/messages/{messageId}/labels/{labelId}#
Aplica etiqueta a mensagem. messageId aceita UUID Catcher ou hex WhatsApp. Retorna 200 { "label_id": "1", "message_id": "3EB0ABC123", "associated": true }.
DELETE /v1/instances/{instanceId}/messages/{messageId}/labels/{labelId}#
Remove etiqueta de mensagem. messageId aceita UUID Catcher ou hex WhatsApp. Retorna 200 { "label_id": "1", "message_id": "3EB0ABC123", "associated": false }.
Notas de chat (exclusivo Catcher)#
Notas privadas do operador num chat. Ficam só no banco da Catcher, nunca são enviadas pro WhatsApp (sem caminho whatsmeow, zero risco de ban) — visíveis apenas no Console. Diferencial sobre a Z-API: carregam autor + timestamps.
| Método | Rota | Corpo |
|---|---|---|
POST |
/v1/instances/{id}/chats/{chatId}/notes |
{ "note": "cliente prefere contato à tarde" } → 201 {id,chat_jid,note,author_user_id,created_at,updated_at} |
GET |
/v1/instances/{id}/chats/{chatId}/notes |
{ "notes": [...] } (mais recente primeiro) |
PATCH |
/v1/instances/{id}/chats/{chatId}/notes/{noteId} |
{ "note": "..." } → 200. 404 se não existe. |
DELETE |
/v1/instances/{id}/chats/{chatId}/notes/{noteId} |
204. |
note máx 8192 chars; author_user_id vem do JWT. Escopo por (instance_id, chat_jid).
GET /v1/instances/{instanceId}/chats/{chatId}/notes#
Lista notas privadas do chat: { "notes": [{ "id": 1, "chat_jid": "554137984905@s.whatsapp.net", "note": "cliente prefere contato à tarde", "author_user_id": 7, "created_at": "2026-03-07T10:00:00Z", "updated_at": "2026-03-07T10:00:00Z" }] }.
POST /v1/instances/{instanceId}/chats/{chatId}/notes#
Cria nota privada. Corpo: { "note": "cliente prefere contato à tarde" }. Retorna 201 {id,chat_jid,note,author_user_id,created_at,updated_at}.
PATCH /v1/instances/{instanceId}/chats/{chatId}/notes/{noteId}#
Atualiza nota privada. Corpo: { "note": "..." }. Retorna 200; 404 NOT_FOUND se não existir nesse chat.
DELETE /v1/instances/{instanceId}/chats/{chatId}/notes/{noteId}#
Remove nota privada. Retorna 204; 404 NOT_FOUND se não existir nesse chat.
Perfil Business (somente leitura)#
| Método | Rota | Descrição |
|---|---|---|
GET |
/v1/instances/{id}/business/profile?jid= |
Lê o perfil business: {jid, address, email, categories:[{id,name}], business_hours_timezone, business_hours:[{day_of_week,mode,open_time,close_time}]}. jid vazio = perfil da própria instância; senão, de qualquer número business. |
SET/edição do perfil business NÃO existe via multi-device (nem whatsmeow nem Baileys expõem) — é território de Cloud API / app WhatsApp Business. Por isso só há leitura.
GET /v1/instances/{instanceId}/business/profile#
Lê perfil WhatsApp Business. Query opcional: jid.
Catálogo de produtos (somente leitura)#
Lê o catálogo de produtos e as coleções de qualquer conta WhatsApp Business
(ou da própria instância). Implementado via fork patch #11 — port fiel das IQ
queries do Baileys no namespace w:biz:catalog.
| Método | Rota | Descrição |
|---|---|---|
GET |
/v1/instances/{id}/business/catalog?jid=&limit=&cursor= |
Lê uma página do catálogo. jid vazio = catálogo da própria instância; senão, de qualquer número business. limit (padrão 10) limita a página; cursor (de next_page_cursor) pagina. Retorna {products:[...], next_page_cursor}. Business sem catálogo → 200 {products:[]}. |
GET |
/v1/instances/{id}/business/collections?jid=&limit= |
Lê as coleções (agrupamentos de produtos) do catálogo. limit (padrão 51). Retorna {collections:[{id,name,status,products:[...]}]}. |
Cada produto: {id, name, description, retailer_id, url, price, currency, is_hidden, review_status, image_url}. price é inteiro na menor unidade da moeda (ex.: 4990 = R$ 49,90 quando currency:"BRL").
GET /v1/instances/{instanceId}/business/catalog#
Lê página do catálogo. Query params: jid, limit, cursor.
GET /v1/instances/{instanceId}/business/collections#
Lê coleções do catálogo. Query params: jid, limit.
image_urlé sempre URL controlada pela Catcher (R2), nunca da CDN da Meta. A imagem primária de cada produto é baixada pelo worker através do túnel/proxy da instância e cacheada no R2 (best-effort: vazia em falha de cache). O browser do consumidor nunca fala direto commmg.whatsapp.net/fbcdn.net(lição #31/#35). Validado ao vivo em 2026-05-24 contra um produto real (Catcher 3). Catálogo é SOMENTE LEITURA. Criar/editar/remover produto esend catalog/product messageNÃO estão disponíveis. A escrita (product_catalog_add/_edit, type=set) foi implementada e validada até o servidor do WhatsApp, mas o IQ de escrita não retorna resposta que o whatsmeow reconheça — mesmo numa conta commerce habilitada — então foi descontinuada (2026-05-24). Detalhes: lição #51 +.claude/rules/whatsmeow-fork.mdpatch #11.