Quickstart: revenda

Para agência ou integrador que opera vários negócios na mesma Conta: cada negócio vira um Cliente, conecta o próprio WhatsApp por um link e recebe mensagens pelo número dele.

Na BotoZap, a sua empresa é a Conta e cada negócio atendido é um Cliente. A Conta vem da chave de API, então você nunca passa um id de conta, e o isolamento é garantido no servidor. O vocabulário completo está em Conceitos. Se você opera um negócio só, o quickstart do seu número é mais curto.

1. Gere uma chave de produção

Em Configurações › Desenvolvedores › Chaves de API, no painel, gere uma chave Produção (bz_live_) com customers:write, numbers:read, webhooks:write e messages:send. Chaves sandbox não acessam Clientes nem links de setup e recebem 403 sandbox_forbidden. Para experimentar o envio antes, use Primeiros passos.

2. Crie o Cliente

Criar um cliente

Cria um Cliente (um negócio atendido por você) na Conta da chave. Cada número conectado pertence a um Cliente.

curl https://botozap.com.br/api/v1/customers \
  -X POST \
  -H "X-API-Key: $BOTOZAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Padaria Boto"
}'

Resposta 201

{
  "data": {
    "id": "5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11",
    "name": "Padaria Boto",
    "external_customer_id": null,
    "is_self": false,
    "created_at": "2026-07-14T12:00:00.000Z",
    "updated_at": "2026-07-14T12:00:00.000Z"
  }
}

`external_customer_id` é opcional: use o id do cliente no seu sistema. O valor é único por Conta; repeti-lo responde 409 `external_id_conflict`.

A Conta vem da chave. Não existe `account_id` no corpo.

O Cliente abre a url e conecta o WhatsApp oficial pelo cadastro da Meta (Embedded Signup), sem compartilhar senha com você. O número conectado fica vinculado a esse Cliente. Pelo painel, o mesmo fluxo está em Clientes e Links de setup. A página do link é sempre em português: o campo language continua aceito por compatibilidade, mas é ignorado.

Gerar um link de setup para o cliente

Cria o link que o cliente abre para conectar o WhatsApp oficial pelo cadastro da Meta (Embedded Signup), sem compartilhar senha com você.

curl https://botozap.com.br/api/v1/customers/5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11/setup_links \
  -X POST \
  -H "X-API-Key: $BOTOZAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "allowed_connection_types": [
    "dedicated",
    "coexistence"
  ],
  "success_redirect_url": "https://exemplo-integracao.com.br/onboarding/ok"
}'

Resposta 201

{
  "data": {
    "id": "5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11",
    "status": "active",
    "whatsapp_setup_status": "pending",
    "url": "https://botozap.com.br/whatsapp/setup/...",
    "allowed_connection_types": [
      "dedicated",
      "coexistence"
    ],
    "language": null,
    "success_redirect_url": "https://exemplo-integracao.com.br/onboarding/ok",
    "failure_redirect_url": null,
    "theme_config": null,
    "expires_at": "2026-07-14T12:00:00.000Z",
    "created_at": "2026-07-14T12:00:00.000Z",
    "updated_at": "2026-07-14T12:00:00.000Z"
  }
}

O link vale 30 dias. Acompanhe `whatsapp_setup_status` (`pending` → `in_progress` → `completed` ou `failed`) em `GET /api/v1/customers/{id}/setup_links`.

`allowed_connection_types` aceita `dedicated` (número só na API) e `coexistence` (API e aplicativo no mesmo número). Omitido, vale `dedicated`.

`provision_phone_number` foi removido: o BotoZap não provisiona número. Se enviado, é ignorado e não volta na resposta.

Para revogar, envie `PATCH /api/v1/customers/{id}/setup_links/{linkId}` com `status: "revoked"`.

A página do link é sempre em português. `language` é aceito por compatibilidade e ignorado: links novos voltam com `language: null`.

`success_redirect_url`/`failure_redirect_url` precisam ser `https`. Ao concluir, a página de conexão leva o cliente para a URL de sucesso com `setup_link_id` e `status=completed`; link esgotado vai para a de falha com `status=failed`, e desistência, com `status=cancelled`. `theme_config` é reservado e sempre `null`.

