Pular para o conteúdo
Páginas da documentação

Conexão do WhatsApp

Como o cliente final conecta o número dele pela página do hub, e o recurso de conexão.

Abrir o Markdown

O cliente final conecta o número de WhatsApp Business dele ao seu workspace por uma página hospedada pelo hub (Embedded Signup da Meta). Seu app não fala com a Meta: abre uma sessão de conexão, redireciona o cliente para a url devolvida e acompanha o resultado por redirect de volta e por eventos.

Pré-requisito: URLs de retorno

O returnUrl da sessão precisa estar na allowlist do seu app, cadastrada pela equipe Matra no painel. A comparação é por origin + pathname, sem query nem fragmento: o hub normaliza a URL enviada e exige que seja igual a uma entrada. Fora da lista: 400 com code: "RETURN_URL_NOT_ALLOWED".

Abrir uma sessão

POST /v1/workspaces/:workspaceId/connect-sessions

{ "kind": "whatsapp", "returnUrl": "https://app.exemplo.com/settings/whatsapp" }

Corpo estrito (campo extra é rejeitado). Resposta 201:

{
  "id": "...",
  "url": "https://.../connect#s=cs_...",
  "expiresAt": "2026-10-22T15:15:00.000Z"
}
  • A url é de uso único e vale 15 minutos (expiresAt). Ela carrega um token de acesso: não registre em log nem exiba para quem não é o cliente que vai conectar.
  • Repetir o POST abre uma sessão nova; as anteriores seguem válidas até expirar ou serem usadas.
Status code Quando
400 RETURN_URL_NOT_ALLOWED returnUrl fora da allowlist do app
404 WORKSPACE_NOT_FOUND workspace inexistente ou de outro app
409 WORKSPACE_DISABLED workspace desativado
503 META_WEBHOOK_NOT_READY a Meta ainda não está entregando webhooks ao hub; uma conexão feita agora nasceria sem receber eventos. Tente de novo em instantes; se persistir, avise a equipe Matra

Retorno do cliente

Ao terminar, cancelar ou falhar, a página redireciona o navegador para o seu returnUrl com parâmetros na query:

Query Significado
status=connected&connectionId=<id> Conexão criada. Ainda está pending: a ativação roda em segundo plano
status=cancelled O cliente fechou ou cancelou o fluxo da Meta
status=error&code=<code> Falha (META_EXCHANGE_FAILED, META_GRANT_INVALID, META_ASSET_MISMATCH, META_PHONE_AMBIGUOUS, COEXISTENCE_INCOMPLETE, PHONE_ALREADY_CONNECTED, WABA_ALREADY_CONNECTED, META_UNAVAILABLE…)

O redirect é só uma dica de interface: o navegador do cliente pode fechar antes dele. A fonte da verdade é o evento connection.created (e GET /v1/connections).

PHONE_ALREADY_CONNECTED e WABA_ALREADY_CONNECTED indicam que o número ou a conta já estão ligados a uma conexão viva em outro workspace; o hub não diz de quem. META_PHONE_AMBIGUOUS sai no Coexistence quando a Meta não informa o número e a conta tem zero ou mais de um número do app WhatsApp Business já migrado; COEXISTENCE_INCOMPLETE, quando o número do app ainda não terminou a migração para a API. Nos dois casos nada é criado e o cliente pode tentar de novo com uma sessão nova.

Sessão de um workspace desativado, ou de um app desativado pela Matra, deixa de valer na hora, mesmo dentro dos 15 minutos: a página mostra que o link não vale mais e nenhuma conexão é criada.

Conexões

Método e rota O que faz Respostas
GET /v1/connections Lista (paginada) as conexões do app. Filtros: workspaceId, status 200
GET /v1/connections/:connectionId Busca uma conexão 200, 404
DELETE /v1/connections/:connectionId Desconecta; repetir é seguro 200, 404
GET /v1/connections/:connectionId/usage Uso do nível gratuito de mensagens de serviço no mês (ver Custos) 200, 404
GET /v1/connections/:connectionId/consumption?month=YYYY-MM Mensagens entregues no mês por categoria e tipo de cobrança, contadas pelo hub e pela Meta (ver Custos) 200, 400, 404

