O que muda da uazapi
A API uazapi e a API Orkesio falam com a mesma inbox e o mesmo token. A uazapi continua funcionando como hoje, sem data para sair: as rotas e os eventos dela não mudam. A Orkesio é o caminho daqui para frente: a API oficial do WhatsApp, os canais novos e as melhorias saem só nela. Dá para migrar uma parte por vez.
Esta página compara as duas lado a lado. Para entender a Orkesio do zero, comece por Como funciona.
A ideia em uma frase
Um modelo de mensagem único (OrkesioMessage), igual nos eventos, na busca e na resposta do envio, dentro de um
envelope único para todos os eventos. Os eventos chegam por GET /events e por
webhook. Os webhooks da Orkesio ficam em /webhooks; os da uazapi (/webhook) seguem iguais e
separados. Quem quiser os dois formatos cria um webhook em cada rota (pode ser o mesmo link).
Envelope
| uazapi (hoje) | Orkesio | |
|---|---|---|
| Nome do evento | EventType (messages, messages_update...) | type no formato recurso.ação (message.received) |
| Id do evento | não tem | id (evt_ + ULID), igual ao header webhook-id: serve para descartar repetidos |
| Quando aconteceu | não tem (cada evento tem seu formato de data) | created_at, sempre ISO 8601 em UTC com milissegundos |
| Inbox | owner, instanceName, BaseUrl e o token no corpo | inbox{id, name, phone, channel}, sem token (phone no WhatsApp; account_id no Messenger, no Instagram e no Telegram) |
| Canal | não tem | inbox.channel: whatsapp_web, whatsapp_cloud, instagram, messenger ou telegram |
| Dados | espalhados no topo (message, chat, event, type, state...) | tudo em data, com formato fixo por type |
| Payload original | só o campo cloud na API oficial | não vem: o conteúdo já chega tipado em data |
| Nomes | PascalCase, camelCase, snake_case e minúsculo junto misturados | sempre snake_case |
{
"id": "evt_01JAB3K9ZQ7V0M4T8R2X6WYD5H",
"type": "message.received",
"created_at": "2026-10-17T12:00:00.000Z",
"inbox": { "id": "r0269625d29bfbd", "name": "loja", "phone": "5511888888888", "channel": "whatsapp_web" },
"data": { "message": { "...": "a mensagem" }, "chat": { "...": "a conversa" }, "lead": { "...": "o lead" } }
}
Nos eventos de mensagem, o data traz a mensagem (message) e a conversa (chat); message.received e message.sent
trazem também o lead (só em conversa direta). Outros eventos têm o data próprio: veja a página de cada um.
As listas de valores podem crescer (type, status, sent_by, channel). Trate valor desconhecido sem quebrar.
Eventos
| uazapi | Orkesio |
|---|---|
messages (do contato) | message.received |
messages (da inbox) | message.sent |
messages_update ReadReceipt / FailedMessage | message.status, um por recibo como hoje (várias mensagens da conversa em messages) |
messages_update GroupReceipts | group.receipts (lote de 60 s, por participante) |
messages_update Pinned / FileDownloaded / Transcribed, edição | message.updated com change |
messages_update DeletedMessage | message.updated com change: deleted |
reação dentro de messages | message.reaction |
messages_update ExpiredMessage | message.status com failed e error.error: expired |
chats, chat_labels (chat inteiro, sem dizer o que mudou) | chat.updated com changes[] |
| (lead junto do chat em toda mensagem) | data.lead em toda mensagem de conversa direta e, quando muda sem mensagem, lead.updated com changes[] |
presence | chat.presence |
contacts / labels | contact.updated / label.updated |
groups | group.updated, group.participants, group.joined |
call | call.updated (com status) e call.log |
connection | inbox.status |
history | history.batch e history.completed |
status_posts / newsletter_messages | status_post.received / newsletter.message |
sender | campaign.updated (com status) |
others (reflexão do whatsmeow) | sai |
A mensagem (OrkesioMessage)
O mesmo objeto nos eventos (message.received, message.sent), na busca e na resposta do envio. A explicação campo a
campo está em A mensagem.
| O que | uazapi (message de hoje) | Orkesio |
|---|---|---|
| Ids | id (owner:id), messageid | id (o id do canal: o do WhatsApp, wamid na oficial; o antigo messageid) |
| Conversa | chatid, chatlid, isGroup, groupName + o chat inteiro (cerca de 60 campos) | chat_id: o id da conversa (em grupo, o do grupo). A conversa (id, lid, type, name...) vem ao lado da mensagem, em data.chat |
| Quem escreveu | sender, sender_pn, sender_lid, senderName, fromMe | author{id, phone, username, lid, name, picture_url} e direction (in/out) |
| Por onde saiu | wasSentByApi, ai_metadata | sent_by (api, automation, campaign, phone, web e, em breve, user) e automation{agent_id, flow_id} |
| Data | messageTimestamp (ms) | sent_at (ISO UTC) |
| Tipo | messageType (nome do proto), mediaType, type | type (lista fechada); os campos do tipo vêm soltos na mensagem, com text como texto principal |
| Conteúdo | content = proto cru do WhatsApp; text | os campos do tipo, soltos na mensagem: text (texto, legenda, corpo), url, mime_type, latitude...; e display_text com tudo num texto só |
| Status | status (Read, ServerAck...) | status normalizado (scheduled, queued, pending, sent, delivered, read, played, failed) e error |
| Citação | quoted (só o id) | reply_to (o id) e quoted{author, direction, type, preview} (o resumo) |
| Edição | edited (id da original) | edited (true/false) e o evento message.updated |
| Apagada | messageType: DeletedMessage | deleted (true/false) |
| Rastreamento | track_source, track_id | track_source, track_id (seus, iguais) e referral (da Meta, anúncio) |
| CRM | lead_* dentro do chat, sempre | lead, sempre na conversa direta, ao lado da mensagem (data.lead) |
Classes (campo category)
Na uazapi cada uso deduzia do messageType. Na Orkesio a api manda a classe em cada mensagem (category), e a busca
filtra por ela.
| Classe | Como reconhecer na mensagem | Sai em message.received/message.sent? |
|---|---|---|
conversation | o resto dos type | sim |
call | type: call | evento próprio (call.log) |
reaction | type: reaction | evento próprio (message.reaction) |
event | type: group_participant ou system (e edição, voto, fixar) | não: fica gravado para a busca e tem evento próprio (group.participants), para não disparar automação |
unsent | status agendado, na fila, enviando, com falha ou cancelado | na busca |
Regras decididas
- Miniatura: na mídia (foto, vídeo, documento, figurinha) vem só no aviso em tempo real (
/eventse webhook); não é gravada, a busca traz ourl. Em link, localização, anúncio e convite vem também na busca. - Reações e votos: continuam uma mensagem cada; na busca, a mensagem reagida traz a soma em
reactionse a enquete traz o resultado emresults. - Grupo:
chat_ididentifica o grupo (edata.chat.nametraz o nome);authortraz quem escreveu. Sem a informação de admin. - Status de grupo:
message.statusleva só osent/failedda mensagem; cada participante vem emgroup.receipts. - Identidade sem telefone:
author.idé opaco (no Instagram e no Messenger não há número). O número vem emphone, e o nome de usuário emusername. - Anúncio:
referraltraz a origem (anúncio, título, link,ctwa_clid), igual na Web e na oficial, e filtra a busca (referral=trueoureferral_source_idemGET /messages).
Envio e busca
Duas rotas novas, com o mesmo modelo de mensagem. As rotas atuais (/send/*, /message/find) continuam iguais.
Uma página por tipo, com a uazapi ao lado da Orkesio: Enviar mensagem e Buscar mensagens.
| uazapi (hoje) | Orkesio | |
|---|---|---|
| Enviar | 11 rotas (/send/text, /send/media, /send/menu...), cada uma com seus campos | POST /messages: uma rota, o corpo é plano, com o formato da mensagem recebida (to, type e os campos do tipo) |
| Resposta do envio | o message da uazapi + response{status, message} | a própria OrkesioMessage, na hora, com status: queued: fila por padrão só nesta rota (options.async: false espera o envio e volta com pending ou o erro) |
| Buscar | POST /message/find com offset | GET /messages com cursor (não pula nem repete quando chega mensagem nova) |
| Erro | {"error": "texto"} | {"error": "código", "message": "texto"} (o error vira um código estável) |
| uazapi | Orkesio (POST /messages) |
|---|---|
number | to (número, id do WhatsApp, LID, grupo, canal ou @bsuid; depois @username de outros canais) |
text, linkPreview* | type: text, com text e link_preview |
/send/media type + file + text + docName | type: image, video, video_note, audio, voice, document ou sticker, com url ou base64, text, mime_type, filename, thumbnail e view_once |
/send/menu (button, list, poll), /send/carousel, /send/location-button | type: poll, buttons, list, carousel ou location_request, com choices no formato da mensagem recebida (não mais "texto|id") |
/send/request-payment, /send/pix-button | type: payment com as formas que vierem (pix, boleto, link, juntas ou não; PIX sem amount = só o botão) |
/send/contact, /send/location, /send/event | type: contacts, location ou event |
| — (a API oficial é só da Orkesio) | type: template, com name, language e components |
replyid, mentions (texto com vírgulas), "all" | reply_to (o id), mentions[], mention_all |
track_source, track_id | track_source, track_id (iguais) |
delay, async, readchat, readmessages | options{delay_ms, async, read_chat, read_messages} |
O que um canal não tem responde 501 com error: unsupported_for_channel (template no Web; enquete, carrossel, event e payment na oficial). O detalhe está em Enviar mensagens.
Campanhas (/sender) e status (/send/status) têm rotas próprias: /campaigns e
/status-posts.
O que já funciona
| Parte | Estado |
|---|---|
GET /messages (busca) | disponível |
POST /messages (envio, todos os tipos) | disponível (na API oficial, sempre envio na hora, sem fila) |
GET /events (todos os eventos, em tempo real) | disponível |
| Webhook no formato da Orkesio (todos os eventos) | disponível |