API v2 (beta)
Migrar da v1 para a v2
A API v2 faz o que a v1 faz, com chaves mais seguras, um único estilo de URL, códigos de status HTTP reais e webhooks JSON assinados. Esta página relaciona cada endpoint e campo da v1 ao equivalente na v2. O que é novo na própria v2 está na visão geral.
O que muda em tudo#
- Chaves: o
client_id+api_keyda v1 viram um único cabeçalho,Authorization: Bearer wbz_live_…. Crie uma chave v2 em Configurações → Chaves de API, no cartão Chaves de API v2, só com as permissões de que o app precisa. Chaves v1 não funcionam na v2, e chaves v2 não funcionam na v1. - Só JSON: sem campos de formulário. Os uploads de arquivo vão para
POST /media(multipart) e são enviados pelomedia_id. - Métodos e URLs:
GETpara ler,POSTpara criar,PATCHpara alterar,DELETEpara cancelar ou excluir, emhttps://wbiztool.com/api/v2. - Códigos de status HTTP no lugar de
"status": 0ou1(veja Respostas e erros). - Números de telefone em formato internacional com
+, semcountry_code. - Horários em ISO 8601 com deslocamento, no lugar de campos separados de data, hora e fuso horário.
- Webhooks são endpoints que você adiciona uma vez para o espaço de trabalho, com eventos JSON assinados, no lugar de uma URL
webhookem cada mensagem.
Endpoint por endpoint#
Os caminhos da v2 são relativos a https://wbiztool.com/api/v2.
Envio, campo a campo#
| v1 | v2 | Observações |
|---|---|---|
client_id + api_key (corpo ou Authorization: Bearer) | Authorization: Bearer wbz_live_… | Uma chave v2 nova; sem client_id |
phone + country_code | to.phone | Um número em E.164 com +: "9876543210" com "country_code": "91" vira {"phone": "+919876543210"}. Nenhum código do país é adicionado por você |
phone com um @username (Telegram) | to.username | @name, t.me/name ou tg: e um id, a partir de uma conta do Telegram |
group_name | to.group | O nome exato do grupo |
| (não existe na v1) | to.contact_id | Um contato salvo |
whatsapp_client | from | O id do número; opcional quando há um só número conectado, como antes |
msg (ou message) | text | Até 3.000 caracteres, como antes |
msg_type 0, 1, 2 | nenhum | Uma mensagem com media é uma mensagem de mídia; media.type (image ou file) quando o link não indica |
img_url / file_url | media.url | Um link público http(s) |
file (upload na mesma requisição) | media.media_id | Envie o arquivo primeiro e depois mande o id quantas vezes quiser |
file_name | media.file_name | Para arquivos |
date + time + timezone de schedule_msg/ | send_at | Um único horário com o deslocamento: 24/12/2026, 10:30 e Asia/Kolkata viram "2026-12-24T10:30:00+05:30" |
expire_after_seconds | expires_at | Um horário, não uma duração: agora mais os segundos, com o deslocamento |
webhook | endpoints de webhook | Adicionados uma vez com POST /webhooks, para todas as mensagens do espaço de trabalho |
msg_id na resposta | id | A própria Message volta, com o status dela |
O mesmo envio na v1 e na v2:
# v1
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Authorization: Bearer YOUR_V1_KEY" \
-H "Content-Type: application/json" \
-d '{"whatsapp_client": 101, "msg_type": 1, "country_code": "91", "phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg", "msg": "Our Diwali sale starts today",
"expire_after_seconds": 3600}'
# v2
curl -X POST https://wbiztool.com/api/v2/messages \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: diwali-9876543210" \
-d '{"from": 101, "to": {"phone": "+919876543210"},
"media": {"url": "https://example.com/offers/diwali-sale.jpg"}, "text": "Our Diwali sale starts today",
"expires_at": "2026-10-20T11:30:00+05:30"}'
Alguns comportamentos da v1 deixaram de existir de propósito:
- Nada de adivinhar o código do país. A v1 colocava
country_codena frente de um número (com91, sempre na frente de um número de 10 dígitos). A v2 usa o número exatamente como escrito, com+. - Nenhum download de arquivo na chamada. A v1 baixava
img_urlefile_urldurante a requisição. A v2 verifica se o link é público e baixa o arquivo quando a mensagem é enviada; um link ruim aparece como uma mensagemfailed. - Nenhuma linha com falha na recusa. Quando a v1 recusa um envio acima das 1.000 diárias, ela ainda salva a mensagem como falha. A v2 não salva nada quando recusa um envio.
- Campos desconhecidos são recusados em vez de ignorados.
Status#
Os números e as palavras da v1 viram um único campo status:
| v1 | status na v2 |
|---|---|
0 Created / Pending | queued, ou scheduled enquanto o send_at dela ainda não chegou |
1 Sent | sent, delivered ou read (os tiques do WhatsApp) |
2 Failed | failed |
3 Cancelled | cancelled |
4 Expired | expired |
Os eventos de webhook são message.sent, message.failed, message.cancelled e message.expired, correspondentes a SENT, FAILED, CANCELLED e EXPIRED da v1.
Respostas e erros#
A v1 responde a muitos erros com HTTP 200 ou 400 e "status": 0, e ao sucesso com "status": 1. A v2 usa o código de status HTTP:
- Sucesso é
200,201(criado) ou202(na fila), e o corpo é o próprio objeto, como a Message. Não há o invólucrostatus: 1. - Erros são
4xxou5xxcom um único formato:{"error": {"code", "message", "field", "docs", "request_id"}}. Decida pelocode, não pelamessageem inglês. Todos os códigos estão na página de erros.
# v1
result = response.json()
if result.get("status") == 1:
msg_id = result["msg_id"]
# v2
if response.status_code == 202:
message_id = response.json()["id"]
else:
error = response.json()["error"]
if error["code"] == "number_daily_cap_reached":
... # try again tomorrow
Algumas mensagens da v1 e os códigos na v2:
| Mensagem da v1 | Código da v2 |
|---|---|
Auth Error: invalid api key | 401 invalid_api_key, api_key_revoked ou api_key_expired |
Invalid phone number / Invalid Contact Number "…" | 422 invalid_phone |
Msg cant be null | 400 text_required |
Message length is too long | 400 text_too_long |
Invalid whatsapp client | 422 number_not_found |
Invalid whatsapp client id. | 422 from_required |
Not enough credits | 402 no_credits |
Daily limit reached: … | 429 number_daily_cap_reached |
Demo Account can not access apis | 403 demo_account |
Account Disabled | 403 account_disabled |
Invalid JSON format: … | 400 invalid_json |
Webhooks#
Na v1, cada mensagem pode levar uma URL webhook que recebe um msg_id=…&status=SENT codificado como formulário. Na v2:
- Adicione um endpoint uma vez com
POST /webhookse guarde osecretdele. - Ele recebe eventos JSON de todas as mensagens do espaço de trabalho, com a Message inteira em
data.message. Associe-os aos seus registros pordata.message.id. - Verifique a assinatura: o mesmo esquema da v1 (
WbizTool-Timestamp,WbizTool-Signature: v1=…), mas com o segredo próprio do endpoint em vez do segredo do espaço de trabalho. - Descarte repetidos com
WbizTool-Event-Id. As novas tentativas continuam por cerca de 23 horas, não 4 tentativas em poucos minutos como na v1, e respostas4xxtambém são tentadas de novo.
Os eventos de conexão da v1 (webhook_url em whatsapp/connect/) ainda não têm evento na v2: consulte GET /numbers/{id} periodicamente.
Uma checklist#
Crie uma chave v2 por app
Em Configurações → Chaves de API, só com as permissões de que ele precisa. Teste primeiro com uma chave de teste, que verifica tudo e não envia nada.
Altere as requisições
URLs e métodos novos, corpos JSON,
to/from/text/media, números de telefone com+, horários com deslocamento. Adicione umaIdempotency-Keya cada envio.Altere o tratamento de erros
Confira o status HTTP e depois
error.code. Trate429esperando oRetry-After.Migre os webhooks
Adicione um endpoint, verifique as assinaturas com o segredo dele e descarte repetidos pelo id do evento.
Troque e revogue
Quando o app estiver rodando na v2, exclua a chave v1 dele em Configurações → Chaves de API.
