Sviluppatori
Documentazione API
Un endpoint per l'invio, uno per leggere lo stato, webhook firmati HMAC per le ricevute. Le chiavi vengono emesse nel momento in cui l'account esiste — non c'è nulla da approvare e nessuno a cui scrivere.
Per iniziare
Tre cose stanno tra un nuovo account e un messaggio consegnato: un token, un po' di credito, e una chiave. Nessuna di queste coinvolge un essere umano.
- Crei un account: il Suo browser genera il token, e quel token è l'account.
- Lo rifornisca. Minimo $40, in una qualsiasi delle criptovalute su la pagina dei pagamenti.
- Crei una chiave API nel pannello. Viene mostrata una sola volta; conserviamo solo il suo hash, esattamente come per il token.
Una chiave con saldo vuoto non può inviare
La creazione della chiave è deliberatamente subordinata a un account con credito. Una credenziale inutilizzata che resta in giro è una passività senza alcun vantaggio, quindi il pannello non ne genera una finché non c'è nulla da spendere.
Autenticazione
Bearer token a ogni richiesta. La chiave identifica l'account; non c'è un secondo fattore, nessuna firma sulla richiesta e nessuna allowlist di IP — la chiave è l'intera credenziale, quindi la tratti come tale.
Authorization: Bearer ws_live_9f2c…
| Trasporto | Solo HTTPS. Una richiesta in HTTP semplice viene rifiutata, non reindirizzata — un reindirizzamento avrebbe già esposto la chiave. |
|---|---|
| Ambito | Una chiave spende il saldo di un solo account. Crei una chiave per ogni sistema che invia, così una fuga viene revocata in modo mirato. |
| Revoca | Immediato. Una chiave revocata restituisce 401 alla richiesta successiva; i batch in corso già accettati vengono comunque completati. |
| Recupero | Nessuno. Conserviamo solo un hash. Una chiave smarrita viene sostituita, mai recuperata. |
Invii messaggi
POST/v1/messages
Una chiamata, uno o più destinatari, destinazioni miste. Ogni destinatario viene tariffato al prezzo della propria destinazione ed è addebitato per segmento. La chiamata viene accettata o rifiutata nel suo complesso; non Le viene mai addebitato solo in parte.
Corpo della richiesta
| Campo | Tipo | Note |
|---|---|---|
to | string[] | Obbligatorio. E.164, fino a 5.000 per chiamata. I numeri che non corrispondono a una destinazione con tariffa vengono respinti prima della fatturazione. |
text | string | Obbligatorio. UTF-8. Il conteggio dei segmenti segue lo standard GSM 03.38 — vedere segmenti. |
from | string | Mittente alfanumerico, fino a 11 caratteri. Supportato dove la rotta lo consente; vedere mittenti. |
vars | object[] | Valori di merge opzionali, un oggetto per destinatario, sostituiti nei segnaposto {{name}} prima che i segmenti vengano conteggiati. |
callback_url | string | Sovrascrittura facoltativa per lotto del webhook dell'account. |
reference | string | Facoltativo. Viene restituito in ogni ricevuta, così può abbinarlo ai Suoi archivi. |
Esempio
# one call, many recipients, mixed destinations
curl -X POST https://api.worldsms.io/v1/messages \
-H "Authorization: Bearer $WORLDSMS_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "ACME",
"to": ["+447700900123", "+33612345678"],
"text": "Your code is 480913"
}'
{
"batch_id": "b_7Kq2xR9wLm",
"accepted": 2,
"rejected": 0,
"segments": 1,
"cost_usd": 0.0353
}
0,0137 $ verso il Regno Unito più 0,0216 $ verso la Francia — il listino prezzi applicato per destinazione, non una media aggregata.
Raggruppamento
Un batch viene accettato immediatamente e defluisce a 200 messaggi al minuto per account, quindi 50.000 destinatari richiedono circa 4 h 10 min. Il traffico critico in termini di tempo non dovrebbe mettersi in coda dietro un invio di marketing: usi una chiave separata per quello.
Stato del messaggio
GET/v1/messages/{batch_id}
Il polling è supportato e sottoposto a limite di frequenza; i webhook sono il percorso previsto. La risposta aggrega il batch ed elenca lo stato per singolo destinatario.
{
"batch_id": "b_7Kq2xR9wLm",
"status": "done",
"sending": 0,
"delivered": 1,
"undelivered": 1,
"refund_usd": 0.0216
}
refund_usd viene regolato una sola volta, al termine del batch. È già di nuovo nel Suo saldo nel momento in cui può leggerlo.
Saldo
GET/v1/balance
Verifichi prima di un invio consistente. I saldi sono conservati internamente in micro-dollari interi — le tariffe arrivano a quattro decimali, e un float non ha ragione d'esistere in un registro movimenti — e restituiti qui arrotondati a sei.
{ "balance_usd": 412.905400, "currency": "USD" }
Ricevute di consegna
Una ricevuta viene emessa per ogni destinatario non appena l'operatore la riporta. Questi sono gli unici quattro stati; non esiste una categoria “sconosciuto” che significhi silenziosamente “l'abbiamo persa”.
| Stato | Significato | Fatturato |
|---|---|---|
queued | Accettato e in attesa del proprio turno nel lotto. | Sì |
sent | Consegnato all'operatore, nessuna conferma ancora. | Sì |
delivered | Il telefono ha confermato la ricezione. | Sì |
undelivered | Non attivo, bloccato, oppure il mittente è stato rifiutato. | Rimborsato |
I numeri che non corrispondono mai a una destinazione con prezzo sono rifiutati al momento dell'invio e non entrano affatto in questo ciclo di vita — non vengono addebitati e poi rimborsati, semplicemente non vengono addebitati.
Webhook
Imposti un endpoint nel pannello o per singolo batch con callback_url. Inviamo JSON via POST e ci aspettiamo un 2xx entro 5 secondi. Un codice non-2xx viene ritentato sei volte con backoff esponenziale nell'arco di circa un'ora, poi scartato.
Payload
{
"event": "message.delivered",
"batch_id": "b_7Kq2xR9wLm",
"to": "+447700900123",
"destination": "gb",
"segments": 1,
"cost_usd": 0.0137,
"reference": "order-4471",
"ts": 1785312041
}
Verifica della firma in corso
Ogni consegna porta X-WorldSMS-Signature e X-WorldSMS-Timestamp. La firma è HMAC-SHA256(timestamp + "." + body) utilizzando il Suo secret del webhook. Confronti in tempo costante, e rifiuti un timestamp più vecchio di cinque minuti, in modo che una consegna intercettata non possa esserLe ripresentata in seguito.
// $secret is the webhook secret from the dashboard
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_WORLDSMS_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_WORLDSMS_SIGNATURE'] ?? '';
// A stale timestamp is a replay, however well it is signed.
if (abs(time() - (int) $ts) > 300) { http_response_code(408); exit; }
$mine = hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (!hash_equals($mine, $sig)) { http_response_code(401); exit; }
http_response_code(204);
Sia idempotente
Un nuovo tentativo dopo un timeout del Suo endpoint appare identico a una prima consegna. Si basi su batch_id + to + event e tratti una ripetizione come nulla di operativo.
Errori
Ogni errore restituisce un corpo JSON con uno slug error stabile. Si basi sullo slug, mai sul testo descrittivo — il testo può essere migliorato.
| HTTP | Slug | Cosa fare |
|---|---|---|
| 400 | invalid_body | JSON malformato o un campo obbligatorio mancante. |
| 401 | key_rejected | Chiave assente, revocata o errata. Non ritentabile. |
| 402 | insufficient_credit | Il lotto costa più del saldo disponibile. Non è stato inviato nulla; ricarichi e invii di nuovo. |
| 422 | no_valid_recipients | Nessun numero è stato risolto in una destinazione con prezzo. |
| 422 | sender_id_invalid | from è più lungo di 11 caratteri o contiene una stringa solo numerica che verrebbe letta come un numero. |
| 429 | rate_limited | Rallenti. Retry-After indica il numero di secondi. |
| 503 | route_unavailable | Una destinazione è temporaneamente non raggiungibile. Ritentabile. |
{
"error": "insufficient_credit",
"message": "Batch costs $84.20, balance is $12.05.",
"required_usd": 84.20,
"balance_usd": 12.05
}
Limiti
| Richieste | 60 al minuto per chiave, con un picco di 20. Oltre tale soglia, 429 con Retry-After. |
|---|---|
| Destinatari per chiamata | 5.000. Divida gli elenchi più grandi in più chiamate, oppure carichi il file nel pannello. |
| Dimensione del corpo | 2 MB. |
| Velocità di invio | 200 messaggi al minuto per account, indipendentemente da quante chiavi inviano. |
| Chiavi | Nessun limite. Una per ogni sistema di invio è il modello previsto. |
I limiti di frequenza si applicano alle chiamate API, non ai messaggi: una chiamata che trasporta 5.000 destinatari costa una richiesta rispetto al limite.
Le chiavi vengono rilasciate istantaneamente. Non è previsto alcun passaggio di approvazione.
Finanzi un account e il pannello ne genera uno all'istante.