Pular para o conteúdo
WbizTool

API v2 (beta)

API v2

A API v2 é a nova API REST do WbizTool: uma chave por app, só com o acesso de que ele precisa, URLs no estilo de recursos, códigos de status HTTP reais, webhooks JSON assinados e novas tentativas seguras. Esta página cobre o que toda requisição tem em comum. As páginas de recursos cobrem cada endpoint.

URL base#

https://wbiztool.com/api/v2

Os caminhos não têm barra no final (/api/v2/messages), mas uma barra final também é aceita. Um endereço que não existe responde 404 com o código not_found.

Exemplo rápido#

Verifique sua chave com GET /me. Funciona com qualquer permissão e não envia nada:

curl https://wbiztool.com/api/v2/me \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"
{
  "workspace": { "id": 5012, "name": "Acme Bakery" },
  "key": {
    "id": 7,
    "name": "Order system",
    "mode": "live",
    "scopes": ["messages:send", "messages:read"],
    "limited_to_numbers": false,
    "number_ids": [],
    "expires_at": null
  },
  "plan": { "name": "Starter" },
  "limits": {
    "requests_per_minute": 60,
    "requests_per_day": 10000,
    "messages_per_number_per_day": 1000,
    "messages_remaining": null
  }
}

messages_remaining é null quando o plano envia mensagens ilimitadas. plan é null quando o espaço de trabalho não tem um plano ativo.

Chaves#

Envie sua chave no cabeçalho Authorization em cada requisição:

Authorization: Bearer wbz_live_…

Não existe client_id: a chave identifica o espaço de trabalho dela. Uma chave v2 começa com wbz_live_ ou wbz_test_, seguida de 38 letras e dígitos. Chaves v1 não funcionam na v2 (recebem v1_key_on_v2), e chaves v2 não funcionam na v1.

Criar uma chave#

Os Proprietários criam chaves em Configurações → Chaves de API, no cartão Chaves de API v2: clique em Criar chave v2 e escolha:

  • Nome: o app que vai usá-la, até 50 caracteres.
  • Tipo de chave: Real envia mensagens de verdade; Teste verifica tudo e não envia nada (veja Modo de teste).
  • O que ela pode fazer: as permissões, ou Tudo.
  • Números que ela pode usar: todos os números, incluindo os adicionados depois, ou só alguns (veja Chaves limitadas a alguns números).
  • Expira: nunca, ou em 30 dias, 90 dias ou 1 ano.

A chave é exibida uma única vez. Copie-a na hora e guarde-a no seu servidor, por exemplo em uma variável de ambiente. O WbizTool guarda apenas um hash dela e os quatro últimos caracteres, então uma chave perdida não pode ser exibida de novo: revogue-a e crie uma nova.

Um espaço de trabalho pode ter até 10 chaves v2 não revogadas. O cartão mostra, para cada chave, os quatro últimos caracteres, as permissões, os números, a expiração e quando e de qual endereço IP ela foi usada pela última vez. Revogar desativa uma chave na hora, e com ela os endpoints de webhook que ela criou. Uma chave com a data de expiração vencida recebe api_key_expired.

Permissões#

Cada chave só pode fazer o que as permissões dela permitem. Uma requisição fora delas responde 403 com missing_scope, e required_scope no erro diz qual permissão é necessária.

PermissãoO que ela permite
messages:sendEnviar mensagens e lotes, e cancelar mensagens em espera: POST /messages, POST /messages/batch, DELETE /messages/{id}
messages:readLer mensagens e o status delas (GET /messages, GET /messages/{id}) e gerenciar endpoints de webhook
remindersCriar, listar, alterar, pausar e excluir lembretes
numbersListar números, ver a conexão deles e conectar números de WhatsApp
mediaEnviar, listar e excluir arquivos no Diretório de mídia
contactsVerificação de números (os endpoints de contatos virão depois)

GET /me não precisa de nenhuma permissão específica. Enviar para um contato salvo com to.contact_id precisa só de messages:send.

Chaves limitadas a alguns números#

Uma chave limitada a alguns números só funciona com eles:

  • Ela envia só desses números e lista, lê e cancela só as mensagens deles. Outro número em from recebe number_not_allowed.
  • GET /numbers lista só esses números. Ela pode reconectá-los, mas não pode adicionar um número novo.
  • Ela vê e altera só os lembretes que enviam desses números, e um lembrete novo precisa indicar um deles como from.
  • Ela não pode gerenciar endpoints de webhook de forma alguma, porque eles recebem os eventos do espaço de trabalho inteiro.

GET /me mostra limited_to_numbers e os number_ids que a chave pode usar.

