Phones (canais)
Phones representam cada conexão WhatsApp ou Instagram da sua account. São o pré-requisito para enviar/receber qualquer mensagem.
Base path: /v1/phones
Objeto Phone
{
"id": "5f7b2e1c-3d4a-4e5f-9a8b-1c2d3e4f5a6b",
"accountId": "a1b2c3d4-...",
"type": "BAILEYS",
"label": "Atendimento Vendas",
"phoneNumber": "5511999998888",
"status": "CONNECTED",
"webhookUrl": "https://api.minhaempresa.com/wpp-events",
"webhookEvents": ["message:received", "message:status"],
"createdAt": "2026-05-21T14:00:00.000Z",
"updatedAt": "2026-05-21T14:02:30.000Z"
}
Campos comuns
| Campo | Tipo | Descrição |
|---|---|---|
id | UUID | Identificador local (use em todos os endpoints) |
type | enum | BAILEYS, WABA, INSTAGRAM (imutável) |
label | string | Nome legível (1-120 chars) |
phoneNumber | string | null | E.164 sem +, populado após conexão |
status | enum | PENDING, PENDING_QR, PENDING_WEBHOOK, CONNECTING, CONNECTED, DISCONNECTED, TOKEN_EXPIRED, FAILED |
webhookUrl | string | null | Onde o gateway entrega eventos |
webhookEvents | string[] | Lista de eventos subscritos (vazio = todos) |
disconnectedAt | datetime | null | Quando saiu de CONNECTED |
Campos exclusivos WABA
wabaPhoneNumberId, wabaBusinessAccountId, wabaThroughputLevel, wabaQualityRating, wabaWebhookConfigured. Tokens (wabaAccessTokenEnc) são internos — nunca retornados.
Campos exclusivos Instagram
igUserId, igUsername, igAccountType, igTokenExpiresAt, igWebhookConfigured.
Endpoints
POST /v1/phones
Cria um novo phone. Para BAILEYS, inicia geração do QR. Para WABA, valida as credenciais e hidrata metadata. Para INSTAGRAM, use o fluxo OAuth dedicado.
Headers
| Header | Valor | Obrigatório |
|---|---|---|
X-API-Key | ak_live_... | sim |
Content-Type | application/json | sim |
Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
type | enum | sim | BAILEYS ou WABA (Instagram usa endpoint próprio) |
label | string | sim | 1-120 chars |
webhook.url | URL | não | Endpoint HTTPS pra eventos |
webhook.secret | string | não | Secret HMAC (≥16 chars; obrigatório se url presente) |
webhook.events | string[] | não | Lista de tipos (vazio = todos) |
credentials.phoneNumberId | string | só WABA | Phone Number ID do Meta |
credentials.businessAccountId | string | só WABA | WABA ID |
credentials.accessToken | string | só WABA | System User token longo |
credentials.verifyToken | string | só WABA | Token de verificação webhook |
Exemplo Baileys:
curl -X POST https://wpp.ogmma.com.br/v1/phones \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"type": "BAILEYS",
"label": "Atendimento Vendas",
"webhook": {
"url": "https://api.acme.com/wpp",
"secret": "supersecret-pelomenos-16chars",
"events": ["message:received", "channel:connected"]
}
}'
Exemplo WABA manual (credenciais via Meta Business Manager):
curl -X POST https://wpp.ogmma.com.br/v1/phones \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"type": "WABA",
"label": "Comercial Oficial",
"credentials": {
"phoneNumberId": "123456789012345",
"businessAccountId": "987654321098765",
"accessToken": "EAAxxx...",
"verifyToken": "meu-verify-token"
},
"webhook": { "url": "https://api.acme.com/wpp", "secret": "supersecret-pelomenos-16chars" }
}'
Response 201
{
"id": "5f7b2e1c-...",
"type": "BAILEYS",
"status": "PENDING_QR",
"label": "Atendimento Vendas",
"webhookUrl": "https://api.acme.com/wpp",
"createdAt": "2026-05-21T14:00:00.000Z"
}
Errors
| HTTP | Code | Quando |
|---|---|---|
| 400 | VALIDATION_ERROR | Campo inválido |
| 400 | WABA_CREDENTIALS_REQUIRED | type=WABA sem credentials |
| 401 | AUTH_MISSING | Sem X-API-Key |
| 402 | ACCOUNT_SUSPENDED | Account em inadimplência |
GET /v1/phones
Lista todos os phones da account, ordenados por createdAt desc.
curl https://wpp.ogmma.com.br/v1/phones \
-H "X-API-Key: ak_live_..."
Response 200
[
{ "id": "...", "type": "BAILEYS", "status": "CONNECTED", ... },
{ "id": "...", "type": "WABA", "status": "CONNECTED", ... }
]
GET /v1/phones/:id
Detalhe de um phone específico.
curl https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-... \
-H "X-API-Key: ak_live_..."
Errors
| HTTP | Code | Quando |
|---|---|---|
| 404 | PHONE_NOT_FOUND | ID inexistente ou pertence a outra account |
DELETE /v1/phones/:id
Remove um phone. Worker é notificado para encerrar a sessão (Baileys envia logout). Operação destrutiva e irreversível — auth state e mídia local são apagados; mensagens enviadas (messages_sent) ficam para auditoria.
curl -X DELETE https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-... \
-H "X-API-Key: ak_live_..."
Response 204 (sem body)
PATCH /v1/phones/:id
Atualiza apenas a configuração de webhook do phone. Não permite trocar type ou label.
Body
| Campo | Tipo | Descrição |
|---|---|---|
webhook.url | URL | null | null ou omitido remove o webhook |
webhook.secret | string | ≥16 chars |
webhook.events | string[] | Lista de tipos |
sharedWebhookId | UUID | null | Aponta para um SharedWebhook (futura feature multi-phone) |
curl -X PATCH https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-... \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{ "webhook": { "url": "https://api.acme.com/wpp-v2", "secret": "novachavedepelomenos16chars" } }'
GET /v1/phones/:id/qrcode
Retorna o QR code Baileys atual (cacheado em Redis com TTL curto após o Worker gerar). Faça polling a cada 1-2s; quando o usuário escanear, o status vira CONNECTED e este endpoint passa a retornar 409.
Response 200
{
"qr": "2@LkPq...,QR data raw...",
"dataUrl": "data:image/png;base64,iVBORw0KGgo..."
}
dataUrl é PNG base64 pronto para <img src="...">.
Errors
| HTTP | Code | Quando |
|---|---|---|
| 400 | QR_NOT_APPLICABLE | Phone não é BAILEYS |
| 404 | PHONE_NOT_FOUND | — |
| 409 | ALREADY_CONNECTED | Phone já conectou |
| 425 | QR_NOT_READY | QR ainda não emitido pelo Worker — tente em 1-2s |
O QR rota Baileys naturalmente refresha a cada ~20s. O endpoint sempre devolve o último QR em cache.
POST /v1/phones/:id/pairing-code
Alternativa ao QR para Baileys: gera um código de 8 dígitos que o usuário digita no celular em "Aparelhos conectados → Conectar com número".
Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
phoneNumber | string | sim | E.164 (com ou sem +), 8-20 dígitos |
curl -X POST https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-.../pairing-code \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{ "phoneNumber": "+5511988887777" }'
Response 202
{ "status": "pending", "phoneNumber": "5511988887777" }
A criação do código é assíncrona (Worker recebe o comando, cria a sessão Baileys com requestPairingCode, salva o resultado em Redis). Faça polling em GET /pairing-code.
Errors
| HTTP | Code | Quando |
|---|---|---|
| 400 | PAIRING_NOT_APPLICABLE | Phone não é BAILEYS |
| 409 | ALREADY_CONNECTED | Phone já conectou |
GET /v1/phones/:id/pairing-code
Busca o pairing code gerado no comando anterior. Faça polling até 200.
Response 200
{ "code": "ABCD1234", "formatted": "ABCD-1234" }
Errors
| HTTP | Code | Quando |
|---|---|---|
| 425 | PAIRING_NOT_READY | Código ainda sendo gerado pelo Worker — tente em 1-2s |
O pairing code é único e descartável. Uma vez consumido (usuário digitou no celular), o Worker emite
channel:pairing-code(uso interno) e depoischannel:connected.
POST /v1/phones/:id/reconnect
Força o Worker a reabrir a sessão (útil quando o phone entrou em DISCONNECTED por instabilidade temporária). Para Baileys, tenta recuperar via auth state persistido. Para WABA, recarrega credenciais.
curl -X POST https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-.../reconnect \
-H "X-API-Key: ak_live_..."
Response 202
{ "status": "reconnecting" }
GET /v1/phones/:id/identities/resolve
Resolve uma identidade do contato. Aceita qualquer formato: canonicalKey, phone (5511999...), BSUID (BR.1234...), username (@maria), ou JID Baileys (5511999@s.whatsapp.net, 123@lid).
Query
| Param | Tipo | Obrigatório |
|---|---|---|
key | string | sim |
curl 'https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-.../identities/resolve?key=5511988887777' \
-H "X-API-Key: ak_live_..."
Response 200
{
"canonicalKey": "+5511988887777",
"pn": "5511988887777",
"lid": null,
"bsuid": null,
"username": null,
"firstSeenAt": "2026-04-12T10:00:00.000Z",
"lastSeenAt": "2026-05-20T18:33:00.000Z"
}
Errors
| HTTP | Code | Quando |
|---|---|---|
| 404 | IDENTITY_NOT_FOUND | Chave não encontrada nesse phone |
WABA Embedded Signup
Fluxo recomendado para WABA quando o cliente não tem credenciais Meta ainda. Usa o SDK JS da Meta no browser.
GET /v1/phones/waba/embedded-signup/config
Retorna config para o SDK Meta inicializar.
curl https://wpp.ogmma.com.br/v1/phones/waba/embedded-signup/config \
-H "X-API-Key: ak_live_..."
Response 200
{
"appId": "1234567890",
"configId": "9876543210",
"graphVersion": "v25.0"
}
Errors
| HTTP | Code | Quando |
|---|---|---|
| 503 | META_APP_ID_MISSING | Gateway sem META_APP_ID configurado |
POST /v1/phones/waba/embedded-signup
Finaliza o signup após o usuário completar o fluxo no SDK Meta (recebe code + phone_number_id + waba_id do callback).
Body
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
code | string | sim | Authorization code retornado pelo SDK Meta |
phoneNumberId | string | sim | ID do número selecionado |
wabaId | string | sim | ID da WABA |
label | string | não | Default: "WhatsApp Business" |
pin | string | não | PIN 6 dígitos para register (default "000000" em dev) |
webhook | object | não | Config webhook (mesma do POST /phones) |
curl -X POST https://wpp.ogmma.com.br/v1/phones/waba/embedded-signup \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"code": "AQDxYzAbCd...",
"phoneNumberId": "123456789012345",
"wabaId": "987654321098765",
"label": "WhatsApp Acme",
"pin": "123456"
}'
Response 201 — phone criado com status: CONNECTED.
O gateway executa:
- Trocar
codepor system user token (server-side, comMETA_APP_SECRET). subscribeAppToWabapara receber webhooks.- Registrar o número (pode falhar silenciosamente se já registrado).
- Hidratar metadata via
getPhoneNumberInfo. - Persistir phone + disparar
channel:connectno Worker.
Errors
| HTTP | Code | Quando |
|---|---|---|
| 503 | META_APP_NOT_CONFIGURED | Sem META_APP_ID/META_APP_SECRET no servidor |
Instagram OAuth
GET /v1/phones/instagram/oauth/config
Retorna config para iniciar o fluxo OAuth Instagram.
Response 200
{
"appId": "...",
"redirectUri": "https://app.acme.com/oauth/instagram/callback",
"scope": "instagram_business_basic,instagram_business_manage_messages",
"authorizationUrl": "https://www.instagram.com/oauth/authorize?client_id=...&redirect_uri=..."
}
POST /v1/phones/instagram
Finaliza o OAuth com o code recebido no redirect.
Body
| Campo | Tipo | Obrigatório |
|---|---|---|
code | string | sim |
label | string | não |
webhook | object | não |
curl -X POST https://wpp.ogmma.com.br/v1/phones/instagram \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{ "code": "AQDxYz...", "label": "Instagram Acme" }'
Response 201 — phone com type: INSTAGRAM, status: CONNECTED, token long-lived (60d) armazenado criptografado.
Errors
| HTTP | Code | Quando |
|---|---|---|
| 503 | IG_NOT_CONFIGURED | Servidor sem credenciais Instagram |
WABA Business Profile
GET /v1/phones/:id/business-profile
Retorna o perfil público do número WABA (about, websites, vertical, etc) direto do Meta.
curl https://wpp.ogmma.com.br/v1/phones/5f7b2e1c-.../business-profile \
-H "X-API-Key: ak_live_..."
PATCH /v1/phones/:id/business-profile
Atualiza o perfil.
Body (todos opcionais)
| Campo | Tipo | Limite |
|---|---|---|
about | string | 139 chars |
address | string | 256 chars |
description | string | 512 chars |
email | — | |
websites | URL[] | até 2 |
vertical | enum | AUTO, BEAUTY, RETAIL, RESTAURANT, etc. |
Response 204
WABA Phone Number lifecycle
Endpoints administrativos do número (alternativa ao Embedded Signup quando o cliente quer controle granular).
POST /v1/phones/:id/request-code
Solicita código de verificação SMS ou voz.
Body
| Campo | Tipo | Default |
|---|---|---|
method | SMS | VOICE | SMS |
locale | string | pt_BR |
Response 204
POST /v1/phones/:id/verify-code
Confirma o código recebido por SMS/voz.
Body: { "code": "123456" } → Response 204
POST /v1/phones/:id/register
Registra o número na WABA (passo final). PIN obrigatório.
Body: { "pin": "123456" } → Response 204
POST /v1/phones/:id/deregister
Desregistra o número (libera para outra WABA).
Response 204
POST /v1/phones/:id/request-name-change
Solicita mudança de display name (precisa aprovação Meta).
Body: { "name": "Acme Atendimento" } → Response 200 com request_id.
POST /v1/phones/:id/two-step-pin
Define o PIN de 6 dígitos (2-step verification).
Body: { "pin": "123456" } → Response 204
POST /v1/phones/:id/rotate-token
Substitui o access token armazenado (sem precisar re-onboardar). Útil quando o System User Token é rotacionado no Business Manager.
Body: { "accessToken": "EAAxxx..." } → Response 204
Validação: o gateway chama getPhoneNumberInfo com o novo token antes de salvar.
WABA Block/Unblock
GET /v1/phones/:id/blocked
Lista usuários bloqueados pelo número (anti-spam).
Response 200
{ "users": [{ "input": "5511988887777", "wa_id": "5511988887777", ... }] }
POST /v1/phones/:id/block
Body: { "users": ["5511988887777", ...] } (1-100 itens) → Response 204
POST /v1/phones/:id/unblock
Mesmo formato. Response 204
WhatsApp Business Account (WABA-level)
Endpoints para inspeção da WABA inteira (não do número individual).
GET /v1/phones/:id/waba
Retorna info da WABA.
GET /v1/phones/:id/waba/phones
Lista todos os números registrados naquela WABA.
GET /v1/phones/:id/waba/subscribed-apps
Lista apps Meta com webhook subscrito.
POST /v1/phones/:id/waba/subscribed-apps
Re-subscreve o app gateway aos webhooks.
Body (opcional)
| Campo | Tipo |
|---|---|
overrideCallbackUri | URL |
verifyToken | string |
Response 204
DELETE /v1/phones/:id/waba/subscribed-apps
Remove subscription. Response 204