API v2 (bêta)
Messages
Envoyez un message maintenant ou à une heure fixée, à un numéro de téléphone, un groupe WhatsApp, un contact enregistré ou un nom d'utilisateur Telegram. Envoyez le même message jusqu'à 1 000 destinataires en une seule requête, lisez l'historique, suivez le statut d'un message et annulez-le tant qu'il attend.
| Opération | Endpoint | Scope |
|---|---|---|
| Envoyer un message | POST /api/v2/messages | messages:send |
| Envoyer à plusieurs destinataires | POST /api/v2/messages/batch | messages:send |
| Lister les messages | GET /api/v2/messages | messages:read |
| Obtenir un message | GET /api/v2/messages/{id} | messages:read |
| Annuler un message | DELETE /api/v2/messages/{id} | messages:send |
Les clés, les erreurs, Idempotency-Key et les limites fonctionnent comme décrit dans la présentation de l'API v2. Pour savoir quand un message est envoyé ou échoue sans interroger l'API en boucle, ajoutez un endpoint de webhook.
Envoyer un message#
https://wbiztool.com/api/v2/messagesCorps: JSON (application/json)
Le message est mis en file d'attente et la réponse arrive avant son départ, avec le code HTTP 202 et le Message au statut queued (ou scheduled avec un send_at futur). Suivez-le avec Obtenir un message ou un webhook.
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 '{
"from": 101,
"to": { "phone": "+919876543210" },
"text": "Hi Asha, your order #1042 is ready."
}'import os
import requests
response = requests.post(
"https://wbiztool.com/api/v2/messages",
headers={
"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}",
"Idempotency-Key": "order-1042-ready",
},
json={
"from": 101,
"to": {"phone": "+919876543210"},
"text": "Hi Asha, your order #1042 is ready.",
},
timeout=30,
)
body = response.json()
if response.status_code == 202:
print("Queued:", body["id"], body["status"])
else:
print("Refused:", body["error"]["code"], body["error"]["message"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order-1042-ready",
},
body: JSON.stringify({
from: 101,
to: { phone: "+919876543210" },
text: "Hi Asha, your order #1042 is ready.",
}),
});
const body = await response.json();
if (response.status === 202) {
console.log("Queued:", body.id, body.status);
} else {
console.error("Refused:", body.error.code, body.error.message);
}<?php
$ch = curl_init('https://wbiztool.com/api/v2/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order-1042-ready',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => 101,
'to' => ['phone' => '+919876543210'],
'text' => 'Hi Asha, your order #1042 is ready.',
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 202) {
echo 'Queued: ' . $body['id'] . ' ' . $body['status'];
} else {
echo 'Refused: ' . $body['error']['code'] . ' ' . $body['error']['message'];
}Réponse (202) :
{
"id": 9817263,
"status": "queued",
"from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
"to": { "phone": "+919876543210", "contact_id": 991 },
"text": "Hi Asha, your order #1042 is ready.",
"media": null,
"send_at": null,
"expires_at": null,
"created_at": "2026-10-18T10:15:02.311Z",
"sent_at": null,
"error": null
}
Corps
toobjectobligatoireQui le reçoit : exactement un des champs
phone,group,contact_idouusername. Voir Destinataires.frominteger or nullObligatoire sauf si l'espace de travail a un seul numéro connectéL'
iddu numéro qui l'envoie, obtenu avec Lister les numéros. S'il est omis, le seul numéro connecté l'envoie : un seul numéro WhatsApp connecté est utilisé même si un compte Telegram est aussi connecté, et un compte Telegram seulement quand aucun numéro WhatsApp n'est connecté. Un numéro déconnecté est accepté : ses messages attendent qu'il se reconnecte.textstringObligatoire sauf si un média est envoyéLe message, jusqu'à 3 000 caractères. Avec
media, c'est la légende et il peut être omis. La mise en forme WhatsApp fonctionne :*bold*,_italic_,~strikethrough~. En JSON, écrivez les retours à la ligne sous la forme\n.mediaobject or nullfacultatifUne image ou un fichier à envoyer. Voir Médias.
send_atstring or nullfacultatifEnvoyer à cette heure plutôt que maintenant : ISO 8601 avec son décalage, comme
2026-10-20T09:30:00+05:30. Elle doit être dans le futur. Voir Planification et expiration.expires_atstring or nullfacultatifNe pas envoyer après cette heure : le message devient alors
expired. ISO 8601 avec son décalage, dans le futur et aprèssend_at.
En-têtes
AuthorizationheaderobligatoireBearer wbz_live_…, une clé avec le scopemessages:send.Idempotency-KeyheaderfacultatifN'importe quelle chaîne unique, pour qu'une nouvelle tentative n'envoie jamais un deuxième message. Voir Idempotency-Key.
Erreurs à l'envoi#
| HTTP | Code | Quand |
|---|---|---|
400 | validation_failed | Un champ manque, a le mauvais type ou est inconnu ; to n'a aucun de ses champs ou en a plusieurs ; media a à la fois url et media_id, ou aucun des deux ; expires_at n'est pas après send_at |
400 | text_required | Ni text ni media |
400 | text_too_long | text dépasse 3 000 caractères |
400 | invalid_datetime | send_at ou expires_at n'est pas au format ISO 8601 avec un décalage |
402 | no_credits | L'espace de travail n'a plus de messages sur son forfait |
403 | number_not_allowed | La clé est limitée à d'autres numéros |
403 | account_disabled | Le compte du propriétaire de l'espace de travail est désactivé |
422 | invalid_phone | to.phone n'est pas un numéro de téléphone 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 | to.username avec un numéro WhatsApp comme from |
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 | time_in_past | send_at ou expires_at est déjà passé |
422 | number_not_found | from n'est pas un numéro de cet espace de travail |
422 | from_required | Pas de from, et l'espace de travail n'a aucun numéro connecté ou en a plusieurs |
422 | message_rejected | Le message n'a pas pu être mis en file d'attente ; message indique pourquoi |
429 | number_daily_cap_reached | Le numéro a envoyé 1 000 messages au cours des dernières 24 heures |
Un envoi refusé ne laisse aucune trace : aucun message n'est enregistré, il n'y a donc rien à annuler. Les erreurs possibles sur n'importe quelle requête (clés, scopes, limites de débit, Idempotency-Key) se trouvent sur la page des erreurs.
Envoyer à plusieurs destinataires#
https://wbiztool.com/api/v2/messages/batchCorps: JSON (application/json)
Envoie le même message jusqu'à 1 000 destinataires. Le corps est le même que pour Envoyer un message, sauf que to est une liste de destinataires.
- Tout ou rien. Chaque destinataire est vérifié avant que quoi que ce soit ne soit mis en file d'attente, et toute la liste doit tenir dans les messages restants du forfait et dans la marge du numéro d'envoi pour les prochaines 24 heures. Si un destinataire est incorrect, rien n'est mis en file d'attente, et
fieldl'indique, par exempleto[3].phone. - Le même destinataire indiqué deux fois reçoit un seul message.
- La réponse est
202avecdata: un Message par destinataire, dans l'ordre deto.
curl -X POST https://wbiztool.com/api/v2/messages/batch \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: opening-hours-2026-10-20" \
-d '{
"from": 101,
"to": [
{ "phone": "+919876543210" },
{ "phone": "+447700900123" },
{ "group": "Bakery staff" }
],
"text": "We open at 10 tomorrow."
}'import os
import requests
recipients = ["+919876543210", "+447700900123"]
response = requests.post(
"https://wbiztool.com/api/v2/messages/batch",
headers={
"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}",
"Idempotency-Key": "opening-hours-2026-10-20",
},
json={
"from": 101,
"to": [{"phone": p} for p in recipients] + [{"group": "Bakery staff"}],
"text": "We open at 10 tomorrow.",
},
timeout=60,
)
body = response.json()
if response.status_code == 202:
for message in body["data"]:
print(message["id"], message["to"], message["status"])
else:
print("Refused:", body["error"]["code"], body["error"]["field"], body["error"]["message"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const recipients = ["+919876543210", "+447700900123"];
const response = await fetch("https://wbiztool.com/api/v2/messages/batch", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "opening-hours-2026-10-20",
},
body: JSON.stringify({
from: 101,
to: [...recipients.map((phone) => ({ phone })), { group: "Bakery staff" }],
text: "We open at 10 tomorrow.",
}),
});
const body = await response.json();
if (response.status === 202) {
for (const message of body.data) console.log(message.id, message.to, message.status);
} else {
console.error("Refused:", body.error.code, body.error.field, body.error.message);
}<?php
$recipients = ['+919876543210', '+447700900123'];
$to = array_map(fn ($phone) => ['phone' => $phone], $recipients);
$to[] = ['group' => 'Bakery staff'];
$ch = curl_init('https://wbiztool.com/api/v2/messages/batch');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: opening-hours-2026-10-20',
],
CURLOPT_POSTFIELDS => json_encode(['from' => 101, 'to' => $to, 'text' => 'We open at 10 tomorrow.']),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$body = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 202) {
foreach ($body['data'] as $message) {
echo $message['id'] . ' ' . $message['status'] . "\n";
}
} else {
echo 'Refused: ' . $body['error']['code'] . ' ' . $body['error']['field'];
}Réponse (202), un Message par destinataire ; le deuxième et le troisième ressemblent au premier, avec to égal à {"phone": "+447700900123", …} et {"group": "Bakery staff", …} :
{
"data": [
{
"id": 9817264,
"status": "queued",
"from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
"to": { "phone": "+919876543210", "contact_id": 991 },
"text": "We open at 10 tomorrow.",
"media": null,
"send_at": null,
"expires_at": null,
"created_at": "2026-10-19T16:02:40.118Z",
"sent_at": null,
"error": null
}
]
}
Erreurs à l'envoi d'un lot#
Les mêmes que pour l'envoi d'un message, avec la position du destinataire dans field (to[0].phone), et en plus :
| HTTP | Code | Quand |
|---|---|---|
400 | too_many_recipients | to a plus de 1 000 entrées |
400 | validation_failed | to est vide ou n'est pas une liste |
402 | no_credits | La liste ne tient pas dans les messages restants : requested et remaining indiquent de combien |
429 | number_daily_cap_reached | La liste ne tient pas dans la marge du numéro pour les prochaines 24 heures : requested et room indiquent combien |
Lister les messages#
https://wbiztool.com/api/v2/messagesLes messages de l'espace de travail des 90 derniers jours, les plus récents d'abord, par pages. Cela inclut les messages envoyés depuis le tableau de bord, les campagnes, les rappels, les intégrations et l'API v1, pas seulement ceux de l'API v2. Une clé limitée à certains numéros ne voit que leurs messages.
Paramètres de requête
numberintegerfacultatifUniquement les messages de cet
idde numéro.statusstringfacultatifUniquement les messages avec ce statut :
queued,scheduled,sent,delivered,read,failed,cancelledouexpired.sincestringfacultatifUniquement les messages créés à cette heure ou après (ISO 8601 avec décalage).
untilstringfacultatifUniquement les messages créés avant cette heure (ISO 8601 avec décalage).
limitintegerfacultatifMessages par page, de 1 à 100 (25 par défaut).
cursorstringfacultatifLe
next_cursorde la page précédente, avec les mêmes filtres.
Les filtres se combinent. Dans une chaîne de requête, écrivez le + d'un décalage sous la forme %2B (un + simple arrive comme une espace, qui est aussi lue comme +), ou utilisez Z.
curl -G https://wbiztool.com/api/v2/messages \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
--data-urlencode "status=failed" \
--data-urlencode "since=2026-10-01T00:00:00+05:30" \
--data-urlencode "limit=100"import os
import requests
headers = {"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"}
params = {"status": "failed", "since": "2026-10-01T00:00:00+05:30", "limit": 100}
failed = []
while True:
page = requests.get("https://wbiztool.com/api/v2/messages",
headers=headers, params=params, timeout=30).json()
failed += page["data"]
if not page["next_cursor"]:
break
params["cursor"] = page["next_cursor"] # same filters, next page
for message in failed:
print(message["id"], message["to"], message["error"]["message"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const params = new URLSearchParams({ status: "failed", since: "2026-10-01T00:00:00+05:30", limit: "100" });
const failed = [];
while (true) {
const response = await fetch(`https://wbiztool.com/api/v2/messages?${params}`, {
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
const page = await response.json();
failed.push(...page.data);
if (!page.next_cursor) break;
params.set("cursor", page.next_cursor); // same filters, next page
}
for (const message of failed) console.log(message.id, message.to, message.error.message);<?php
$params = ['status' => 'failed', 'since' => '2026-10-01T00:00:00+05:30', 'limit' => 100];
$failed = [];
do {
$ch = curl_init('https://wbiztool.com/api/v2/messages?' . http_build_query($params));
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$page = json_decode(curl_exec($ch), true);
curl_close($ch);
$failed = array_merge($failed, $page['data']);
$params['cursor'] = $page['next_cursor']; // same filters, next page
} while ($page['next_cursor']);
foreach ($failed as $message) {
echo $message['id'] . ' ' . $message['error']['message'] . "\n";
}La réponse est {"data": [Message, …], "next_cursor": "…" or null}.
Erreurs de la liste#
| HTTP | Code | Quand |
|---|---|---|
400 | validation_failed | number n'est pas un identifiant de numéro, status n'est pas l'un des statuts, ou limit n'est pas entre 1 et 100 |
400 | invalid_datetime | since ou until n'est pas au format ISO 8601 avec un décalage |
400 | invalid_cursor | Le curseur est endommagé ou a été créé avec d'autres filtres |
Obtenir un message#
https://wbiztool.com/api/v2/messages/{id}Un message et son statut actuel.
curl https://wbiztool.com/api/v2/messages/9817263 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"import os
import requests
response = requests.get(
"https://wbiztool.com/api/v2/messages/9817263",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
timeout=30,
)
message = response.json()
print(message["status"], message["sent_at"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/messages/9817263", {
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
const message = await response.json();
console.log(message.status, message.sent_at);<?php
$ch = curl_init('https://wbiztool.com/api/v2/messages/9817263');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
]);
$message = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $message['status'];Réponse (200), un message qui a été distribué :
{
"id": 9817263,
"status": "delivered",
"from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
"to": { "phone": "+919876543210", "contact_id": 991 },
"text": "Hi Asha, your order #1042 is ready.",
"media": null,
"send_at": null,
"expires_at": null,
"created_at": "2026-10-18T10:15:02.311Z",
"sent_at": "2026-10-18T10:15:09.870Z",
"error": null
}
Un message qui n'existe pas, qui appartient à un autre espace de travail ou (pour une clé limitée à certains numéros) qui a été envoyé depuis un autre numéro répond 404 message_not_found.
Annuler un message#
https://wbiztool.com/api/v2/messages/{id}Annule un message qui attend encore (queued ou scheduled), quelle que soit son origine. La réponse est 200 avec le Message, désormais au statut cancelled. Un endpoint de webhook reçoit message.cancelled.
Un message déjà parti ne peut pas être rappelé. Un message que le numéro d'envoi est en train de prendre en charge à ce moment-là peut encore partir : vérifiez donc son statut ensuite si cela compte.
curl -X DELETE https://wbiztool.com/api/v2/messages/9817263 \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"import os
import requests
response = requests.delete(
"https://wbiztool.com/api/v2/messages/9817263",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
timeout=30,
)
body = response.json()
if response.status_code == 200:
print("Cancelled")
elif body["error"]["code"] == "not_cancellable":
print("Too late, it is", body["error"]["status"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/messages/9817263", {
method: "DELETE",
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
const body = await response.json();
if (response.ok) console.log("Cancelled");
else if (body.error.code === "not_cancellable") console.log("Too late, it is", body.error.status);<?php
$ch = curl_init('https://wbiztool.com/api/v2/messages/9817263');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
]);
$body = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status === 200 ? 'Cancelled' : $body['error']['code'];Erreurs à l'annulation#
| HTTP | Code | Quand |
|---|---|---|
404 | message_not_found | Aucun message de ce type pour cette clé |
409 | not_cancellable | Il n'attend plus ; status dans l'erreur indique son état actuel, par exemple sent |
L'objet Message#
Chaque opération de cette page répond avec des objets Message, et les événements webhook en contiennent un dans data.message.
| Champ | Type | Description |
|---|---|---|
id | integer | L'identifiant du message. Utilisez-le pour obtenir ou annuler le message. |
status | string | Où il en est. Voir Statuts. |
from | object | Le numéro d'envoi : id, phone (ses chiffres avec l'indicatif du pays, sans +) et platform (whatsapp ou telegram). |
to | object | Le destinataire : phone (avec +), group ou username, et contact_id, le contact enregistré auquel il a été envoyé. Un numéro de téléphone ou un groupe qui reçoit un message pour la première fois est enregistré comme contact. (contact_id ne vaut null que pour un message de test vers un numéro non enregistré.) |
text | string | Le texte ou la légende ; "" s'il n'y en a pas. |
media | object or null | type (image ou file), url et file_name (null pour les images). L'url peut être un lien valable pendant une durée limitée ; ne le conservez pas. |
send_at | string or null | L'heure pour laquelle il est planifié, ou null pour « maintenant ». |
expires_at | string or null | L'heure après laquelle il n'est plus envoyé, ou null. |
created_at | string | Quand il a été créé. |
sent_at | string or null | Quand il est parti, une fois parti (sent, delivered ou read). |
error | object or null | Pour un message failed ou expired, message indique pourquoi, par exemple File exceeds WhatsApp size limit (16MB max). null sinon. |
Statuts#
| Statut | Signification |
|---|---|
queued | En attente d'envoi. |
scheduled | En attente de son send_at. |
sent | Envoyé depuis votre numéro (une coche dans WhatsApp). |
delivered | Distribué sur le téléphone du destinataire (deux coches). |
read | Lu par le destinataire (coches bleues). |
failed | Il n'a pas pu être envoyé ; error.message indique pourquoi. |
cancelled | Annulé avant son départ : avec Annuler un message, depuis le tableau de bord, ou parce que son numéro ou sa campagne a été supprimé. |
expired | Non envoyé avant son expires_at. |
queued et scheduled peuvent être annulés. sent peut encore devenir delivered puis read. failed, cancelled, expired et read sont définitifs. Les webhooks signalent sent, failed, cancelled et expired ; pour voir delivered et read, obtenez le message.
Destinataires#
to prend exactement un de ces champs :
| Champ | Exemple | Qui le reçoit |
|---|---|---|
phone | {"phone": "+919876543210"} | Un numéro de téléphone au format international avec + (E.164). Les espaces et les tirets sont acceptés. |
group | {"group": "Bakery staff"} | Un groupe WhatsApp dont fait partie le numéro d'envoi, par son nom exact (jusqu'à 200 caractères). |
contact_id | {"contact_id": 991} | Un contact enregistré dans l'espace de travail, par son identifiant (le contact_id d'un message précédent, par exemple). Le message part vers le numéro ou le groupe de ce contact. |
username | {"username": "@asha_bakes"} | Un utilisateur Telegram : @name, un lien t.me/name, ou tg: suivi d'un identifiant d'utilisateur. Uniquement depuis un compte Telegram : indiquez-en un comme from (ou n'en ayez qu'un seul connecté). |
Les envois vers un groupe ou sur Telegram exigent que le numéro d'envoi fasse partie de ce groupe ou puisse joindre cet utilisateur ; un problème à ce niveau apparaît comme un message failed, pas comme une erreur au moment de l'envoi.
Médias#
media envoie une image ou un fichier, avec text comme légende. Indiquez exactement un des champs url ou media_id :
media.urlstringurl ou media_idUn lien public
httpouhttpsvers le fichier, jusqu'à 1 000 caractères. Les liens vers des adresses privées ou locales sont refusés avecinvalid_media_url.media.media_idintegerurl ou media_idUn fichier du Répertoire média de l'espace de travail, obtenu avec Téléverser un fichier. Téléversez un fichier une fois et envoyez-le aussi souvent que vous le souhaitez.
media.typestringfacultatifimageoufile. S'il est omis, un lien se terminant par.jpg,.jpeg,.png,.gifou.webpest envoyé comme image et tout le reste comme fichier ; unmedia_idutilise le type avec lequel le fichier a été téléversé.media.file_namestringfacultatifPour un
file: le nom que voit le destinataire, commeinvoice-1042.pdf(jusqu'à 100 caractères). S'il est omis, le nom vient du lien ou du fichier téléversé. Son extension détermine la façon dont le fichier est envoyé : incluez-en donc une. Ignoré pour les images.
{
"to": { "phone": "+919876543210" },
"text": "Your invoice for order #1042",
"media": { "url": "https://example.com/invoices/1042.pdf", "type": "file", "file_name": "invoice-1042.pdf" }
}
Le fichier est récupéré au moment de l'envoi du message, pas lors de l'appel à l'API : un lien cassé ou un fichier trop volumineux apparaît donc comme un message failed avec la raison dans error.message. Les règles de taille et de type sont celles de la v1 : voir Envoyer des images et des fichiers.
Planification et expiration#
send_atplanifie le message. Il restescheduledjusque-là et peut être annulé tant qu'il n'est pas parti. Écrivez l'heure avec son décalage :2026-10-20T09:30:00+05:30signifie 09:30 en Inde. Pour les messages qui se répètent, utilisez les rappels.expires_atest une échéance : si le message n'est pas parti d'ici là (parce que le numéro était déconnecté, par exemple), il devientexpiredau lieu de partir en retard. Utilisez-le pour les codes à usage unique, les heures de livraison et les offres. Une tâche en arrière-plan le marque comme expiré au moins 30 secondes après l'échéance : ne comptez donc pas sur des échéances de moins d'une minute.- Les deux doivent être dans le futur, et
expires_atdoit être aprèssend_at.
