API de mensagens
API de envio de mensagens
Envie um texto, uma imagem ou um documento de WhatsApp para um número de telefone a partir do seu número de WhatsApp conectado. Use-a para confirmações de pedido, lembretes de pagamento, alertas e respostas de suporte.
https://wbiztool.com/api/v1/send_msg/Corpo: JSON, campos de formulário ou multipart/form-data ao enviar um arquivo
A mensagem entra na fila e é enviada do seu número de WhatsApp em instantes. A resposta traz um msg_id que você pode usar para verificar o status.
Exemplo rápido#
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": "9876543210",
"msg": "Hi Aman, your order #4821 has shipped and will arrive on Thursday."
}'import requests
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": "9876543210",
"msg": "Hi Aman, your order #4821 has shipped and will arrive on Thursday.",
},
timeout=60,
)
result = response.json() # read the body even when the HTTP code is 400
if result.get("status") == 1:
print("Queued with msg_id", result["msg_id"])
else:
print("Failed:", result.get("message"))// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", {
method: "POST",
headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
whatsapp_client: 678,
msg_type: 0,
country_code: "91",
phone: "9876543210",
msg: "Hi Aman, your order #4821 has shipped and will arrive on Thursday.",
}),
});
const result = await response.json(); // read the body even when the HTTP code is 400
if (result.status === 1) {
console.log("Queued with msg_id", result.msg_id);
} else {
console.error("Failed:", result.message);
}<?php
$payload = [
'whatsapp_client' => 678,
'msg_type' => 0,
'country_code' => '91',
'phone' => '9876543210',
'msg' => 'Hi Aman, your order #4821 has shipped and will arrive on Thursday.',
];
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['status'] ?? 0) === 1) {
echo 'Queued with msg_id ' . $result['msg_id'];
} else {
echo 'Failed: ' . ($result['message'] ?? 'no response');
}Substitua YOUR_API_KEY e 678 pela sua própria chave e pelo ID do seu número. Veja em Autenticação onde encontrá-los. A chave vai no cabeçalho Authorization: Bearer (recomendado); client_id e api_key no corpo, como JSON ou campos de formulário, também funcionam – os exemplos mais abaixo usam essa forma.
Parâmetros da requisição#
Autenticação
AuthorizationheaderRecomendadoBearer YOUR_API_KEY: sua chave de API de Configurações → Chaves de API. Com o cabeçalho,client_ideapi_keypodem ficar fora do corpo; se os dois forem enviados, uma chave válida no cabeçalho é a usada. Veja Enviar a chave em um cabeçalho.client_idintegerSem o cabeçalho AuthorizationSeu ID do Cliente da API, em Configurações → Chaves de API. Opcional com o cabeçalho; se você enviar, ele precisa ser o do espaço de trabalho da chave.
api_keystringSem o cabeçalho AuthorizationSua chave de API, na mesma página, quando você não a envia no cabeçalho.
whatsapp_clientintegerObrigatório se você tiver mais de um númeroID do número de WhatsApp ou da conta do Telegram a partir do qual enviar, nas configurações do WhatsApp. Se você não enviar, o único número conectado é usado, WhatsApp primeiro: um único número de WhatsApp conectado é usado mesmo que uma conta do Telegram também esteja conectada, e uma conta do Telegram só quando nenhum número de WhatsApp estiver conectado. Um
@usernameusa a única conta do Telegram conectada.
Destinatário e mensagem
phonestringobrigatórioO número de WhatsApp do destinatário. Espaços,
+,-,., parênteses e um00inicial são removidos automaticamente, então+91 98765-43210funciona. Valores de planilha como919876543210.0e9.19876543210E+11são lidos como os seus dígitos, mas um valor arredondado como9.19877E+11é recusado, porque faltam dígitos. Envie o número com o código do país (919876543210) ou sem ele (9876543210) junto comcountry_code. Um número local escrito com o0inicial também funciona:09876543210comcountry_code91vai para919876543210, e0612345678com39(Itália, onde o0faz parte do número) vai para390612345678. Um número escrito com+ou00já traz o próprio código do país:country_codenão é adicionado a ele, e um(0)entre parênteses depois do código é removido, então+44 (0)20 7946 0018vai para442079460018. De uma conta do Telegram,phonetambém pode ser um@username, um linkt.me/usernameoutg:<id>.country_codestringopcionalCódigo de discagem do país sem
+, por exemplo91para a Índia ou1para os EUA. Ele é adicionado antes dephone, a menos que o número já comece com ele ou esteja escrito com+ou00. Exceção: com91, um número de 10 dígitos sempre recebe o prefixo. Com outros códigos, um número local que comece com os mesmos dígitos não recebe o prefixo, então envie-o já com o código do país.msg_typeintegeropcional0texto (padrão),1imagem,2arquivo ou documento.msgstringObrigatório quando msg_type é 0Texto da mensagem, com até 3.000 caracteres. Para imagens e arquivos, é a legenda e pode ficar vazio. A formatação do WhatsApp funciona:
*bold*,_italic_,~strikethrough~.messageé aceito como alias.
Imagens e arquivos
img_urlstringObrigatório quando msg_type é 1 e nenhum arquivo é enviadoURL pública
httpouhttpsda imagem.file_urlstringObrigatório quando msg_type é 2 e nenhum arquivo é enviadoURL pública
httpouhttpsa partir da qual o arquivo pode ser baixado diretamente.filefileopcionalEnvie a imagem ou o arquivo em vez de informar uma URL. Envie a requisição como
multipart/form-datacom o campo chamadofile.file_namestringopcionalNome do arquivo que o destinatário vê, como
invoice-4821.pdf. A extensão define como o arquivo é enviado, então inclua uma. Ele é enviado em letras minúsculas, caracteres como& : ? * $ ;são substituídos por_, e ele é cortado em 150 caracteres. Se você não enviar, o nome vem da URL ou do arquivo enviado.
Opções de entrega
expire_after_secondsintegeropcionalMarca a mensagem como expirada (status
4) se ela não tiver sido enviada dentro desse número de segundos, por exemplo3600para uma hora. Útil para mensagens com prazo, como previsões de entrega. Um processo em segundo plano faz isso pelo menos 30 segundos depois do prazo, então não conte com isso para prazos menores que um minuto.webhookstringopcionalURL que recebe um
POSTquando a mensagem é enviada, falha, é cancelada ou expira. Veja Webhook.
Enviar imagens e arquivos#
Limites de download para img_url e file_url:
- A URL precisa ser pública:
httpouhttps, acessível pela internet. São seguidos até 5 redirecionamentos, e cada um deles também precisa levar a um endereço público. - Os arquivos por link podem ter até 100 MB. O servidor precisa começar a responder em até 45 segundos e não pode ficar parado por mais tempo que isso.
- O arquivo é baixado quando você chama a API, então um link quebrado falha imediatamente com
Invalid file url.
Arquivos enviados com msg_type 2 mantêm estas extensões:
| Categoria | Extensões |
|---|---|
| Imagens | .jpg, .jpeg, .jpe, .png, .gif, .webp, .bmp |
| Documentos | .pdf, .doc, .docx, .docm, .xls, .xlsx, .xlsm, .xlsb, .ppt, .pptx, .pptm, .txt, .csv |
| Áudio | .mp3, .mpga, .m4a, .aac, .wav, .ogg, .oga |
| Vídeo | .mp4, .mov, .avi, .webm |
| Arquivos compactados | .zip, .rar |
Estas verificações acontecem quando a mensagem é enviada, e não quando você chama a API, então as falhas só aparecem em Status da mensagem e no webhook:
| Problema | error em Status da mensagem |
|---|---|
Uma imagem (msg_type 1) acima de 16 MB | File exceeds WhatsApp size limit (16MB max) |
Um vídeo (.mp4, .webm) acima de 64 MB, também quando enviado como imagem (msg_type 1) | File exceeds WhatsApp size limit (64MB max) |
Qualquer outro arquivo (msg_type 2) acima de 100 MB | File exceeds WhatsApp size limit (100MB max) |
| Um arquivo vazio (0 bytes) | The file is empty |
Um arquivo .wav ou .ogg enviado como imagem (msg_type 1) | File type not supported |
Áudios WAV e OGG não podem ser enviados como imagem (msg_type 1). Enviados como arquivo (msg_type 2), eles chegam como documento com o próprio nome, como recording.wav. Arquivos .mp3, .mpga, .m4a e .aac chegam como áudio que toca na conversa, e msg vem depois como mensagem de texto separada (áudio não tem legenda).
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Content-Type: application/json" \
-d '{
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 1,
"country_code": "91",
"phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg",
"msg": "Our Diwali sale starts today 🎉"
}'import requests
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
json={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 1,
"country_code": "91",
"phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg",
"msg": "Our Diwali sale starts today 🎉",
},
timeout=60,
)
print(response.json())// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: 12345,
api_key: "YOUR_API_KEY",
whatsapp_client: 678,
msg_type: 1,
country_code: "91",
phone: "9876543210",
img_url: "https://example.com/offers/diwali-sale.jpg",
msg: "Our Diwali sale starts today 🎉",
}),
});
console.log(await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'whatsapp_client' => 678,
'msg_type' => 1,
'country_code' => '91',
'phone' => '9876543210',
'img_url' => 'https://example.com/offers/diwali-sale.jpg',
'msg' => 'Our Diwali sale starts today 🎉',
]),
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);
curl_close($ch);curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-F client_id=12345 \
-F api_key=YOUR_API_KEY \
-F whatsapp_client=678 \
-F msg_type=2 \
-F country_code=91 \
-F phone=9876543210 \
-F "msg=Your invoice for order #4821 is attached." \
-F file_name=invoice-4821.pdf \
-F file=@./invoice-4821.pdfimport requests
with open("invoice-4821.pdf", "rb") as f:
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
data={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 2,
"country_code": "91",
"phone": "9876543210",
"msg": "Your invoice for order #4821 is attached.",
"file_name": "invoice-4821.pdf",
},
files={"file": f},
timeout=120,
)
print(response.json())// Node.js 20+ (built-in fetch, FormData and fs.openAsBlob). Save as .mjs to use top-level await.
import { openAsBlob } from "node:fs";
const form = new FormData();
form.append("client_id", "12345");
form.append("api_key", "YOUR_API_KEY");
form.append("whatsapp_client", "678");
form.append("msg_type", "2");
form.append("country_code", "91");
form.append("phone", "9876543210");
form.append("msg", "Your invoice for order #4821 is attached.");
form.append("file_name", "invoice-4821.pdf");
form.append("file", await openAsBlob("./invoice-4821.pdf"), "invoice-4821.pdf");
// Don't set Content-Type yourself; fetch adds the multipart boundary.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", { method: "POST", body: form });
console.log(await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
// An array body (not json_encode) makes cURL send multipart/form-data.
CURLOPT_POSTFIELDS => [
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'whatsapp_client' => 678,
'msg_type' => 2,
'country_code' => '91',
'phone' => '9876543210',
'msg' => 'Your invoice for order #4821 is attached.',
'file_name' => 'invoice-4821.pdf',
'file' => new CURLFile('/path/to/invoice-4821.pdf', 'application/pdf', 'invoice-4821.pdf'),
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
echo curl_exec($ch);
curl_close($ch);Usar os clientes oficiais#
Os clientes para Python e Node.js chamam este endpoint para você.
from wbiztool_client import WbizToolClient
client = WbizToolClient(api_key="YOUR_API_KEY", client_id="12345")
result = client.send_message(
phone="9876543210",
country_code="91",
msg="Hi Aman, your order #4821 has shipped.",
whatsapp_client=678,
)
print(result)Os erros lançam requests.HTTPError. Leia o motivo com e.response.json()["message"].
const { WbizToolClient } = require("wbiztool-client");
const client = new WbizToolClient({
clientId: 12345,
apiKey: "YOUR_API_KEY",
whatsappClient: 678,
});
(async () => {
// Errors throw, with the API's response in the error message.
const result = await client.sendMessage({
phone: "9876543210",
countryCode: "91",
message: "Hi Aman, your order #4821 has shipped.",
});
console.log(result);
})().catch(console.error);Resposta#
Uma requisição bem-sucedida retorna HTTP 200:
{
"status": 1,
"message": "Created",
"msg_id": 9817263
}
| Campo | Tipo | Descrição |
|---|---|---|
status | integer | 1 se a mensagem entrou na fila, 0 se a requisição falhou. |
message | string | Created em caso de sucesso; caso contrário, o erro. |
msg_id | integer | ID da mensagem na fila. Guarde-o para verificar o status depois. Presente apenas em caso de sucesso. |
"status": 1 significa que a mensagem entrou na fila, não que já chegou ao destinatário. Use um webhook ou Status da mensagem para confirmar que ela foi enviada.
Erros#
Os erros retornam HTTP 400 com status igual a 0 (Account Disabled não tem o campo status):
{ "status": 0, "message": "Msg cant be null" }
| Mensagem | Como corrigir |
|---|---|
Auth Error - Please send correct API key and Client id | Envie uma api_key não vazia. |
Invalid client id. | Envie client_id como número. |
Auth Error: invalid api key | Verifique se a chave existe, não foi excluída e pertence a este client_id. |
Either phone or group_name parameter is required | Adicione phone. |
Please provide either phone OR group_name, not both | Remova um dos dois. |
Invalid phone number | phone deve ser um número de 6 a 17 dígitos. Letras e outros símbolos não são permitidos, nem um valor de planilha arredondado como 9.19877E+11. |
Invalid Contact Number "…" | Com o código do país incluído, o número deve ter de 7 a 15 dígitos. |
Msg cant be null | Mensagens de texto (msg_type 0) precisam de msg. |
Message length is too long | Limite msg a 3.000 caracteres ou menos. |
Image Url Can't be null | Para msg_type 1, envie img_url ou faça upload de um file. |
File Url Can't be null | Para msg_type 2, envie file_url ou faça upload de um file. |
Invalid file url, Can't download / Invalid file url | A URL não é pública, o download excedeu o tempo limite ou o arquivo tem mais de 100 MB. |
Invalid whatsapp client | Esse ID de whatsapp_client não está no seu espaço de trabalho. |
Invalid whatsapp client id. | Envie whatsapp_client. Ele é obrigatório quando seu espaço de trabalho tem mais de um número conectado. |
Telegram usernames can only be sent to from a Telegram account: pass its id as whatsapp_client | Um @username, um link t.me ou tg:<id> em phone precisa de uma conta do Telegram como whatsapp_client. |
Not enough credits | O espaço de trabalho está no plano gratuito e não tem mais mensagens: os planos pagos enviam mensagens ilimitadas. Veja Quando as mensagens acabam. |
Daily limit reached: a number can send 1,000 messages in 24 hours (fair use). Send the rest tomorrow. (HTTP 429, "code": "daily_limit_reached") | Este número já aceitou 1.000 mensagens nas últimas 24 horas (uso justo). A resposta ainda traz o msg_id da mensagem recusada, que aparece com falha. Envie o restante mais tarde ou de outro número. |
Demo Account can not access apis | Use uma conta normal. |
Account Disabled | Sua conta está desativada. Fale com o suporte. |
Invalid JSON format: … | O corpo JSON não é válido, geralmente por causa de uma vírgula sobrando no final ou de uma quebra de linha sem escape em msg. Use \n para novas linhas. |
Uma mensagem na fila ainda pode falhar no envio, por exemplo com File exceeds WhatsApp size limit (…). Esses erros nunca aparecem nesta resposta. Veja Enviar imagens e arquivos e confira Status da mensagem.
Webhook#
Se você informar webhook, o WbizTool envia um POST para essa URL quando a mensagem é enviada ou falha, e também quando ela é cancelada ou expira antes de ser enviada. O corpo é codificado como formulário (application/x-www-form-urlencoded), não como JSON:
msg_id=9817263&status=SENT
| Campo | Valores |
|---|---|
msg_id | O msg_id retornado quando você enviou a mensagem. |
status | SENT, FAILED, CANCELLED (cancelada antes de ser enviada: com Cancelar mensagem, pelo painel, ou pela remoção do número de WhatsApp ou da campanha dela) ou EXPIRED (não foi enviada antes de acabar o prazo de expire_after_seconds) |
Cada webhook é assinado: os cabeçalhos WbizTool-Timestamp e WbizTool-Signature (v1= e um HMAC-SHA256 de <timestamp>.<raw body> com o segredo de assinatura do seu espaço de trabalho) permitem verificar que ele veio do WbizTool. Veja como obter o segredo e a verificação em Python e Node.js em Assinaturas de webhook; receptores que ignoram os cabeçalhos continuam funcionando.
Responda com qualquer código 2xx; um redirecionamento é seguido, no máximo 3 vezes. Se o seu endpoint não responder em 10 segundos, não puder ser alcançado ou retornar 429 ou 5xx, o WbizTool tenta de novo após 30 segundos, 1 minuto e 2 minutos (4 tentativas no total). Outras respostas 4xx não são repetidas. A URL deve ser um endereço público da internet: um webhook para um endereço privado ou local (como 192.168.x.x ou localhost) não é enviado.
Dicas#
- Números de telefone: armazene os números em formato internacional e envie-os com
country_codepara evitar ambiguidades. - Novas linhas em JSON: escreva-as como
\ndentro demsg. Uma quebra de linha literal deixa o JSON inválido. - Mantenha seu número conectado: as mensagens são enviadas do seu número de WhatsApp, então ele precisa continuar conectado nas configurações do WhatsApp.
- Muitos destinatários: para enviar a mesma mensagem para vários números em uma única requisição, use Enviar para vários números. Para campanhas grandes, envie uma planilha pela página Campanhas.