Resposta de uma conexão ({ "connection": ... } no GET por id e no DELETE; item de data na listagem):

{
  "id": "...",
  "kind": "whatsapp",
  "status": "active",
  "errorCode": null,
  "workspaceId": "...",
  "whatsapp": {
    "wabaId": "123456789012345",
    "phoneNumberId": "109876543210987",
    "displayPhoneNumber": "+55 43 99999-0000",
    "verifiedName": "Clínica Exemplo",
    "isOnBizApp": true,
    "qualityRating": "GREEN"
  },
  "sync": [
    { "type": "smb_app_state_sync", "status": "accepted", "progress": null },
    { "type": "history", "status": "accepted", "progress": 40 }
  ],
  "tokenExpiresAt": null,
  "health": {
    "status": "LIMITED",
    "issues": [
      {
        "entityType": "PHONE_NUMBER",
        "canSendMessage": "LIMITED",
        "errors": [],
        "additionalInfo": ["Your display name has not been approved yet. Your message limit will increase after the display name is approved."]
      }
    ],
    "checkedAt": "2026-10-23T16:36:19.000Z"
  },
  "createdAt": "2026-10-22T15:00:00.000Z",
  "updatedAt": "2026-10-22T15:00:00.000Z"
}
  • status: pending (criada, ativação em andamento), active, error (precisa de atenção, ver errorCode) ou disconnected.
  • errorCode só vem preenchido em error: offboarded (a Meta retirou o número do parceiro; volta a active se a Meta reconectar), token_expired (a credencial venceu; o cliente precisa conectar de novo), onboarding_incomplete (a ativação não terminou em 2 h), activation_failed, subscribe_failed:<código> e register_failed:<código>. Trate valores desconhecidos como erro genérico.
  • whatsapp.isOnBizApp é true quando o número continua no app WhatsApp Business do cliente (Coexistence).
  • sync aparece só em Coexistence: o hub pede à Meta a sincronização do estado do app (smb_app_state_sync) e do histórico de 180 dias (history). status: requested, accepted, completed ou failed. progress (0 a 100, ou null antes do primeiro bloco) é o maior progresso informado pela Meta no histórico; em 100 o history vira completed e sai um connection.updated. O histórico recusado pelo cliente no app vira failed (com connection.updated). O conteúdo sincronizado chega pelos eventos whatsapp.history.received e whatsapp.contacts.synced.
  • tokenExpiresAt é null quando a credencial não tem prazo.
  • health é o health_status da Meta para o número, lido na ativação e de hora em hora (null antes da primeira leitura). status é o can_send_message geral: AVAILABLE, LIMITED (envia com limite menor) ou BLOCKED (conversa iniciada pela empresa não sai; resposta dentro da janela pode sair). issues lista só as entidades (PHONE_NUMBER, WABA, BUSINESS, APP) que não estão AVAILABLE ou que têm erro de mensagem, com errors (code, description e solution como a Meta devolve, em inglês) e additionalInfo; erros da API de chamadas (138xxx) ficam de fora. Exemplos vistos: 141010 (empresa sem verificação, LIMITED), 141006 (sem forma de pagamento, BLOCKED) e o nome de exibição em análise (additionalInfo, LIMITED). Quando o estado ou os códigos mudam, sai connection.updated com meta: { "health": "changed" }; a primeira leitura só avisa quando não está AVAILABLE.
  • Nenhuma resposta traz token, PIN ou qualquer credencial.

Reconectar. Uma nova sessão para o mesmo workspace e o mesmo número reaproveita a mesma conexão (mesmo id): ela volta a pending e emite connection.updated, não connection.created. Um número que está active, pending ou error em outro workspace não pode ser conectado: o 409 vai para a página de conexão, não para o seu app. O que o seu app vê é o retorno do navegador com ?status=error&code=PHONE_ALREADY_CONNECTED (ou WABA_ALREADY_CONNECTED), e nenhum connection.created é emitido.

Desconectar. DELETE marca disconnected, apaga a credencial no hub e cancela a assinatura de webhooks da conta quando nenhuma outra conexão a usa. O número do cliente não é desregistrado na Meta. Responde 200 com a conexão; chamar de novo devolve a conexão atual sem novo evento. Conexões desconectadas há mais de 30 dias são apagadas do hub.