Vai al contenuto
WbizTool

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.

OperazioneEndpointScope
Inviare un messaggioPOST /api/v2/messagesmessages:send
Inviare a molti destinatariPOST /api/v2/messages/batchmessages:send
Elencare i messaggiGET /api/v2/messagesmessages:read
Ottenere un messaggioGET /api/v2/messages/{id}messages:read
Annullare un messaggioDELETE /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#

POSThttps://wbiztool.com/api/v2/messages

Corpo: 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."
  }'

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

toobjectobbligatorio

Chi lo riceve: esattamente uno tra phone, group, contact_id o username. Vedi Destinatari.

frominteger or nullObbligatorio, a meno che lo spazio di lavoro abbia un solo numero collegato

L'id del 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 media

Il 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 nullfacoltativo

Un'immagine o un file da inviare. Vedi Media.

send_atstring or nullfacoltativo

Invia 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 nullfacoltativo

Non inviare dopo questo orario: il messaggio diventa invece expired. ISO 8601 con il suo offset, nel futuro e dopo send_at.

Header

Authorizationheaderobbligatorio

Bearer wbz_live_…, una chiave con lo scope messages:send.

Idempotency-Keyheaderfacoltativo

Qualsiasi stringa univoca, così un nuovo tentativo non invia mai un secondo messaggio. Vedi Idempotency-Key.

Errori durante l'invio#

HTTPCodiceQuando
400validation_failedUn 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
400text_requiredNé text né media
400text_too_longtext supera i 3.000 caratteri
400invalid_datetimesend_at o expires_at non è in ISO 8601 con un offset
402no_creditsLo spazio di lavoro non ha più messaggi nel suo piano
403number_not_allowedLa chiave è limitata ad altri numeri
403account_disabledL'account del proprietario dello spazio di lavoro è disattivato
422invalid_phoneto.phone non è un numero di telefono in formato internazionale con +
422invalid_usernameto.username non è uno username, un link o un id tg: di Telegram
422username_needs_telegramto.username con un numero WhatsApp come from
422contact_not_foundNessun contatto con quel to.contact_id
422media_not_foundNessun file con quel media.media_id
422invalid_media_urlmedia.url non è un link pubblico http(s)
422time_in_pastsend_at o expires_at è già passato
422number_not_foundfrom non è un numero di questo spazio di lavoro
422from_requiredNessun from, e lo spazio di lavoro non ha nessun numero collegato oppure ne ha diversi
422message_rejectedNon è stato possibile mettere in coda il messaggio; message spiega perché
429number_daily_cap_reachedIl 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#

POSThttps://wbiztool.com/api/v2/messages/batch

Corpo: 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 field lo indica, come to[3].phone.
  • Lo stesso destinatario indicato due volte riceve un solo messaggio.
  • La risposta è 202 con data: un Message per destinatario, nell'ordine di to.
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."
  }'

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:

HTTPCodiceQuando
400too_many_recipientsto ha più di 1.000 voci
400validation_failedto è vuoto o non è un elenco
402no_creditsL'elenco non rientra nei messaggi rimasti: requested e remaining indicano di quanto
429number_daily_cap_reachedL'elenco non rientra nella disponibilità del numero per le prossime 24 ore: requested e room indicano quanti

Elencare i messaggi#

GEThttps://wbiztool.com/api/v2/messages

I 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

numberintegerfacoltativo

Solo i messaggi di questo id di numero.

statusstringfacoltativo

Solo i messaggi con questo stato: queued, scheduled, sent, delivered, read, failed, cancelled o expired.

sincestringfacoltativo

Solo i messaggi creati a partire da questo orario (ISO 8601 con offset).

untilstringfacoltativo

Solo i messaggi creati prima di questo orario (ISO 8601 con offset).

limitintegerfacoltativo

Messaggi per pagina, da 1 a 100 (predefinito 25).

cursorstringfacoltativo

Il next_cursor dell'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"

La risposta è {"data": [Message, …], "next_cursor": "…" or null}.

Errori durante l'elenco#

HTTPCodiceQuando
400validation_failednumber non è un id di numero, status non è uno degli stati, oppure limit non è tra 1 e 100
400invalid_datetimesince o until non è in ISO 8601 con un offset
400invalid_cursorIl cursore è danneggiato o è stato creato con altri filtri

Ottenere un messaggio#

GEThttps://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"

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#

DELETEhttps://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"

Errori durante l'annullamento#

HTTPCodiceQuando
404message_not_foundNessun messaggio di questo tipo per questa chiave
409not_cancellableNon è 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.

CampoTipoDescrizione
idintegerL'id del messaggio. Usalo per ottenere o annullare il messaggio.
statusstringIn che stato si trova ora. Vedi Stati.
fromobjectIl numero mittente: id, phone (le sue cifre con il prefisso internazionale, senza +) e platform (whatsapp o telegram).
toobjectIl 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.)
textstringIl testo o la didascalia; "" quando non c'è.
mediaobject or nulltype (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_atstring or nullL'orario per cui è pianificato, oppure null per "subito".
expires_atstring or nullL'orario dopo il quale non viene inviato, oppure null.
created_atstringQuando è stato creato.
sent_atstring or nullQuando è partito, una volta partito (sent, delivered o read).
errorobject or nullPer un messaggio failed o expired, message spiega perché, come File exceeds WhatsApp size limit (16MB max). Altrimenti null.

Stati#

StatoSignificato
queuedIn attesa di partire.
scheduledIn attesa del suo send_at.
sentInviato dal tuo numero (una spunta in WhatsApp).
deliveredConsegnato al telefono del destinatario (due spunte).
readLetto dal destinatario (spunte blu).
failedNon è stato possibile inviarlo; error.message spiega perché.
cancelledAnnullato prima di partire: con Annullare un messaggio, dalla dashboard, oppure perché il suo numero o la sua campagna sono stati rimossi.
expiredNon 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:

CampoEsempioChi 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_id

Un link pubblico http o https al file, fino a 1.000 caratteri. I link a indirizzi privati o locali vengono rifiutati con invalid_media_url.

media.media_idintegerurl oppure media_id

Un 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.typestringfacoltativo

image o file. Se lo ometti, un link che termina con .jpg, .jpeg, .png, .gif o .webp viene inviato come immagine e tutto il resto come file; un media_id usa il tipo con cui il file è stato caricato.

media.file_namestringfacoltativo

Per un file: il nome che vede il destinatario, come invoice-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_at pianifica il messaggio. Rimane scheduled fino a quel momento e può essere annullato finché non parte. Scrivi l'orario con il suo offset, così 2026-10-20T09:30:00+05:30 significa 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), diventa expired invece 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_at deve essere dopo send_at.

Pagine correlate#