Développeurs
Référence API
Un point d'accès pour l'envoi, un pour lire le statut, des webhooks signés HMAC pour les accusés de réception. Les clés sont délivrées dès que le compte existe — rien à approuver, personne à contacter par e-mail.
Démarrage
Trois choses séparent un nouveau compte d'un message distribué : un jeton, du crédit et une clé. Aucune n'implique un humain.
- Créez un compte — votre navigateur génère le jeton, et ce jeton est le compte.
- Alimentez-le. $40 minimum, dans n'importe laquelle des cryptos sur la page des paiements.
- Créez une clé API dans le tableau de bord. Elle est affichée une seule fois ; nous ne stockons que son hash, exactement comme le jeton.
Une clé sur un solde vide ne peut pas envoyer
La création de clé est délibérément conditionnée à un compte alimenté. Un identifiant inutilisé qui traîne est un risque sans contrepartie, le tableau de bord n'en génère donc aucun tant qu'il n'y a rien à dépenser.
Authentification
Un jeton porteur à chaque requête. La clé identifie le compte ; il n'y a ni second facteur, ni signature de la requête, ni liste blanche d'IP — la clé est l'identifiant complet, traitez-la comme telle.
Authorization: Bearer ws_live_9f2c…
| Transport | HTTPS uniquement. Une requête en HTTP simple est refusée, pas redirigée — une redirection aurait déjà divulgué la clé. |
|---|---|
| Portée | Une clé dépense le solde d'un seul compte. Créez une clé par système qui envoie, afin qu'une fuite soit révoquée de façon ciblée. |
| Révocation | Immédiat. Une clé révoquée renvoie 401 à la prochaine requête ; les lots en cours déjà acceptés se terminent quand même. |
| Récupération | Aucune. Nous conservons un hachage. Une clé perdue est remplacée, jamais récupérée. |
Envoyer des messages
POST/v1/messages
Un seul appel, un ou plusieurs destinataires, des destinations mixtes. Chaque destinataire est facturé au tarif de sa propre destination, par segment. L'appel est accepté ou refusé dans son ensemble ; il ne vous facture jamais partiellement.
Corps de la requête
| Champ | Type | Notes |
|---|---|---|
to | string[] | Obligatoire. E.164, jusqu'à 5 000 par appel. Les numéros qui ne correspondent à aucune destination tarifée sont rejetés avant facturation. |
text | string | Obligatoire. UTF-8. Le nombre de segments suit la norme GSM 03.38 — voir segments. |
from | string | ID expéditeur alphanumérique, jusqu'à 11 caractères. Transmis là où la route le permet ; voir ID expéditeur. |
vars | object[] | Valeurs de fusion facultatives, un objet par destinataire, substituées dans les emplacements {{name}} avant le comptage des segments. |
callback_url | string | Remplacement optionnel du webhook de compte, par lot. |
reference | string | Facultatif. Renvoyé sur chaque accusé de réception afin de le relier à vos propres registres. |
Exemple
# 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 $ vers le Royaume-Uni plus 0,0216 $ vers la France — la grille tarifaire appliquée par destination, et non une moyenne mélangée.
Groupement
Un lot est accepté immédiatement et s'écoule à raison de 200 messages par minute et par compte, donc 50 000 destinataires prennent environ 4 h 10 min. Un trafic urgent ne devrait pas attendre derrière un envoi marketing : utilisez une clé distincte pour cela.
Statut du message
GET/v1/messages/{batch_id}
L'interrogation périodique est prise en charge et limitée en débit ; les webhooks sont la voie prévue. La réponse regroupe le lot et liste l'état par destinataire.
{
"batch_id": "b_7Kq2xR9wLm",
"status": "done",
"sending": 0,
"delivered": 1,
"undelivered": 1,
"refund_usd": 0.0216
}
refund_usd est réglé une seule fois, à la fin du lot. Il est déjà de retour dans votre solde au moment où vous pouvez le lire.
Solde
GET/v1/balance
Vérifiez avant un envoi important. Les soldes sont conservés en interne sous forme de micro-dollars entiers — les tarifs vont jusqu'à quatre décimales, et un flottant n'a rien à faire dans un registre — et sont restitués ici arrondis à six décimales.
{ "balance_usd": 412.905400, "currency": "USD" }
Accusés de réception
Un accusé est émis par destinataire au fur et à mesure que l'opérateur le signale. Ce sont les quatre seuls états ; il n'existe pas de catégorie « inconnu » qui signifierait discrètement « nous l'avons perdu ».
| État | Signification | Facturé |
|---|---|---|
queued | Accepté et en attente de son tour dans le lot. | Oui |
sent | Remis à l'opérateur, pas encore de confirmation. | Oui |
delivered | Le téléphone l'a confirmé. | Oui |
undelivered | Hors service, barré, ou l'expéditeur a été refusé. | Remboursé |
Les numéros qui ne correspondent à aucune destination tarifée sont rejetés dès la soumission et n'entrent jamais dans ce cycle de vie — ils ne sont pas facturés puis remboursés, ils ne sont simplement jamais facturés.
Webhooks
Définissez un point de terminaison dans le tableau de bord ou par lot avec callback_url. Nous envoyons du JSON en POST et attendons un 2xx sous 5 secondes. Toute réponse hors 2xx est retentée six fois avec un backoff exponentiel sur environ une heure, puis abandonnée.
Charge utile
{
"event": "message.delivered",
"batch_id": "b_7Kq2xR9wLm",
"to": "+447700900123",
"destination": "gb",
"segments": 1,
"cost_usd": 0.0137,
"reference": "order-4471",
"ts": 1785312041
}
Vérification de la signature
Chaque distribution transporte X-WorldSMS-Signature et X-WorldSMS-Timestamp. La signature est HMAC-SHA256(timestamp + "." + body) en utilisant votre secret de webhook. Comparez en temps constant, et rejetez un horodatage vieux de plus de cinq minutes afin qu'une distribution interceptée ne puisse pas vous être rejouée plus tard.
// $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);
Être idempotent
Une nouvelle tentative après un délai d'expiration de votre point de terminaison est identique à une première distribution. Utilisez batch_id + to + event comme clé et traitez une répétition comme un no-op.
Erreurs
Chaque échec renvoie un corps JSON avec un identifiant error stable. Faites correspondre sur cet identifiant, jamais sur le texte — le texte est libre de s'améliorer.
| HTTP | Slug | Que faire |
|---|---|---|
| 400 | invalid_body | JSON malformé ou champ requis manquant. |
| 401 | key_rejected | Clé absente, révoquée ou mal saisie. Non réessayable. |
| 402 | insufficient_credit | Le lot coûte plus que le solde. Rien n'a été envoyé ; rechargez et soumettez à nouveau. |
| 422 | no_valid_recipients | Aucun numéro n'a pu être résolu vers une destination tarifée. |
| 422 | sender_id_invalid | from comporte plus de 11 caractères ou contient une chaîne uniquement numérique qui serait lue comme un nombre. |
| 429 | rate_limited | Ralentissez. Retry-After indique le nombre de secondes. |
| 503 | route_unavailable | Une destination est temporairement inaccessible. Réessayable. |
{
"error": "insufficient_credit",
"message": "Batch costs $84.20, balance is $12.05.",
"required_usd": 84.20,
"balance_usd": 12.05
}
Limites
| Requêtes | 60 par minute et par clé, rafale de 20. 429 avec Retry-After au-delà. |
|---|---|
| Destinataires par appel | 5 000. Répartissez les listes plus longues sur plusieurs appels, ou importez le fichier dans le tableau de bord. |
| Taille du corps | 2 MB. |
| Débit | 200 messages par minute et par compte, quel que soit le nombre de clés qui envoient. |
| Clés | Aucune limite. Une par système d'envoi est le modèle prévu. |
Les limites de débit s'appliquent aux appels API, pas aux messages : un appel transportant 5 000 destinataires compte pour une seule requête au regard de la limite.
Les clés sont délivrées instantanément. Aucune étape d'approbation.
Financez un compte et le tableau de bord en crée un sur-le-champ.