Requisições#

  • JSON na entrada e na saída. Envie os corpos como Content-Type: application/json. A única exceção é o envio de um arquivo, que é multipart/form-data. Toda resposta é JSON, inclusive os erros.
  • Os nomes dos campos são snake_case, e campos desconhecidos são recusados: um erro de digitação como txt responde validation_failed em vez de ser ignorado.
  • Números de telefone vão no formato internacional com + (E.164), por exemplo +919876543210. Espaços e hifens são permitidos; um número sem + é recusado com invalid_phone.
  • Horários vão em ISO 8601 com o deslocamento, por exemplo 2026-10-20T09:30:00+05:30 ou 2026-10-20T04:00:00Z. Um horário sem deslocamento é recusado com invalid_datetime. Os horários nas respostas estão em UTC e terminam em Z, exceto o next_run_at de um lembrete, que fica no fuso horário do lembrete.
  • IDs são inteiros, como o id de um número (from quando você envia) ou o id de uma mensagem.
  • Os códigos de status significam o que dizem: 200 OK, 201 criado, 202 aceito (na fila), 400 a requisição está errada, 401 a chave está errada, 402 não há mensagens restantes, 403 não permitido, 404 não encontrado, 409 conflito, 413 grande demais, 415 tipo de conteúdo errado, 422 um valor não pode ser usado, 429 requisições demais, 5xx problema do nosso lado.

As respostas trazem Cache-Control: no-store.

Erros#

Todo erro tem o mesmo formato:

{
  "error": {
    "code": "invalid_phone",
    "message": "This is not a valid phone number. Write it in international format with +, e.g. +919876543210.",
    "field": "to.phone",
    "docs": "https://wbiztool.com/docs/api/v2/errors/#invalid_phone",
    "request_id": "req_4f1c2a9b8e7d6c5b4a392817"
  }
}
  • code é estável: tome decisões com base nele no seu código. message é um texto em inglês para o desenvolvedor e pode mudar.
  • field indica o campo a que o erro se refere (to.phone, to[3].phone, schedule.cron), ou é null.
  • docs leva ao código na página de erros.
  • request_id é igual ao cabeçalho X-Request-Id. Informe-o se entrar em contato com a gente.
  • Alguns erros trazem detalhes, por exemplo status em not_cancellable ou used e limit em storage_full. Quando uma requisição tem vários problemas, errors lista os outros, cada um com field e message.

Todos os códigos, o status HTTP de cada um e o que fazer estão na página de erros.

Idempotency-Key#

Um erro de rede ou um timeout deixa você sem saber se uma requisição funcionou. Envie um cabeçalho Idempotency-Key com um POST que cria algo, e você pode enviá-lo de novo com segurança:

curl -X POST https://wbiztool.com/api/v2/messages \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042-ready" \
  -d '{"to": {"phone": "+919876543210"}, "text": "Hi Asha, your order #1042 is ready."}'
  • O valor é seu: qualquer string única de 1 a 255 caracteres imprimíveis, como um UUID ou o ID do seu próprio pedido. Crie um novo para cada requisição nova e reutilize-o só para uma nova tentativa da mesma requisição.
  • Uma nova tentativa recebe de volta a primeira resposta, com o cabeçalho Idempotent-Replayed: true. Nada é feito duas vezes: nenhuma segunda mensagem, lembrete, arquivo ou endpoint.
  • As chaves duram 24 horas a partir da primeira requisição e pertencem à sua chave de API: outra chave de API do espaço de trabalho pode usar o mesmo valor sem conflito.
  • Mesma chave, requisição diferente: uma requisição com uma chave já usada para outro método, caminho ou corpo responde 422 idempotency_key_reused.
  • Ainda em andamento: enquanto a primeira requisição com a chave ainda está sendo processada, uma nova tentativa responde 409 idempotency_in_progress com Retry-After: 1. Espere um instante e envie de novo.
  • Erros não são guardados. Se a primeira requisição respondeu com um erro, nada fica guardado: corrija a requisição e envie de novo com a mesma chave.
  • Segredos não são repetidos. Uma repetição de POST /webhooks não inclui o secret do endpoint, que só aparece na primeira resposta.

Funciona em POST /messages, POST /messages/batch, POST /numbers, POST /reminders, POST /media, POST /number-checks e POST /webhooks, e é opcional em todos. As outras requisições ignoram o cabeçalho. Um valor vazio ou longo demais responde 400 invalid_idempotency_key.

Limites de requisições#

Cada chave pode fazer 60 requisições por minuto e 10.000 requisições por dia. São janelas fixas: a janela do minuto começa no minuto do relógio, e a do dia às 00:00 UTC. Acima de um limite, a requisição responde 429 rate_limited.

As respostas a requisições com uma chave válida trazem estes cabeçalhos:

CabeçalhoSignificado
RateLimit-LimitRequisições permitidas na janela atual (60, ou 10000 depois que o limite diário é atingido)
RateLimit-RemainingRequisições restantes nessa janela
RateLimit-ResetSegundos até essa janela recomeçar
RateLimit-PolicyOs dois limites: 60;w=60, 10000;w=86400
Retry-AfterEm um 429: segundos para esperar antes de tentar de novo

