API de mensajería
API para enviar a varios números
Envía el mismo mensaje de WhatsApp a varios números de teléfono y grupos en una sola solicitud. Úsala para difusiones pequeñas, como boletines, ofertas y anuncios.
https://wbiztool.com/api/v1/send_msg/multi/Cuerpo: JSON o campos de formulario
WbizTool crea un mensaje por destinatario y devuelve un msg_id para cada uno, así que puedes consultar su estado por separado.
Ejemplo rápido#
curl -X POST https://wbiztool.com/api/v1/send_msg/multi/ \
-H "Content-Type: application/json" \
-d '{
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": "9876543210,9812345670,Sales Team Mumbai",
"msg": "Our Diwali sale starts tomorrow. Get 20% off on all orders!"
}'import requests
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/multi/",
json={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": ",".join(["9876543210", "9812345670", "Sales Team Mumbai"]),
"msg": "Our Diwali sale starts tomorrow. Get 20% off on all orders!",
},
timeout=60,
)
result = response.json() # read the body even when the HTTP code is 400
if result.get("status") == 1:
for item in result["messages"]:
print(item["contact"], "->", item["msg_id"])
else:
print("Failed:", result.get("message", "no message in response"))// 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/multi/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: 12345,
api_key: "YOUR_API_KEY",
whatsapp_client: 678,
msg_type: 0,
country_code: "91",
phone: ["9876543210", "9812345670", "Sales Team Mumbai"].join(","),
msg: "Our Diwali sale starts tomorrow. Get 20% off on all orders!",
}),
});
const result = await response.json(); // read the body even when the HTTP code is 400
if (result.status === 1) {
for (const item of result.messages) {
console.log(item.contact, "->", item.msg_id);
}
} else {
console.error("Failed:", result.message ?? "no message in response");
}<?php
$payload = [
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'whatsapp_client' => 678,
'msg_type' => 0,
'country_code' => '91',
'phone' => implode(',', ['9876543210', '9812345670', 'Sales Team Mumbai']),
'msg' => 'Our Diwali sale starts tomorrow. Get 20% off on all orders!',
];
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/multi/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['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) {
foreach ($result['messages'] as $item) {
echo $item['contact'] . ' -> ' . $item['msg_id'] . PHP_EOL;
}
} else {
echo 'Failed: ' . ($result['message'] ?? 'no message in response');
}Sustituye 12345, YOUR_API_KEY y 678 por tus propios valores. Consulta Autenticación para saber dónde encontrarlos.
Parámetros de la solicitud#
Autenticación
client_idintegerobligatorioTu ID de cliente de la API, de Configuración → Claves API.
api_keystringobligatorioTu clave API, de esa misma página.
whatsapp_clientintegerobligatorioID del número de WhatsApp o de la cuenta de Telegram desde la que se envía, de la configuración de WhatsApp. A diferencia de Enviar mensaje, este endpoint nunca elige un número por ti.
Destinatarios y mensaje
phonestringobligatorioNúmeros de teléfono y nombres de grupo en una sola cadena separada por comas, por ejemplo
9876543210,9812345670,Sales Team Mumbai. No envíes un array JSON. Consulta Cómo se leen los destinatarios.country_codestringopcionalCódigo telefónico del país sin
+, por ejemplo91. Se añade delante de cada número de teléfono, salvo que el número ya empiece por él o esté escrito con+o00. En JSON, funcionan tanto una cadena ("91") como un número (91).msg_typeintegeropcional0texto (predeterminado),1imagen,2archivo o documento.msgstringObligatorio cuando msg_type es 0Texto del mensaje. En imágenes y archivos es el pie de foto y puede estar vacío. El formato de WhatsApp funciona:
*bold*,_italic_,~strikethrough~. También se aceptamessagecomo alias.
Imágenes y archivos
img_urlstringObligatorio cuando msg_type es 1URL pública
httpohttpsde la imagen.file_urlstringObligatorio cuando msg_type es 2URL pública
httpohttpsdesde la que se puede descargar el archivo directamente.file_namestringopcionalNombre de archivo que ven los destinatarios, como
price-list.pdf. Se envía en minúsculas, los caracteres como& : ? * $ ;se reemplazan por_y se recorta a 150 caracteres. Si lo omites, el nombre se toma de la URL.
Opciones de entrega
webhookstringopcionalURL que recibe un
POSTpor cada mensaje cuando se envía, falla, se cancela o caduca. El contenido es el mismo que en Enviar mensaje.
curl -X POST https://wbiztool.com/api/v1/send_msg/multi/ \
-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,9812345670",
"img_url": "https://example.com/offers/diwali-sale.jpg",
"msg": "Our Diwali sale starts tomorrow."
}'Cómo se leen los destinatarios#
WbizTool divide phone por las comas, quita los espacios alrededor de cada elemento y luego decide qué es cada elemento:
- Los números de teléfono se pueden escribir tal como los tengas:
+91 98765 43210,98765-43210,(987) 654-3210,0091 98765 43210y+44 (0)20 7946 0018funcionan, igual que los valores de hoja de cálculo como919876543210.0y9.19876543210E+11. country_codese añade salvo que el número ya empiece por él o esté escrito con+o00:+44 20 7946 0018concountry_code91se queda en442079460018. Así, una lista puede mezclar países: escribe con+los números de los demás países.- Un número local escrito con su
0inicial también funciona:09876543210concountry_code91va a919876543210, y0612345678con39(Italia, donde el0forma parte del número) va a390612345678. - Con el código de país añadido, un número debe tener entre 7 y 15 dígitos.
- Un texto con letras u otros símbolos, como
Sales Team MumbaioFamily 2024, se trata como nombre de un grupo de WhatsApp, que se busca igual que en Enviar a un grupo. - Un nombre de grupo sin letras, como
2024-2025, se lee como número de teléfono, salvo que tenga menos de 10 dígitos y tu espacio de trabajo ya haya enviado un mensaje a un grupo con exactamente ese nombre (aparece en Grupos en Contactos). Uno corto, con menos de 7 dígitos y un guion, un punto o paréntesis, como2024-25o(2024), siempre es un nombre de grupo. Los nombres de grupo que contienen comas no se pueden enviar desde este endpoint. Usa Enviar a un grupo para esos casos. - Desde una cuenta de Telegram, un
@username, un enlacet.me/usernameotg:<id>es una persona, no un nombre de grupo, y un número de teléfono va a esa persona en Telegram. Desde un número de WhatsApp, los nombres de usuario, los enlacest.meytg:<id>se omiten.
Otras cosas que debes saber:
- Los números demasiado cortos o demasiado largos tras añadir el código de país, los valores de hoja de cálculo redondeados y los elementos que solo son ceros (
0,00) se omiten sin avisar. No aparecen en la respuesta y no reciben unmsg_id. - Los duplicados no se eliminan. Un número que aparece dos veces recibe dos mensajes.
- Si un número local empieza por los mismos dígitos que
country_code(por ejemplo9123456780concountry_code91), el código no se añade. Envía esos números con el código de país ya incluido (919123456780). - Las URL de imágenes y archivos no se comprueban cuando llamas a la API. Se descargan al enviar cada mensaje, así que un enlace roto hace que fallen los mensajes más tarde, no la solicitud. Se aplican las mismas reglas de envío que en Enviar mensaje: fallan las imágenes de más de 16 MB y los videos de más de 64 MB, el audio WAV y OGG no se puede enviar como imagen (
msg_type1), y a los archivos (msg_type2) sin extensión o con una que no se admite se les añade.pdf. Consulta Enviar imágenes y archivos.
Límites de mensajes#
Todo el lote se comprueba antes de crear nada, así que una lista nunca se envía a medias. Cuenta cada elemento no vacío de phone, incluidos los que después se omiten, y también cuentan los mensajes en cola que aún no se han enviado.
- Todos los planes: el lote tiene que caber en el límite diario de uso justo del número de envío: 1.000 mensajes en cualquier periodo de 24 horas. Si no, no se crea ningún mensaje y recibes:
{
"message": "Daily limit reached: a number can send 1,000 messages in 24 hours (fair use). Send the rest tomorrow. 1200 messages requested, 640 more can go out from this number in the next 24 hours.",
"code": "daily_limit_reached",
"status": 0
}
- Plan gratuito: el lote también tiene que caber en los mensajes gratis que le quedan al espacio de trabajo (50 en cualquier periodo de 30 días). Si no, recibes:
{
"message": "Not enough credits: 120 messages requested, 35 credits remaining",
"status": 0
}
Reparte las listas grandes entre varios números o días. Para campañas grandes, sube en su lugar una hoja de cálculo desde la página de Campañas.
Respuesta#
Una solicitud correcta devuelve HTTP 200:
{
"msg_ids": [9817263, 9817264, 9817265],
"messages": [
{ "msg_id": 9817263, "contact": "919876543210", "is_group": false },
{ "msg_id": 9817264, "contact": "919812345670", "is_group": false },
{ "msg_id": 9817265, "contact": "Sales Team Mumbai", "is_group": true }
],
"message": "Successfully created 3 messages",
"status": 1
}
| Campo | Tipo | Descripción |
|---|---|---|
status | integer | 1 si se puso en cola al menos un mensaje, 0 en caso contrario. |
message | string | Successfully created N messages si todo va bien; en caso contrario, el error. |
msg_ids | array of integers | IDs de los mensajes en cola, en el orden de phone. Solo aparece si la solicitud es correcta. |
messages | array | Un objeto por cada mensaje en cola. Solo aparece si la solicitud es correcta. |
messages[].msg_id | integer | ID del mensaje. |
messages[].contact | string | El número de teléfono con el código de país aplicado, o el nombre del grupo. |
messages[].is_group | boolean | true si el elemento se trató como nombre de grupo. |
Compara messages con la lista que enviaste para detectar los números omitidos, y comprueba que is_group sea false en cada elemento que querías que fuera un número de teléfono.
Errores#
La mayoría de los errores devuelven HTTP 200 con status con valor 0, así que revisa siempre status en el cuerpo. Salvo en los errores HTTP 400 y 403, las respuestas (incluidas las correctas) son JSON enviado con Content-Type: text/html, así que procesa el cuerpo tú mismo en lugar de confiar en la detección automática de JSON (por ejemplo, en herramientas sin código):
{ "message": "Invalid whatsapp client", "status": 0 }
| Mensaje | Cómo solucionarlo |
|---|---|
Auth Error | Envía client_id y api_key. |
Invalid Client Id | Envía client_id como número. Se devuelve con HTTP 403. |
Auth Error: invalid api key | Comprueba que la clave existe, que no se ha eliminado y que pertenece a este client_id. Se devuelve con HTTP 400. |
Msg cant be null | Los mensajes de texto (msg_type 0) necesitan msg. |
Image Url Can't be null | Para msg_type 1, envía img_url. |
File Url Can't be null | Para msg_type 2, envía file_url. |
Not enough credits: … messages requested, … credits remaining | Los mensajes del plan gratuito no cubren la lista. Envía menos destinatarios o elige un plan. Consulta Límites de mensajes. |
Daily limit reached: … messages requested, … more can go out from this number in the next 24 hours. | Reparte la lista entre varios días o números. Consulta Límites de mensajes. |
Invalid whatsapp client | Ese ID de whatsapp_client no está en tu espacio de trabajo. |
No valid contacts found | Todos los elementos de phone estaban vacíos o se omitieron. Comprueba que los números tengan entre 7 y 15 dígitos con el código de país. |
Demo Account can not access apis | Usa una cuenta normal. |
Invalid JSON format: … | El cuerpo JSON no es válido, o enviaste campos de formulario sin client_id. |
Consejos#
- Envía
phonecomo cadena: une tu lista con comas. Un array JSON devuelve{}. - Por ahora no uses
send_bulk_messagesdel cliente de Python: envía la lista comophones, que este endpoint ignora. Llama al endpoint directamente como en los ejemplos anteriores. - Haz seguimiento de cada mensaje: guarda cada
msg_iddemessages, o pasa unwebhookpara recibir un aviso cuando cada uno se envíe, falle, se cancele o caduque. - Mantén tu número conectado: cada mensaje se envía desde tu número de WhatsApp, así que debe seguir conectado en la configuración de WhatsApp hasta que salga todo el lote.
- Texto distinto para cada persona: este endpoint envía el mismo
msga todos. Llama a Enviar mensaje una vez por destinatario para personalizar cada mensaje.