4. Encontre o número do Cliente

Depois que o link chega a completed, liste os números. Cada item traz customer_id, e a listagem aceita o filtro ?customer_id= para trazer só os números de um Cliente.

Listar números conectados

Lista os números da conta, paginado por página (`page`/`per_page`).

curl https://botozap.com.br/api/v1/phone_numbers?page=1&per_page=2 \
  -H "X-API-Key: $BOTOZAP_KEY"

Resposta 200

{
  "data": [],
  "meta": {
    "page": 1,
    "per_page": 2,
    "total_pages": 1,
    "total_count": 1
  }
}

5. Receba os eventos

Um endpoint com customer_id: null recebe os eventos de todos os Clientes da Conta. Informe o customer_id para separar um endpoint por Cliente. Em qualquer caso, o endpoint só passa a receber eventos reais depois do teste assinado respondido com 2xx (Webhooks).

Registrar um endpoint de webhook

Cria o endpoint com `health_status=unverified`: mesmo com `active=true`, eventos reais só são admitidos depois de um teste assinado com resposta 2xx.

curl https://botozap.com.br/api/v1/webhooks \
  -X POST \
  -H "X-API-Key: $BOTOZAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://exemplo-integracao.com.br/webhooks/botozap",
  "events": [
    "messages",
    "statuses"
  ],
  "customer_id": null
}'

Resposta 201

{
  "data": {
    "id": "5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11",
    "customer_id": "5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11",
    "url": "https://exemplo-integracao.com.br/webhooks/botozap",
    "events": [
      "messages",
      "statuses"
    ],
    "active": true,
    "has_authorization": false,
    "health_status": "unverified",
    "failure_streak": 0,
    "verified_at": null,
    "last_success_at": null,
    "last_failure_at": null,
    "last_response_code": null,
    "next_attempt_at": null,
    "paused_at": null,
    "secret": "whsec_...",
    "created_at": "2026-07-14T12:00:00.000Z",
    "updated_at": "2026-07-14T12:00:00.000Z"
  }
}

O `secret` (`whsec_...`) só aparece nesta resposta de criação — guarde-o agora, ele assina cada entrega (`X-Webhook-Signature`).

`active` expressa sua intenção manual; `health_status` começa como `unverified`. Execute `POST /api/v1/webhooks/{id}/test` e receba 2xx para verificar e ativar o endpoint.

`customer_id` é opcional: omitido ou `null`, o endpoint recebe eventos de todos os Clientes da Conta; informado, recebe apenas eventos daquele Cliente. O id precisa pertencer à Conta da chave.

A URL precisa usar https:// e resolver para um destino público (o BotoZap bloqueia loopback/redes privadas por segurança).

6. Envie pelo número do Cliente

Com mais de um número na Conta, todo envio precisa de from: o phone_number_id da Meta ou o UUID interno do número, ambos na listagem do passo 4. Sem ele, a API responde 422 ambiguous_phone.

Enviar por um número específico (`from`)

Contas com mais de um número conectado precisam informar `from` (o `phone_number_id` Meta ou o UUID interno) para desambiguar por qual número enviar.

curl https://botozap.com.br/api/v1/messages \
  -X POST \
  -H "X-API-Key: $BOTOZAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+5511988887777",
  "type": "template",
  "template": {
    "name": "pedido_confirmado",
    "language": {
      "code": "pt_BR"
    }
  },
  "from": "112233445566778"
}'

Resposta 201

{
  "id": "5b0a9d0e-6e1a-4f3b-8c2d-1a9f6e0b7c11",
  "wamid": "wamid.HBgNNTU5MTk5OTk5OTk5FQIAERgSM0FCQzFEMkUzRjRBNUI2QzdEAA==",
  "to": "5511988887777",
  "sent_to": "5511988887777",
  "status": "sent"
}

`from` é obrigatório quando a conta tem mais de um número conectado — sem ele a API responde 422 `ambiguous_phone`.

Use o `phone_number_id` Meta ou o UUID interno retornado por `GET /api/v1/phone_numbers`.

Próximos passos