Além desses:

  • Chaves erradas: mais de 30 requisições por minuto com uma chave errada a partir de um endereço IP respondem 429 too_many_auth_failures com Retry-After: 60.
  • Mensagens por número: um número envia no máximo 1.000 mensagens em 24 horas (uso justo). Um envio acima disso responde 429 number_daily_cap_reached.

Paginação#

Listas que podem crescer (GET /messages, /reminders, /media, /number-checks e os /results de uma verificação) vêm em páginas, das mais recentes para as mais antigas:

{
  "data": [ … ],
  "next_cursor": "eyJpZCI6OTgxNzI2MywidCI6IjIwMjYtMTAtMThUMTA6MTU6MDIuMzExWiIsImYiOiI0NGIxMzZmYTM1NWIifQ"
}
  • limit define o tamanho da página, de 1 a 100 (padrão 25).
  • Para obter a próxima página, envie a mesma requisição com cursor igual ao next_cursor da última página. next_cursor é null na última página.
  • Mantenha os outros filtros iguais: um cursor usado com filtros diferentes responde 400 invalid_cursor. Recomece sem cursor.
  • Trate o cursor como uma string opaca. Itens adicionados enquanto você percorre as páginas não deslocam as páginas.
curl "https://wbiztool.com/api/v2/messages?limit=100&cursor=eyJpZCI6OTgxNzI2MywidCI6..." \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

GET /numbers e GET /webhooks retornam tudo em uma única lista data.

IDs de requisição#

Toda resposta, inclusive os erros, tem um cabeçalho X-Request-Id como req_4f1c2a9b8e7d6c5b4a392817. Os erros trazem o mesmo valor em request_id. Registre-o e informe-o se entrar em contato com a gente: ele nos permite encontrar a requisição nos nossos logs, que registram o ID da sua chave, mas nunca a chave.

Se você enviar o seu próprio X-Request-Id (até 100 caracteres imprimíveis), ele volta como X-Client-Request-Id, para você relacionar as respostas com os seus próprios logs.

Modo de teste#

Uma chave de teste (wbz_test_…) permite criar e testar uma integração sem enviar nada. Crie uma em Configurações → Chaves de API com Tipo de chave: Teste. GET /me mostra "mode": "test".

O que uma chave de teste faz igual a uma chave real:

  • POST /messages e POST /messages/batch verificam tudo o que um envio real verifica: o destinatário, o texto, a mídia, send_at e expires_at, o número que envia e as permissões e os números da chave. Os mesmos erros recebem as mesmas respostas de erro.
  • Permissões, números, limites de requisições e Idempotency-Key funcionam do mesmo jeito.
  • Toda leitura do resto do espaço de trabalho (GET /me, /numbers, /reminders, /media, /number-checks, /webhooks) mostra os dados reais, somente para leitura.

O que muda:

  • Nada é enviado. Um envio de teste fica guardado como mensagem de teste e não usa as mensagens do plano nem as 1.000 diárias do número, então nunca recebe no_credits nem number_daily_cap_reached.
  • O status avança sozinho: queued, depois sent 5 segundos mais tarde e delivered 15 segundos depois de criada (contados a partir de send_at em uma mensagem agendada). Uma mensagem cujo expires_at chega antes de ela ser enviada passa a expired. Mensagens de teste nunca ficam read nem failed.
  • Uma chave de teste vê só as próprias mensagens de teste. GET /messages e GET /messages/{id} mostram essas mensagens e nada mais, e DELETE /messages/{id} cancela uma enquanto ela está queued ou scheduled. Chaves reais nunca veem mensagens de teste. O filtro status de GET /messages não é suportado em chaves de teste e responde test_mode_unsupported; number, since e until funcionam.
  • As outras gravações são recusadas com 403 test_mode_unsupported: conectar um número, criar, alterar ou excluir lembretes, enviar ou excluir mídia, iniciar uma verificação de números e adicionar, remover, trocar o segredo ou testar endpoints de webhook.
  • Nenhum evento de webhook é enviado para mensagens de teste.
  • As mensagens de teste ficam guardadas por 30 dias.

Recursos#

  • Mensagens: envie agora ou depois, envie para até 1.000 destinatários, leia o histórico, cancele.
  • Números: liste seus números de WhatsApp e contas do Telegram e conecte um número de WhatsApp por código QR ou código de login.
  • Lembretes: mensagens repetidas em um agendamento cron.
  • Mídia: envie os arquivos uma vez e mande-os por media_id.
  • Verificação de números: descubra quais números estão no WhatsApp.
  • Webhooks: eventos assinados quando uma mensagem é enviada, falha, é cancelada ou expira.
  • Erros: todos os códigos de erro.
  • Migrar da v1 para a v2: cada endpoint e campo da v1 e o equivalente na v2.