Gestione errori
Questa guida mappa gli errori che puoi incontrare chiamando la SMS API di Agile Telecom in azioni di recovery chiare. Gli errori emergono in tre punti: HTTP di submission, codici di stato per messaggio in submission e stati finali del DLR.
1. Errori a livello HTTP (Submission)
| HTTP | Significato | Cosa fare |
|---|---|---|
200 | Submission accettata (verifica accepted e statusCode per messaggio) | Continua; aspetta i DLR |
400 | Richiesta malformata | Correggi il payload; non ritentare così com'è |
401 | Credenziali non valide | Verifica API key / Basic Auth |
403 | IP non in whitelist | Aggiungi l'IP chiamante alla whitelist |
404 | Endpoint o URL account-type errato | Usa l'URL del tuo tipo di account (legacy vs new) |
408 | Timeout della richiesta | Ritenta con back-off |
413 | Payload troppo grande | Suddividi l'array messages in batch più piccoli |
415 | Content-Type errato | Imposta Content-Type: application/json |
429 | Rate limit superato | Back-off esponenziale, vedi Best Practice |
5xx | Errore di piattaforma | Ritenta con back-off; allerta se persiste |
Una risposta 200 non significa che ogni singola destinazione sia stata accettata — controlla il statusCode per messaggio in results.
2. Codici di submission per messaggio
In una risposta 200, ogni voce in results[] porta il proprio accepted e statusCode.
| Codice | Significato | Azione |
|---|---|---|
200 | Messaggio accettato | Aspetta il DLR |
400 | Destinazione o body invalidi | Correggi e re-invia |
401 | Sender ID non autorizzato per questa destinazione/paese | Usa un altro sender ID o pre-registralo |
402 | Credito insufficiente | Ricarica dal portale wholesale |
403 | Destinazione blacklisted o opt-out | Rimuovila dalla lista, non ritentare |
429 | Throttling per account/route | Rallenta gli invii su quella route |
500 | Errore interno | Ritenta con back-off |
3. Stati finali DLR
Una volta inviato, l'operatore restituisce un delivery report. Il mapping completo è nella guida Delivery Report; ecco la visione di recovery:
| Stato | Codice | Recovery |
|---|---|---|
DELIVERED | 0 | Nessuna — successo |
BUFFERED | 1 | Attendi — l'operatore consegnerà o farà scadere |
EXPIRED | 2 | Opzionale: ritenta una volta dopo un ritardo se il messaggio è ancora utile |
REJECTED | 3 | Investiga sender ID / contenuti; non ritentare alla cieca |
UNDELIVERABLE | 4 | Marca il numero come errato; mai ritentare |
UNKNOWN | 5 | Trattalo come delivered o expired in base alla tolleranza ai falsi negativi |
FAILED | 6 | Ritenta una volta con back-off; se persiste, allerta |
Errori comuni
"Tutto va in 401 dopo mezzanotte." Hai ruotato le key ma il cron job usa ancora quella vecchia. Fix: carica le key da env ad ogni restart e ruotale via deployment.
"Alcune destinazioni vengono silenziosamente scartate."
Spesso il sender ID non è registrato per quel paese (Italia e India sono i casi più comuni). Verifica i DLR REJECTED e il statusCode per messaggio nella risposta di submission.
"I clienti lamentano SMS arrivati 6 ore dopo."
Il telefono era spento e l'operatore ha bufferizzato il messaggio fino all'accensione. Lo stato era BUFFERED → DELIVERED. Abbassa il validity (se disponibile sul tuo account) per send time-sensitive.
"429 casuali a basso carico." Verifica la granularità — i limiti si applicano per API key e a volte per route. SMPP evita la maggior parte di questi casi; vedi SMPP.
"Il webhook continua a essere rilanciato."
Il tuo endpoint DLR non sta tornando 200 (o il tuo endpoint inbound non sta tornando +OK) entro 10–30 secondi. Sposta i lavori pesanti dietro una coda.
Strategia di retry in codice
import time, requests
def send_with_retry(payload, headers, max_attempts=3):
backoff = 1.0
for attempt in range(1, max_attempts + 1):
r = requests.post(
"https://wholesale.agiletelecom.com/services/sms/send",
json=payload, headers=headers, timeout=10,
)
if r.status_code == 200:
return r.json()
if r.status_code in (408, 429) or 500 <= r.status_code < 600:
time.sleep(backoff)
backoff *= 2
continue
# 4xx diversi da 408/429 — non ritentare, la richiesta è errata.
r.raise_for_status()
raise RuntimeError("send_with_retry: retry esauriti")
Prossimi passi
- Best Practice — Throughput, opt-out, idempotenza.
- Delivery Report — Contratto DLR e setup webhook.
- Portale wholesale — Ispeziona i log, le approvazioni sender ID e il credito.