API v2 (beta)
Recordatorios
Un recordatorio envía el mismo mensaje a un destinatario una y otra vez según una programación: el alquiler cada mes, una clase cada lunes, un informe cada tarde. La programación es una expresión cron de 5 partes en la zona horaria que elijas. Los recordatorios creados con la API son los mismos que los de la página Recordatorios del panel.
| Operación | Endpoint | Permiso |
|---|---|---|
| Crear un recordatorio | POST /api/v2/reminders | reminders |
| Listar recordatorios | GET /api/v2/reminders | reminders |
| Obtener un recordatorio | GET /api/v2/reminders/{id} | reminders |
| Cambiar, pausar o reanudar | PATCH /api/v2/reminders/{id} | reminders |
| Eliminar un recordatorio | DELETE /api/v2/reminders/{id} | reminders |
Crear y cambiar recordatorios requiere un plan que incluya recordatorios; si no, la respuesta es 403 plan_required. Listar, leer, pausar y eliminar funcionan en cualquier plan. Para un mensaje que sale una sola vez a una hora fija, usa en su lugar send_at en Enviar un mensaje.
Crear un recordatorio#
https://wbiztool.com/api/v2/remindersCuerpo: JSON (application/json)
curl -X POST https://wbiztool.com/api/v2/reminders \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: rent-flat-4b" \
-d '{
"name": "Weekly rent",
"from": 101,
"to": { "phone": "+919876543210" },
"text": "Hi, a reminder that the rent is due on Friday.",
"schedule": { "cron": "0 9 * * 1", "timezone": "Asia/Kolkata" }
}'import os
import requests
response = requests.post(
"https://wbiztool.com/api/v2/reminders",
headers={
"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}",
"Idempotency-Key": "rent-flat-4b",
},
json={
"name": "Weekly rent",
"from": 101,
"to": {"phone": "+919876543210"},
"text": "Hi, a reminder that the rent is due on Friday.",
"schedule": {"cron": "0 9 * * 1", "timezone": "Asia/Kolkata"},
},
timeout=30,
)
reminder = response.json()
print(response.status_code, reminder.get("id"), reminder.get("next_run_at"))// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/reminders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "rent-flat-4b",
},
body: JSON.stringify({
name: "Weekly rent",
from: 101,
to: { phone: "+919876543210" },
text: "Hi, a reminder that the rent is due on Friday.",
schedule: { cron: "0 9 * * 1", timezone: "Asia/Kolkata" },
}),
});
const reminder = await response.json();
console.log(response.status, reminder.id, reminder.next_run_at);<?php
$ch = curl_init('https://wbiztool.com/api/v2/reminders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: rent-flat-4b',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Weekly rent',
'from' => 101,
'to' => ['phone' => '+919876543210'],
'text' => 'Hi, a reminder that the rent is due on Friday.',
'schedule' => ['cron' => '0 9 * * 1', 'timezone' => 'Asia/Kolkata'],
]),
CURLOPT_RETURNTRANSFER => true,
]);
$reminder = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $reminder['id'] . ' next: ' . $reminder['next_run_at'];Respuesta (201):
{
"id": 812,
"name": "Weekly rent",
"active": true,
"to": { "phone": "+919876543210" },
"from": 101,
"text": "Hi, a reminder that the rent is due on Friday.",
"media": null,
"schedule": { "cron": "0 9 * * 1", "timezone": "Asia/Kolkata" },
"next_run_at": "2026-10-19T09:00:00+05:30",
"created_at": "2026-10-18T10:20:11.004Z"
}
Cuerpo
namestringobligatorioUn nombre para el recordatorio, de hasta 100 caracteres, tal como aparece en la página Recordatorios.
toobjectobligatorioExactamente uno de
phone(formato internacional con+),group(el nombre exacto de un grupo de WhatsApp),contact_idousername(Telegram), como en Mensajes → Destinatarios.frominteger or nullObligatorio con una clave limitada a algunos númerosEl
iddel número que lo envía. Debe estar conectado cuando lo indicas. Si se omite o esnull, lo envía cualquier número conectado del espacio de trabajo.textstringobligatorioEl mensaje, de hasta 3.000 caracteres. También es el pie de foto cuando se envía
media.mediaobject or nullopcionalUna imagen o un archivo para enviar cada vez:
urlomedia_id, y opcionalmentetype, como en Mensajes → Medios.scheduleobjectobligatoriocron(obligatorio) ytimezone. Consulta Programación.activebooleanopcionaltrue(predeterminado) lo activa;falselo crea en pausa.
Programación#
schedule.cron tiene cinco partes separadas por espacios: minuto, hora, día del mes, mes y día de la semana. * significa "cada". Debe ser una programación que se ejecute en algún momento (no el 31 de febrero).
cron | Se ejecuta |
|---|---|
0 9 * * 1 | Los lunes a las 09:00 |
30 18 * * * | Todos los días a las 18:30 |
0 10 1 * * | El día 1 de cada mes a las 10:00 |
0 9 * * 1-5 | De lunes a viernes a las 09:00 |
0 8,20 * * * | Todos los días a las 08:00 y a las 20:00 |
0 9 15 1 * | El 15 de enero a las 09:00, cada año |
schedule.timezone es el nombre de una zona horaria IANA, como Asia/Kolkata, Europe/London o America/New_York (predeterminado UTC). Las horas del cron están en esa zona, y next_run_at también se da en ella, con su desfase. Consulta la referencia de zonas horarias.
Cada ejecución envía un mensaje como cualquier otro: necesita que queden mensajes en el plan y aparece en Listar mensajes.
Errores al crear#
| HTTP | Código | Cuándo |
|---|---|---|
400 | validation_failed | Falta un campo obligatorio o está vacío, un campo es desconocido o demasiado largo (name, to.group), o media no es válido |
400 | text_required | text está vacío |
400 | text_too_long | text tiene más de 3.000 caracteres |
400 | invalid_cron | schedule.cron no tiene 5 partes o nunca se ejecuta |
400 | invalid_timezone | schedule.timezone no es una zona horaria IANA |
403 | plan_required | El plan no incluye recordatorios |
403 | number_not_allowed | La clave está limitada a algunos números y from no es uno de ellos, o falta |
422 | invalid_phone | to.phone no es un número válido en formato internacional con + |
422 | invalid_username | to.username no es un nombre de usuario de Telegram, un enlace ni un id tg: |
422 | username_needs_telegram | Un nombre de usuario de Telegram, pero from no es una cuenta de Telegram (o, sin from, no hay ninguna cuenta de Telegram conectada) |
422 | contact_not_found | No hay ningún contacto con ese to.contact_id |
422 | media_not_found | No hay ningún archivo con ese media.media_id |
422 | invalid_media_url | media.url no es un enlace público http(s) |
422 | number_not_connected | from no es un número conectado de este espacio de trabajo |
Listar recordatorios#
https://wbiztool.com/api/v2/remindersLos recordatorios del espacio de trabajo, del más reciente al más antiguo, en páginas (limit de 1 a 100, predeterminado 25, y cursor). Se incluyen los que están en pausa, con "active": false. Una clave limitada a algunos números solo ve los recordatorios que se envían desde ellos.
curl "https://wbiztool.com/api/v2/reminders?limit=50" \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
La respuesta es {"data": [Reminder, …], "next_cursor": "…" or null}.
Obtener un recordatorio#
https://wbiztool.com/api/v2/reminders/{id}curl https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
Un recordatorio que no existe, que se eliminó o que se envía desde un número que la clave no puede usar responde 404 reminder_not_found.
Cambiar, pausar o reanudar un recordatorio#
https://wbiztool.com/api/v2/reminders/{id}Cuerpo: JSON (application/json)
Envía solo los campos que cambian; los demás conservan sus valores. Los campos son los de Crear un recordatorio. La respuesta es 200 con el recordatorio tal como queda.
- Pausar:
{"active": false}. Deja de ejecutarse ynext_run_atpasa a sernull. Pausar funciona en cualquier plan. - Reanudar:
{"active": true}. Vuelve a ejecutarse a partir de su próxima hora. Reanudar requiere un plan con recordatorios. schedulese reemplaza entero: envíacroncon él. Sintimezone, el recordatorio conserva la que tiene.
# Pause
curl -X PATCH https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active": false}'
# Move it to Fridays at 10:00 and change the text
curl -X PATCH https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"schedule": {"cron": "0 10 * * 5"}, "text": "Hi, the rent is due today."}'import os
import requests
headers = {"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"}
url = "https://wbiztool.com/api/v2/reminders/812"
paused = requests.patch(url, headers=headers, json={"active": False}, timeout=30).json()
print(paused["active"], paused["next_run_at"]) # False None
resumed = requests.patch(url, headers=headers, json={"active": True}, timeout=30).json()
print(resumed["active"], resumed["next_run_at"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/reminders/812", {
method: "PATCH",
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ active: false }),
});
const reminder = await response.json();
console.log(reminder.active, reminder.next_run_at); // false null<?php
$ch = curl_init('https://wbiztool.com/api/v2/reminders/812');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['active' => false]),
CURLOPT_RETURNTRANSFER => true,
]);
$reminder = json_decode(curl_exec($ch), true);
curl_close($ch);
var_dump($reminder['active']);Un cambio responde con los mismos errores que la creación, y con 404 reminder_not_found. Si un campo es incorrecto, no se cambia nada.
Eliminar un recordatorio#
https://wbiztool.com/api/v2/reminders/{id}Elimina el recordatorio: no vuelve a ejecutarse nunca. Los mensajes que ya envió se quedan en el historial. Para detenerlo solo por un tiempo, ponlo en pausa.
curl -X DELETE https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
{ "id": 812, "deleted": true }
El objeto Reminder#
| Campo | Tipo | Descripción |
|---|---|---|
id | integer | El id del recordatorio. |
name | string | Su nombre. |
active | boolean | true mientras se ejecuta, false mientras está en pausa. |
to | object | El destinatario: phone (con +), group o username. Un recordatorio creado con contact_id muestra el número o el grupo del contacto. |
from | integer or null | El id del número que envía, o null para cualquier número conectado. |
text | string | El mensaje. |
media | object or null | type (image o file), url y file_name. |
schedule | object | cron y timezone. |
next_run_at | string or null | Cuándo se ejecuta la próxima vez, en su zona horaria con el desfase, como 2026-10-19T09:00:00+05:30. null mientras está en pausa. |
created_at | string | Cuándo se creó (UTC). |
Relacionado#
- Recordatorios en el panel
- Referencia de zonas horarias
- Mensajes: un mensaje a una hora fija con
send_at - Errores
