API v2 (bêta)
Rappels
Un rappel envoie le même message à un destinataire, encore et encore, selon un planning : le loyer chaque mois, un cours chaque lundi, un rapport chaque soir. Le planning est une expression cron en 5 parties dans le fuseau horaire de votre choix. Les rappels créés avec l'API sont les mêmes que ceux de la page Rappels du tableau de bord.
| Opération | Endpoint | Scope |
|---|---|---|
| Créer un rappel | POST /api/v2/reminders | reminders |
| Lister les rappels | GET /api/v2/reminders | reminders |
| Obtenir un rappel | GET /api/v2/reminders/{id} | reminders |
| Modifier, mettre en pause ou réactiver | PATCH /api/v2/reminders/{id} | reminders |
| Supprimer un rappel | DELETE /api/v2/reminders/{id} | reminders |
Créer et modifier des rappels demande un forfait qui inclut les rappels ; sinon, la réponse est 403 plan_required. Lister, lire, mettre en pause et supprimer fonctionnent avec n'importe quel forfait. Pour un message qui part une seule fois à une heure fixée, utilisez plutôt send_at dans Envoyer un message.
Créer un rappel#
https://wbiztool.com/api/v2/remindersCorps: 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'];Réponse (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"
}
Corps
namestringobligatoireUn nom pour le rappel, jusqu'à 100 caractères, tel qu'affiché sur la page Rappels.
toobjectobligatoireExactement un des champs
phone(format international avec+),group(le nom exact d'un groupe WhatsApp),contact_idouusername(Telegram), comme dans Messages → Destinataires.frominteger or nullObligatoire pour une clé limitée à certains numérosL'
iddu numéro qui l'envoie. Il doit être connecté au moment où vous le définissez. S'il est omis ou vautnull: n'importe quel numéro connecté de l'espace de travail l'envoie.textstringobligatoireLe message, jusqu'à 3 000 caractères. C'est aussi la légende lorsque
mediaest envoyé.mediaobject or nullfacultatifUne image ou un fichier à envoyer à chaque fois :
urloumedia_id, et éventuellementtype, comme dans Messages → Médias.scheduleobjectobligatoirecron(obligatoire) ettimezone. Voir Planning.activebooleanfacultatiftrue(par défaut) l'active ;falsele crée en pause.
Planning#
schedule.cron comporte cinq parties séparées par des espaces : minute, heure, jour du mois, mois, jour de la semaine. * signifie « chaque ». Ce doit être un planning qui s'exécute à un moment donné (pas le 31 février).
cron | S'exécute |
|---|---|
0 9 * * 1 | Le lundi à 09:00 |
30 18 * * * | Tous les jours à 18:30 |
0 10 1 * * | Le 1er de chaque mois à 10:00 |
0 9 * * 1-5 | Du lundi au vendredi à 09:00 |
0 8,20 * * * | Tous les jours à 08:00 et 20:00 |
0 9 15 1 * | Le 15 janvier à 09:00, chaque année |
schedule.timezone est un nom de fuseau horaire IANA, comme Asia/Kolkata, Europe/London ou America/New_York (UTC par défaut). Les heures du cron sont dans ce fuseau, et next_run_at y est aussi exprimé, avec son décalage. Consultez la référence des fuseaux horaires.
Chaque exécution envoie un message comme n'importe quel autre : il faut des messages restants sur le forfait, et il apparaît dans Lister les messages.
Erreurs à la création#
| HTTP | Code | Quand |
|---|---|---|
400 | validation_failed | Un champ obligatoire manque ou est vide, un champ est inconnu ou trop long (name, to.group), ou media n'est pas valide |
400 | text_required | text est vide |
400 | text_too_long | text dépasse 3 000 caractères |
400 | invalid_cron | schedule.cron n'a pas 5 parties, ou ne s'exécute jamais |
400 | invalid_timezone | schedule.timezone n'est pas un fuseau horaire IANA |
403 | plan_required | Le forfait n'inclut pas les rappels |
403 | number_not_allowed | La clé est limitée à certains numéros et from n'en fait pas partie, ou manque |
422 | invalid_phone | to.phone n'est pas un numéro valide au format international avec + |
422 | invalid_username | to.username n'est pas un nom d'utilisateur Telegram, un lien ou un identifiant tg: |
422 | username_needs_telegram | Un nom d'utilisateur Telegram, mais from n'est pas un compte Telegram (ou, sans from, aucun compte Telegram n'est connecté) |
422 | contact_not_found | Aucun contact avec ce to.contact_id |
422 | media_not_found | Aucun fichier avec ce media.media_id |
422 | invalid_media_url | media.url n'est pas un lien http(s) public |
422 | number_not_connected | from n'est pas un numéro connecté de cet espace de travail |
Lister les rappels#
https://wbiztool.com/api/v2/remindersLes rappels de l'espace de travail, les plus récents d'abord, par pages (limit de 1 à 100, 25 par défaut, et cursor). Les rappels en pause sont inclus, avec "active": false. Une clé limitée à certains numéros ne voit que les rappels qui envoient depuis ceux-ci.
curl "https://wbiztool.com/api/v2/reminders?limit=50" \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
La réponse est {"data": [Reminder, …], "next_cursor": "…" or null}.
Obtenir un rappel#
https://wbiztool.com/api/v2/reminders/{id}curl https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
Un rappel qui n'existe pas, a été supprimé ou envoie depuis un numéro que la clé ne peut pas utiliser répond 404 reminder_not_found.
Modifier, mettre en pause ou réactiver un rappel#
https://wbiztool.com/api/v2/reminders/{id}Corps: JSON (application/json)
N'envoyez que les champs qui changent ; les autres gardent leur valeur. Les champs sont ceux de Créer un rappel. La réponse est 200 avec le rappel dans son état actuel.
- Mettre en pause :
{"active": false}. Il cesse de s'exécuter etnext_run_atdevientnull. La mise en pause fonctionne avec n'importe quel forfait. - Réactiver :
{"active": true}. Il s'exécute de nouveau à partir de sa prochaine heure. La réactivation demande un forfait avec les rappels. scheduleest remplacé en entier : envoyezcronavec lui. Sanstimezone, le rappel garde son fuseau actuel.
# 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']);Une modification répond avec les mêmes erreurs que la création, plus 404 reminder_not_found. Si un champ est incorrect, rien n'est modifié.
Supprimer un rappel#
https://wbiztool.com/api/v2/reminders/{id}Supprime le rappel : il ne s'exécute plus jamais. Les messages qu'il a déjà envoyés restent dans l'historique. Pour l'arrêter temporairement, mettez-le plutôt en pause.
curl -X DELETE https://wbiztool.com/api/v2/reminders/812 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
{ "id": 812, "deleted": true }
L'objet Rappel#
| Champ | Type | Description |
|---|---|---|
id | integer | L'identifiant du rappel. |
name | string | Son nom. |
active | boolean | true tant qu'il s'exécute, false lorsqu'il est en pause. |
to | object | Le destinataire : phone (avec +), group ou username. Un rappel créé avec contact_id affiche le numéro ou le groupe du contact. |
from | integer or null | L'id du numéro d'envoi, ou null pour n'importe quel numéro connecté. |
text | string | Le message. |
media | object or null | type (image ou file), url et file_name. |
schedule | object | cron et timezone. |
next_run_at | string or null | Sa prochaine exécution, dans son fuseau horaire avec le décalage, comme 2026-10-19T09:00:00+05:30. null lorsqu'il est en pause. |
created_at | string | Quand il a été créé (UTC). |
Voir aussi#
- Rappels dans le tableau de bord
- Référence des fuseaux horaires
- Messages : un message unique à une heure fixée avec
send_at - Erreurs
