API v2 (beta)
API v2
La API v2 es la nueva API REST de WbizTool: una clave por app con solo el acceso que necesita, URLs orientadas a recursos, códigos de estado HTTP reales, webhooks JSON firmados y reintentos seguros. Esta página explica lo que tienen en común todas las solicitudes. Las páginas de recursos describen cada endpoint.
URL base#
https://wbiztool.com/api/v2
Las rutas no llevan barra final (/api/v2/messages), aunque también se acepta. Una dirección que no existe responde 404 con el código not_found.
Ejemplo rápido#
Comprueba tu clave con GET /me. Funciona con cualquier permiso y no envía nada:
curl https://wbiztool.com/api/v2/me \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"import os
import requests
response = requests.get(
"https://wbiztool.com/api/v2/me",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json())// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/me", {
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
console.log(response.status, await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v2/me');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), "\n";
print_r($body);
curl_close($ch);{
"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 es null cuando el plan envía mensajes ilimitados. plan es null cuando el espacio de trabajo no tiene un plan activo.
Claves#
Envía tu clave en la cabecera Authorization en cada solicitud:
Authorization: Bearer wbz_live_…
No hay client_id: la clave indica su espacio de trabajo. Una clave v2 empieza por wbz_live_ o wbz_test_, seguida de 38 letras y dígitos. Las claves v1 no funcionan en v2 (reciben v1_key_on_v2), y las claves v2 no funcionan en v1.
Crear una clave#
Los Propietarios crean claves en Configuración → Claves API, en la tarjeta Claves API v2: haz clic en Crear clave v2 y elige:
- Nombre: la app que la usará, hasta 50 caracteres.
- Tipo de clave: Real envía mensajes de verdad; Prueba lo comprueba todo y no envía nada (consulta Modo de prueba).
- Qué puede hacer: los permisos, o Todo.
- Números que puede usar: todos los números, incluidos los que se añadan después, o solo algunos (consulta Claves limitadas a algunos números).
- Caduca: nunca, o en 30 días, 90 días o 1 año.
La clave se muestra una sola vez. Cópiala enseguida y guárdala en tu servidor, por ejemplo en una variable de entorno. WbizTool solo guarda un hash de la clave y sus cuatro últimos caracteres, así que una clave perdida no se puede volver a mostrar: revócala y crea otra.
Un espacio de trabajo puede tener hasta 10 claves v2 sin revocar. La tarjeta muestra de cada clave sus cuatro últimos caracteres, sus permisos, sus números, su caducidad, y cuándo y desde qué dirección IP se usó por última vez. Revocar detiene una clave al instante y, con ella, los endpoints de webhook que creó. Una clave que pasó su fecha de caducidad recibe api_key_expired.
Permisos#
Cada clave solo puede hacer lo que permiten sus permisos. Una solicitud fuera de ellos responde 403 con missing_scope, y required_scope en el error indica cuál necesita.
| Permiso | Qué permite |
|---|---|
messages:send | Enviar mensajes y lotes, y cancelar mensajes en espera: POST /messages, POST /messages/batch, DELETE /messages/{id} |
messages:read | Leer mensajes y su estado (GET /messages, GET /messages/{id}), y gestionar endpoints de webhook |
reminders | Crear, listar, cambiar, pausar y eliminar recordatorios |
numbers | Listar números, ver su conexión y conectar números de WhatsApp |
media | Subir, listar y eliminar archivos del Directorio de medios |
contacts | Verificaciones de números (los endpoints de contactos llegarán más adelante) |
GET /me no necesita ningún permiso en particular. Enviar a un contacto guardado con to.contact_id solo necesita messages:send.
Claves limitadas a algunos números#
Una clave limitada a algunos números solo funciona con ellos:
- Solo envía desde esos números, y solo lista, lee y cancela sus mensajes. Otro número en
fromrecibenumber_not_allowed. GET /numberslista solo esos números. Puede volver a conectarlos, pero no puede añadir un número nuevo.- Solo ve y cambia los recordatorios que se envían desde esos números, y un recordatorio nuevo debe indicar uno de ellos como
from. - No puede gestionar endpoints de webhook en absoluto, porque reciben los eventos de todo el espacio de trabajo.
GET /me muestra limited_to_numbers y los number_ids que la clave puede usar.
Solicitudes#
- JSON de entrada y de salida. Envía los cuerpos como
Content-Type: application/json. La única excepción es subir un archivo, que esmultipart/form-data. Todas las respuestas son JSON, también los errores. - Los nombres de los campos están en
snake_case, y los campos desconocidos se rechazan: un error de escritura comotxtrespondevalidation_faileden lugar de ignorarse. - Los números de teléfono van en formato internacional con
+(E.164), por ejemplo+919876543210. Se permiten espacios y guiones; un número sin+se rechaza coninvalid_phone. - Las horas van en ISO 8601 con desfase horario, por ejemplo
2026-10-20T09:30:00+05:30o2026-10-20T04:00:00Z. Una hora sin desfase se rechaza coninvalid_datetime. Las horas de las respuestas están en UTC y terminan enZ, excepto elnext_run_atde un recordatorio, que está en la zona horaria del recordatorio. - Los IDs son números enteros, como el
idde un número (fromcuando envías) o elidde un mensaje. - Los códigos de estado significan lo que dicen:
200correcto,201creado,202aceptado (en cola),400la solicitud es incorrecta,401la clave es incorrecta,402no quedan mensajes,403no permitido,404no encontrado,409conflicto,413demasiado grande,415tipo de contenido incorrecto,422un valor no se puede usar,429demasiadas solicitudes,5xxproblema de nuestro lado.
Las respuestas llevan Cache-Control: no-store.
Errores#
Todos los errores tienen el mismo 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"
}
}
codees estable: usa este campo para decidir qué hacer en tu código.messagees un texto en inglés para el desarrollador y puede cambiar.fieldindica el campo al que se refiere el error (to.phone,to[3].phone,schedule.cron), o esnull.docsenlaza al código en la página de errores.request_ides igual que la cabeceraX-Request-Id. Indícalo si te pones en contacto con nosotros.- Algunos errores añaden detalles, por ejemplo
statusennot_cancellableousedylimitenstorage_full. Cuando una solicitud tiene varios problemas,errorslista los demás, cada uno confieldymessage.
Todos los códigos, su estado HTTP y qué hacer están en la página de errores.
Idempotency-Key#
Un error de red o un tiempo de espera agotado te deja sin saber si una solicitud funcionó. Envía una cabecera Idempotency-Key con un POST que crea algo y podrás volver a enviarlo sin riesgo:
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."}'
- El valor lo eliges tú: cualquier cadena única de 1 a 255 caracteres imprimibles, como un UUID o tu propio ID de pedido. Crea uno nuevo para cada solicitud nueva y reutilízalo solo para reintentar la misma solicitud.
- Un reintento recibe la primera respuesta con la cabecera
Idempotent-Replayed: true. Nada se hace dos veces: ni un segundo mensaje, ni un segundo recordatorio, archivo o endpoint. - Los valores duran 24 horas desde la primera solicitud y pertenecen a tu clave API: otra clave API del espacio de trabajo puede usar el mismo valor sin conflicto.
- Mismo valor, otra solicitud: una solicitud con un valor ya usado para otro método, otra ruta u otro cuerpo responde
422idempotency_key_reused. - Aún en curso: mientras la primera solicitud con ese valor todavía se está procesando, un reintento responde
409idempotency_in_progressconRetry-After: 1. Espera un momento y vuelve a enviarla. - Los errores no se guardan. Si la primera solicitud respondió con un error, no se guarda nada: corrige la solicitud y vuelve a enviarla con el mismo valor.
- Los secretos no se repiten. Una repetición de
POST /webhooksomite elsecretdel endpoint, que solo se muestra en la primera respuesta.
Funciona en POST /messages, POST /messages/batch, POST /numbers, POST /reminders, POST /media, POST /number-checks y POST /webhooks, y en todos es opcional. Las demás solicitudes ignoran la cabecera. Un valor vacío o demasiado largo responde 400 invalid_idempotency_key.
Límites de solicitudes#
Cada clave puede hacer 60 solicitudes por minuto y 10.000 solicitudes al día. Son ventanas fijas: la ventana de un minuto empieza al inicio de cada minuto del reloj, y la de un día a las 00:00 UTC. Por encima de un límite, la solicitud responde 429 rate_limited.
Las respuestas a solicitudes con una clave válida llevan estas cabeceras:
| Cabecera | Significado |
|---|---|
RateLimit-Limit | Solicitudes permitidas en la ventana actual (60, o 10000 una vez alcanzado el límite diario) |
RateLimit-Remaining | Solicitudes que quedan en esa ventana |
RateLimit-Reset | Segundos hasta que esa ventana vuelva a empezar |
RateLimit-Policy | Ambos límites: 60;w=60, 10000;w=86400 |
Retry-After | En un 429: segundos que debes esperar antes de volver a intentarlo |
Aparte de estos:
- Claves incorrectas: más de 30 solicitudes por minuto con una clave incorrecta desde una misma dirección IP responden
429too_many_auth_failuresconRetry-After: 60. - Mensajes por número: un número envía como máximo 1.000 mensajes en 24 horas (uso justo). Un envío por encima de ese límite responde
429number_daily_cap_reached.
Paginación#
Las listas que pueden crecer (GET /messages, /reminders, /media, /number-checks y los /results de una verificación) llegan en páginas, primero lo más reciente:
{
"data": [ … ],
"next_cursor": "eyJpZCI6OTgxNzI2MywidCI6IjIwMjYtMTAtMThUMTA6MTU6MDIuMzExWiIsImYiOiI0NGIxMzZmYTM1NWIifQ"
}
limitfija el tamaño de la página, de 1 a 100 (25 por defecto).- Para obtener la página siguiente, envía la misma solicitud con
cursorigual alnext_cursorde la última página.next_cursoresnullen la última página. - Mantén iguales los demás filtros: un cursor usado con otros filtros responde
400invalid_cursor. Vuelve a empezar sin cursor. - Trata el cursor como una cadena opaca. Los elementos que se añaden mientras recorres las páginas no las desplazan.
curl "https://wbiztool.com/api/v2/messages?limit=100&cursor=eyJpZCI6OTgxNzI2MywidCI6..." \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
GET /numbers y GET /webhooks devuelven todo en una sola lista data.
IDs de solicitud#
Todas las respuestas, también los errores, llevan una cabecera X-Request-Id como req_4f1c2a9b8e7d6c5b4a392817. Los errores llevan el mismo valor como request_id. Regístralo en tus logs e indícalo si te pones en contacto con nosotros: nos permite encontrar la solicitud en nuestros registros, que guardan el ID de tu clave, pero nunca la clave.
Si envías tu propio X-Request-Id (hasta 100 caracteres imprimibles), vuelve como X-Client-Request-Id, para que puedas relacionar las respuestas con tus propios logs.
Modo de prueba#
Una clave de prueba (wbz_test_…) te permite crear y probar una integración sin enviar nada. Créala en Configuración → Claves API con Tipo de clave: Prueba. GET /me muestra "mode": "test".
Lo que una clave de prueba hace igual que una clave real:
POST /messagesyPOST /messages/batchcomprueban todo lo que comprueba un envío real: el destinatario, el texto, los medios,send_atyexpires_at, el número que envía, y los permisos y números de la clave. Los mismos fallos reciben los mismos errores.- Los permisos, los números, los límites de solicitudes y
Idempotency-Keyfuncionan igual. - Cada lectura del resto del espacio de trabajo (
GET /me,/numbers,/reminders,/media,/number-checks,/webhooks) muestra sus datos reales, solo en lectura.
Lo que cambia:
- No se envía nada. Un envío de prueba se guarda como mensaje de prueba y no usa los mensajes del plan ni los 1.000 diarios del número, así que nunca recibe
no_creditsninumber_daily_cap_reached. - Su estado avanza solo:
queued, luegosent5 segundos después ydelivered15 segundos después de crearse (contados desdesend_atsi está programado). Un mensaje cuyoexpires_atllega antes de que se envíe pasa aexpired. Los mensajes de prueba nunca pasan areadni afailed. - Una clave de prueba solo ve sus propios mensajes de prueba.
GET /messagesyGET /messages/{id}los muestran y nada más, yDELETE /messages/{id}cancela uno mientras estáqueuedoscheduled. Las claves reales nunca ven los mensajes de prueba. El filtrostatusdeGET /messagesno se admite con claves de prueba y respondetest_mode_unsupported;number,sinceyuntilfuncionan. - Las demás escrituras se rechazan con
403test_mode_unsupported: conectar un número; crear, cambiar o eliminar recordatorios; subir o eliminar medios; iniciar una verificación de números; y añadir, quitar, rotar o probar endpoints de webhook. - No se envían eventos de webhook para los mensajes de prueba.
- Los mensajes de prueba se guardan durante 30 días.
Recursos#
- Mensajes: envía ahora o más tarde, envía a hasta 1.000 destinatarios, lee el historial, cancela.
- Números: lista tus números de WhatsApp y cuentas de Telegram, y conecta un número de WhatsApp con código QR o código de vinculación.
- Recordatorios: mensajes que se repiten según una programación cron.
- Medios: sube los archivos una vez y envíalos por
media_id. - Verificaciones de números: averigua qué números tienen WhatsApp.
- Webhooks: eventos firmados cuando un mensaje se envía, falla, se cancela o caduca.
- Errores: todos los códigos de error.
- Pasar de v1 a v2: cada endpoint y campo de v1, y su equivalente en v2.
