API v2 (beta)
Messaggi
Invia un messaggio subito o a un orario stabilito, a un numero di telefono, a un gruppo WhatsApp, a un contatto salvato o a uno username Telegram. Invia lo stesso messaggio fino a 1.000 destinatari in una sola richiesta, leggi la cronologia, segui lo stato di un messaggio e annullalo mentre è in attesa.
| Operazione | Endpoint | Scope |
|---|---|---|
| Inviare un messaggio | POST /api/v2/messages | messages:send |
| Inviare a molti destinatari | POST /api/v2/messages/batch | messages:send |
| Elencare i messaggi | GET /api/v2/messages | messages:read |
| Ottenere un messaggio | GET /api/v2/messages/{id} | messages:read |
| Annullare un messaggio | DELETE /api/v2/messages/{id} | messages:send |
Chiavi, errori, Idempotency-Key e limiti funzionano come descritto nella panoramica dell'API v2. Per sapere quando un messaggio viene inviato o non riesce senza interrogare l'API, aggiungi un endpoint del webhook.
Inviare un messaggio#
https://wbiztool.com/api/v2/messagesCorpo: JSON (application/json)
Il messaggio viene messo in coda e la risposta arriva prima che parta, con HTTP 202 e il Message nello stato queued (oppure scheduled con un send_at futuro). Seguilo con Ottenere un messaggio o con 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'];
}Risposta (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
}
Body
toobjectobbligatorioChi lo riceve: esattamente uno tra
phone,group,contact_idousername. Vedi Destinatari.frominteger or nullObbligatorio, a meno che lo spazio di lavoro abbia un solo numero collegatoL'
iddel numero che lo invia, da Elencare i numeri. Se lo ometti, lo invia l'unico numero collegato: un numero WhatsApp collegato viene usato anche se è collegato anche un account Telegram, e un account Telegram solo quando non è collegato nessun numero WhatsApp. Un numero disconnesso viene accettato: i suoi messaggi attendono finché non si ricollega.textstringObbligatorio, a meno che vengano inviati mediaIl messaggio, fino a 3.000 caratteri. Con
mediaè la didascalia e può essere omesso. La formattazione di WhatsApp funziona:*bold*,_italic_,~strikethrough~. In JSON scrivi gli a capo come\n.mediaobject or nullfacoltativoUn'immagine o un file da inviare. Vedi Media.
send_atstring or nullfacoltativoInvia a questo orario invece che subito: ISO 8601 con il suo offset, come
2026-10-20T09:30:00+05:30. Deve essere nel futuro. Vedi Pianificazione e scadenza.expires_atstring or nullfacoltativoNon inviare dopo questo orario: il messaggio diventa invece
expired. ISO 8601 con il suo offset, nel futuro e doposend_at.
Header
AuthorizationheaderobbligatorioBearer wbz_live_…, una chiave con lo scopemessages:send.Idempotency-KeyheaderfacoltativoQualsiasi stringa univoca, così un nuovo tentativo non invia mai un secondo messaggio. Vedi Idempotency-Key.
Errori durante l'invio#
| HTTP | Codice | Quando |
|---|---|---|
400 | validation_failed | Un campo manca, ha il tipo sbagliato o non è riconosciuto; to non ha nessuno dei suoi campi o ne ha più di uno; media ha sia url sia media_id o nessuno dei due; expires_at non è dopo send_at |
400 | text_required | Né text né media |
400 | text_too_long | text supera i 3.000 caratteri |
400 | invalid_datetime | send_at o expires_at non è in ISO 8601 con un offset |
402 | no_credits | Lo spazio di lavoro non ha più messaggi nel suo piano |
403 | number_not_allowed | La chiave è limitata ad altri numeri |
403 | account_disabled | L'account del proprietario dello spazio di lavoro è disattivato |
422 | invalid_phone | to.phone non è un numero di telefono in formato internazionale con + |
422 | invalid_username | to.username non è uno username, un link o un id tg: di Telegram |
422 | username_needs_telegram | to.username con un numero WhatsApp come from |
422 | contact_not_found | Nessun contatto con quel to.contact_id |
422 | media_not_found | Nessun file con quel media.media_id |
422 | invalid_media_url | media.url non è un link pubblico http(s) |
422 | time_in_past | send_at o expires_at è già passato |
422 | number_not_found | from non è un numero di questo spazio di lavoro |
422 | from_required | Nessun from, e lo spazio di lavoro non ha nessun numero collegato oppure ne ha diversi |
422 | message_rejected | Non è stato possibile mettere in coda il messaggio; message spiega perché |
429 | number_daily_cap_reached | Il numero ha inviato 1.000 messaggi nelle ultime 24 ore |
Un invio rifiutato non lascia traccia: nessun messaggio viene salvato, quindi non c'è nulla da annullare. Gli errori che possono verificarsi con qualsiasi richiesta (chiavi, scope, limiti di richieste, Idempotency-Key) sono nella pagina degli errori.
Inviare a molti destinatari#
https://wbiztool.com/api/v2/messages/batchCorpo: JSON (application/json)
Invia lo stesso messaggio fino a 1.000 destinatari. Il body è lo stesso di Inviare un messaggio, tranne che to è un elenco di destinatari.
- Tutto o niente. Ogni destinatario viene controllato prima di mettere in coda qualsiasi cosa, e l'intero elenco deve rientrare nei messaggi rimasti del piano e nella disponibilità del numero mittente per le prossime 24 ore. Se un destinatario è errato, non viene messo in coda nulla, e
fieldlo indica, cometo[3].phone. - Lo stesso destinatario indicato due volte riceve un solo messaggio.
- La risposta è
202condata: un Message per destinatario, nell'ordine dito.
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'];
}Risposta (202), un Message per destinatario; il secondo e il terzo sono come il primo, con to impostato a {"phone": "+447700900123", …} e {"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
}
]
}
Errori durante l'invio di un batch#
Gli stessi dell'invio di un singolo messaggio, con la posizione del destinatario in field (to[0].phone), e inoltre:
| HTTP | Codice | Quando |
|---|---|---|
400 | too_many_recipients | to ha più di 1.000 voci |
400 | validation_failed | to è vuoto o non è un elenco |
402 | no_credits | L'elenco non rientra nei messaggi rimasti: requested e remaining indicano di quanto |
429 | number_daily_cap_reached | L'elenco non rientra nella disponibilità del numero per le prossime 24 ore: requested e room indicano quanti |
Elencare i messaggi#
https://wbiztool.com/api/v2/messagesI messaggi dello spazio di lavoro degli ultimi 90 giorni, dal più recente, in pagine. Sono compresi i messaggi inviati dalla dashboard, dalle campagne, dai promemoria, dalle integrazioni e dall'API v1, non solo quelli dell'API v2. Una chiave limitata ad alcuni numeri vede solo i loro messaggi.
Parametri di query
numberintegerfacoltativoSolo i messaggi di questo
iddi numero.statusstringfacoltativoSolo i messaggi con questo stato:
queued,scheduled,sent,delivered,read,failed,cancelledoexpired.sincestringfacoltativoSolo i messaggi creati a partire da questo orario (ISO 8601 con offset).
untilstringfacoltativoSolo i messaggi creati prima di questo orario (ISO 8601 con offset).
limitintegerfacoltativoMessaggi per pagina, da 1 a 100 (predefinito 25).
cursorstringfacoltativoIl
next_cursordell'ultima pagina, con gli stessi filtri.
I filtri si combinano. In una query string, scrivi il + di un offset come %2B (un + semplice arriva come spazio, che viene comunque letto come +), oppure usa 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 risposta è {"data": [Message, …], "next_cursor": "…" or null}.
Errori durante l'elenco#
| HTTP | Codice | Quando |
|---|---|---|
400 | validation_failed | number non è un id di numero, status non è uno degli stati, oppure limit non è tra 1 e 100 |
400 | invalid_datetime | since o until non è in ISO 8601 con un offset |
400 | invalid_cursor | Il cursore è danneggiato o è stato creato con altri filtri |
Ottenere un messaggio#
https://wbiztool.com/api/v2/messages/{id}Un messaggio e il suo stato attuale.
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'];Risposta (200), un messaggio consegnato:
{
"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 messaggio che non esiste, appartiene a un altro spazio di lavoro oppure (per una chiave limitata ad alcuni numeri) è stato inviato da un altro numero risponde 404 message_not_found.
Annullare un messaggio#
https://wbiztool.com/api/v2/messages/{id}Annulla un messaggio ancora in attesa (queued o scheduled), chiunque l'abbia creato. La risposta è 200 con il Message, ora nello stato cancelled. Un endpoint del webhook riceve message.cancelled.
Un messaggio già partito non può essere richiamato. Un messaggio che il numero mittente sta prendendo in carico proprio in quel momento può ancora partire, quindi controllane lo stato in seguito se è importante.
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'];Errori durante l'annullamento#
| HTTP | Codice | Quando |
|---|---|---|
404 | message_not_found | Nessun messaggio di questo tipo per questa chiave |
409 | not_cancellable | Non è più in attesa; status nell'errore indica in che stato si trova ora, come sent |
L'oggetto Message#
Ogni operazione di questa pagina risponde con oggetti Message, e gli eventi webhook ne contengono uno in data.message.
| Campo | Tipo | Descrizione |
|---|---|---|
id | integer | L'id del messaggio. Usalo per ottenere o annullare il messaggio. |
status | string | In che stato si trova ora. Vedi Stati. |
from | object | Il numero mittente: id, phone (le sue cifre con il prefisso internazionale, senza +) e platform (whatsapp o telegram). |
to | object | Il destinatario: phone (con +), group o username, e contact_id, il contatto salvato a cui è andato. Un numero di telefono o un gruppo a cui si invia per la prima volta viene salvato come contatto. (contact_id è null solo per un messaggio di test a un numero non salvato.) |
text | string | Il testo o la didascalia; "" quando non c'è. |
media | object or null | type (image o file), url e file_name (null per le immagini). L'url può essere un link valido per un tempo limitato; non salvarlo. |
send_at | string or null | L'orario per cui è pianificato, oppure null per "subito". |
expires_at | string or null | L'orario dopo il quale non viene inviato, oppure null. |
created_at | string | Quando è stato creato. |
sent_at | string or null | Quando è partito, una volta partito (sent, delivered o read). |
error | object or null | Per un messaggio failed o expired, message spiega perché, come File exceeds WhatsApp size limit (16MB max). Altrimenti null. |
Stati#
| Stato | Significato |
|---|---|
queued | In attesa di partire. |
scheduled | In attesa del suo send_at. |
sent | Inviato dal tuo numero (una spunta in WhatsApp). |
delivered | Consegnato al telefono del destinatario (due spunte). |
read | Letto dal destinatario (spunte blu). |
failed | Non è stato possibile inviarlo; error.message spiega perché. |
cancelled | Annullato prima di partire: con Annullare un messaggio, dalla dashboard, oppure perché il suo numero o la sua campagna sono stati rimossi. |
expired | Non inviato prima del suo expires_at. |
queued e scheduled possono essere annullati. sent può ancora diventare delivered e poi read. failed, cancelled, expired e read sono definitivi. I webhook segnalano sent, failed, cancelled ed expired; per vedere delivered e read, ottieni il messaggio.
Destinatari#
to accetta esattamente uno di questi campi:
| Campo | Esempio | Chi lo riceve |
|---|---|---|
phone | {"phone": "+919876543210"} | Un numero di telefono in formato internazionale con + (E.164). Spazi e trattini sono consentiti. |
group | {"group": "Bakery staff"} | Un gruppo WhatsApp di cui fa parte il numero mittente, con il suo nome esatto (fino a 200 caratteri). |
contact_id | {"contact_id": 991} | Un contatto salvato nello spazio di lavoro, tramite il suo id (per esempio il contact_id di un messaggio precedente). Va al numero o al gruppo di quel contatto. |
username | {"username": "@asha_bakes"} | Un utente Telegram: @name, un link t.me/name, oppure tg: e un id utente. Solo da un account Telegram, quindi indicane uno come from (oppure tienine collegato esattamente uno). |
Gli invii a gruppi e su Telegram richiedono che il numero mittente faccia parte di quel gruppo o possa raggiungere quell'utente; i problemi in questi casi compaiono come messaggio failed, non come errore al momento dell'invio.
Media#
media invia un'immagine o un file, con text come didascalia. Indica esattamente uno tra url e media_id:
media.urlstringurl oppure media_idUn link pubblico
httpohttpsal file, fino a 1.000 caratteri. I link a indirizzi privati o locali vengono rifiutati coninvalid_media_url.media.media_idintegerurl oppure media_idUn file nella Directory media dello spazio di lavoro, da Caricare un file. Carica un file una volta e invialo tutte le volte che vuoi.
media.typestringfacoltativoimageofile. Se lo ometti, un link che termina con.jpg,.jpeg,.png,.gifo.webpviene inviato come immagine e tutto il resto come file; unmedia_idusa il tipo con cui il file è stato caricato.media.file_namestringfacoltativoPer un
file: il nome che vede il destinatario, comeinvoice-1042.pdf(fino a 100 caratteri). Se lo ometti, il nome viene preso dal link o dal file caricato. La sua estensione decide come viene inviato il file, quindi includine una. Ignorato per le immagini.
{
"to": { "phone": "+919876543210" },
"text": "Your invoice for order #1042",
"media": { "url": "https://example.com/invoices/1042.pdf", "type": "file", "file_name": "invoice-1042.pdf" }
}
Il file viene scaricato quando il messaggio viene inviato, non quando chiami l'API, quindi un link non funzionante o un file troppo grande compare come messaggio failed con il motivo in error.message. Le regole su dimensioni e tipi sono quelle della v1: vedi Invio di immagini e file.
Pianificazione e scadenza#
send_atpianifica il messaggio. Rimanescheduledfino a quel momento e può essere annullato finché non parte. Scrivi l'orario con il suo offset, così2026-10-20T09:30:00+05:30significa le 09:30 in India. Per i messaggi ricorrenti usa i promemoria.expires_atè una scadenza: se il messaggio non è partito entro quel momento (per esempio perché il numero era disconnesso), diventaexpiredinvece di partire in ritardo. Usalo per codici monouso, orari di consegna e offerte. Un processo in background lo segna come scaduto almeno 30 secondi dopo la scadenza, quindi non fare affidamento su scadenze inferiori a un minuto.- Entrambi devono essere nel futuro, e
expires_atdeve essere doposend_at.
Pagine correlate#
- Webhook: ricevi
message.sentemessage.failedinvece di interrogare l'API. - File multimediali: carica i file da inviare tramite
media_id. - Numeri: l'
idda usare comefrom. - Errori
