Onboarding de parceiros (Embedded Signup)

Onboarding de parceiros (Embedded Signup)

POST /v1/onboarding/sessions e /v1/onboarding/domains — seu cliente conecta o WhatsApp Business de dentro do seu produto, sem passar pela dashboard.

Permite que o seu cliente final conecte o WhatsApp Business dele de dentro do seu produto, sem passar pela dashboard do WaBlast. Visão comercial do modelo de parceria: /parceiros.

Dois hosts diferentes. Os endpoints abaixo ficam em https://api.wablastmessage.com (autenticados pela sua chave wak_), mas a embed_url devolvida aponta para https://app.wablastmessage.com. Não troque um pelo outro.

POST /v1/onboarding/sessions

Cria a sessão de onboarding e devolve a URL que o cliente final deve abrir.

Chame sempre do seu servidor — nunca do navegador. A chave wak_ no front-end é chave vazada.

POST /v1/onboarding/sessions 201400401402409429

Body (todos opcionais):

Campo Tipo Obrigatório Regras
external_ref string Não 1–191 chars. O seu id do cliente final; volta no webhook e na consulta da sessão
redirect_uri string Não URL https, ≤ 2048 chars. O host precisa estar registrado como domínio REDIRECT ativo
origin string Não Só para popup no domínio do parceiro — hoje sempre falha (ver limitações abaixo)

Pré-condição: ter ao menos um slot de conexão livre, senão 402 NO_FREE_SLOT.

Resposta 201:

Resposta 201

{
"id": "sess_abc",
"session_token": "wos_...",
"embed_url": "https://app.wablastmessage.com/embed/v1/connect?session=sess_abc&t=wos_...",
"expires_at": "2026-08-02T12:10:00.000Z",
"external_ref": "cliente-42"
}

O session_token aparece uma única vez — no banco guardamos só o hash, não há como recuperá-lo. A sessão vale 10 minutos e é de uso único (consumo atômico: dois resgates simultâneos, só um passa). Expirou ou já foi usada? Crie outra sessão.

O dono da sessão é sempre a chave autenticada; campos de identidade no body são ignorados.

Erros na criação da sessão:

codeHTTPO que significa
NO_FREE_SLOT402Sem slot de conexão livre. Compre outra conexão ou libere uma
REDIRECT_URI_NOT_ALLOWED400Host do redirect_uri não está registrado como domínio REDIRECT ativo
ORIGIN_NOT_ALLOWED400origin não permitido
DOMAIN_NOT_REGISTERED409Domínio de embed sem registro na Meta (ver limitações abaixo)
INVALID_URL400URL malformada ou não-https
INVALID_BODY400Falha de schema (ex.: external_ref acima de 191 caracteres)
UNAUTHENTICATED401Chave ausente, inválida, revogada ou expirada
RATE_LIMITED429Acima do limite de requisições

Exemplo

curl -X POST https://api.wablastmessage.com/v1/onboarding/sessions \
-H "Authorization: Bearer wak_sua_chave" \
-H "Content-Type: application/json" \
-d '{"external_ref":"cliente-42","redirect_uri":"https://app.seusistema.com/wa/callback"}'

GET /v1/onboarding/sessions/{id}

Fonte autoritativa do resultado do onboarding. Não trate o redirect do navegador como confirmação — o cliente pode fechar a aba. A confirmação é o webhook account.connected e, como fallback, o polling deste endpoint.

GET /v1/onboarding/sessions/{id} 200401404429

Resposta 200:

Resposta 200

{
"id": "sess_abc",
"status": "CONSUMED",
"external_ref": "cliente-42",
"account_id": "cms5cy8nx0010mvqwy9nbmzb8",
"failure_reason": null,
"expires_at": "2026-08-02T12:10:00.000Z",
"created_at": "2026-08-02T12:00:00.000Z"
}
statusSignificado
PENDINGCriada, ainda não usada
CONSUMINGResgate em andamento (troca de token + conexão)
CONSUMEDSucesso — account_id preenchido
FAILEDFalhou após o resgate — failure_reason preenchido
EXPIREDPassou dos 10 min sem uso (derivado na leitura, não é estado gravado)
  • account_id é o id interno da conexão, o mesmo de GET /v1/accounts — não é o WABA ID. É ele que você passa como account_id ao enviar mensagens.
  • failure_reason é texto em pt-BR, sanitizado e truncado em 500 chars. Não é código estável — serve para o humano ler; ramifique por status.
  • Sessão de outro tenant devolve 404 (não 403): confirmar a existência já seria vazamento.

Exemplo

curl https://api.wablastmessage.com/v1/onboarding/sessions/sess_abc \
-H "Authorization: Bearer wak_sua_chave"

POST /v1/onboarding/domains

Registra domínio próprio para redirect_uri. Self-service, vale na hora.

POST /v1/onboarding/domains 201400401409429

Body (JSON):

{ "domain": "app.seusistema.com", "purpose": "REDIRECT" }
  • Aceita host puro ou URL completa; guardamos só o host, em minúsculas.
  • Recusa localhost, .local, .internal e IP literal (400 INVALID_DOMAIN).
  • Máximo de 20 domínios por conta → 409 DOMAIN_LIMIT_REACHED se exceder.
  • purpose: "REDIRECT" nasce ACTIVE. purpose: "EMBED" nasce PENDING e depende de registro manual na Meta — hoje não há caminho self-service para ativá-lo.

Exemplo

curl -X POST https://api.wablastmessage.com/v1/onboarding/domains \
-H "Authorization: Bearer wak_sua_chave" \
-H "Content-Type: application/json" \
-d '{"domain":"app.seusistema.com","purpose":"REDIRECT"}'

GET /v1/onboarding/domains

Lista os domínios registrados da sua conta.

GET /v1/onboarding/domains 200401429

DELETE /v1/onboarding/domains/{id}

Remove o domínio. Domínio de outra conta → 404.

DELETE /v1/onboarding/domains/{id} 200401404429
{ "deleted": true }

Eventos relacionados e limitações

Ao concluir o onboarding, você recebe o evento account.connected no seu endpoint de webhooks, com external_ref, waba_id, phone_number, display_name e onboarded_via no payload — case por data.external_ref e guarde o account_id do envelope. Nunca vai token nenhum nesse payload.

O evento account.connect_failed consta do catálogo mas não é emitido hoje — não construa tratamento de falha em cima dele. Detecte falha por GET /v1/onboarding/sessions/\{id\} (status: FAILED + failure_reason). Além disso, o account.connected pode não chegar quando um slot de conexão é reciclado (desconectar um cliente e onboardar outro no lugar). Por isso o polling da sessão é recomendado como fallback, não como opcional.

Popup no domínio do parceiro não é oferecido hoje. O campo origin existe no contrato, mas qualquer uso falha: rodar o Embedded Signup no domínio do parceiro depende de registro manual do domínio na Meta (purpose: "EMBED" nasce PENDING e não há caminho self-service para ativá-lo). O modo suportado é o popup a partir da nossa página (embed_url), em que o cliente final aceita os termos da Meta diretamente.

Dúvidas comerciais sobre o modelo de parceria (quem é dono de quê, pré-requisitos do cliente final, fricções da Meta): /parceiros.

Pular para o conteúdo