---
title: "Envoyer un SMS par API : exemples Python, Node.js, PHP et cURL"
description: "Envoyer des SMS par API en Python, Node.js, PHP et cURL : envois unitaires et en masse, Unicode et arabe, segments, webhooks de statut et gestion d'erreurs."
canonical: "https://omnichannels.ai/fr/blog/send-sms-api-examples/"
language: "fr"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "envoyer sms api python"
keywords: ["envoyer sms python", "exemple api sms node.js", "api sms php", "api sms curl", "api sms unicode arabe", "webhook accusé de réception sms", "exemple api sms en masse"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "Pour envoyer un SMS avec l'API OmniChannels.ai, effectuez un POST authentifié vers https://api.broadnet.me/sms/sendSms avec un corps JSON contenant senderId, destinationNumber, message et messageType. Utilisez TEXT pour du texte GSM-7 et UNICODE pour l'arabe ou les emojis. Une réponse 200 renvoie l'identifiant du message en texte brut, et le statut de livraison final arrive plus tard sur votre webhook."
takeaways: ["POST /sms/sendSms exige quatre champs : senderId, destinationNumber, message et messageType ; le corps de la réponse est l'identifiant du message en texte brut, pas du JSON.", "Réglez messageType sur UNICODE pour l'arabe, les emojis ou tout caractère hors GSM-7 ; un seul de ces caractères fait passer tout le message en Unicode et raccourcit chaque segment.", "POST /sms/identify compte les caractères et les segments avant l'envoi, ce qui permet de prévoir le nombre de segments d'un message.", "La livraison est asynchrone : un 200 signifie « accepté », et DELIVERED, FAILED ou REJECTED arrive plus tard sur votre webhook.", "L'API n'a pas de clé d'idempotence : enregistrez chaque envoi avant de l'effectuer et vérifiez le statut après un délai d'attente dépassé plutôt que de renvoyer."]
faq: 
  - q: "Comment envoyer un SMS avec Python ?"
    a: "Utilisez la bibliothèque requests pour envoyer en POST du JSON vers https://api.broadnet.me/sms/sendSms avec un en-tête Authorization: Bearer et les champs senderId, destinationNumber, message et messageType. Lisez le jeton dans une variable d'environnement. Le corps d'une réponse 200 est l'identifiant du message en texte brut : utilisez donc r.text plutôt que r.json()."
  - q: "Quel format de numéro de téléphone l'API SMS attend-elle ?"
    a: "L'indicatif pays suivi du numéro national, uniquement des chiffres, sans signe plus, sans préfixe 00, sans espaces ni zéro initial. Par exemple, 447700900123 est valide, alors que +44 7700 900123 et 07700900123 ne le sont pas. Stockez les numéros au format E.164 dans votre base de données et retirez le signe plus au moment de construire la requête."
  - q: "Comment envoyer un SMS en arabe via l'API ?"
    a: "Réglez messageType sur UNICODE et envoyez le texte arabe dans le champ message en UTF-8. Les messages Unicode contiennent 70 caractères dans un segment unique et 67 par segment lorsqu'ils sont découpés, contre 160 et 153 en GSM-7. Testez sur de vrais téléphones et appelez d'abord /sms/identify pour connaître le nombre de segments."
  - q: "Comment obtenir les accusés de livraison ?"
    a: "Les statuts sont poussés vers l'URL de webhook configurée sur votre compte. Les messages passent par SUBMITTED et SENT avant d'arriver à DELIVERED, FAILED ou REJECTED. Votre point de terminaison doit stocker l'événement brut, répondre rapidement en 2xx et traiter de façon asynchrone. Si des événements ont été manqués, POST /sms/resendDlr peut renvoyer les accusés pour une plage de dates."
  - q: "Comment envoyer un SMS à de nombreux numéros à la fois ?"
    a: "Utilisez POST /sms/sendbulk, une requête multipart avec un destinationNumberFile (CSV ou TXT) et une chaîne JSON bulkRequest contenant senderId, message et messageType. La réponse indique combien de numéros étaient valides, invalides ou en doublon, et renvoie un bulkSessionId que vous pouvez stocker avec votre campagne."
  - q: "Faut-il enregistrer un sender ID ?"
    a: "Dans de nombreux pays, oui. Certains exigent un sender ID alphanumérique approuvé, d'autres des identifiants de régulateur ou de modèle, que l'API accepte dans des champs facultatifs comme peId et templateId. Les exigences dépendent du pays : consultez la page sender ID de votre destination, et notre équipe peut s'occuper de l'enregistrement avec vous."
sources: 
  - title: "3GPP TS 23.040 : réalisation technique du service de messages courts (SMS)"
    url: "https://www.3gpp.org/dynareport?code=23040"
  - title: "ITU-T E.164 : plan de numérotation public international des télécommunications"
    url: "https://www.itu.int/rec/T-REC-E.164"
  - title: "RFC 9110 : HTTP Semantics"
    url: "https://www.rfc-editor.org/rfc/rfc9110"
---

# Envoyer un SMS par API : exemples Python, Node.js, PHP et cURL

Canonical: https://omnichannels.ai/fr/blog/send-sms-api-examples/
Language: fr
Publisher: OmniChannels.ai by BroadNet Technologies

Ce guide s'adresse aux développeurs qui doivent envoyer des SMS depuis une application et veulent du code fonctionnel en Python, Node.js, PHP ou cURL. Il couvre un envoi unitaire, l'Unicode et l'arabe, le comptage des segments, l'envoi en masse par fichier, les webhooks de statut de livraison et la gestion des erreurs, en n'utilisant que les points de terminaison et champs de notre [référence de l'API SMS](/developers/sms/) et de la spécification OpenAPI.

## Comment envoyer un SMS avec l'API ?

Effectuez un `POST` authentifié vers `/sms/sendSms` avec un corps JSON. La réponse est `200 OK` avec l'identifiant du message en texte brut.

| Élément | Valeur |
|---|---|
| URL de base | `https://api.broadnet.me` (sans préfixe `/v1`) |
| Point de terminaison | `POST /sms/sendSms` |
| Authentification | `Authorization: Bearer $BROADNET_TOKEN` |
| Type de contenu | `application/json` |
| Champs obligatoires | `senderId`, `destinationNumber`, `message`, `messageType` |

Les identifiants de test sont délivrés après une brève demande d'accès, et les envois de test partent vers vos propres numéros vérifiés. Il n'existe pas d'inscription instantanée en libre-service. Voir le [démarrage rapide](/developers/quickstart/).

```bash
curl -X POST https://api.broadnet.me/sms/sendSms \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "OmniDemo",
    "destinationNumber": "447700900123",
    "message": "Your OmniDemo code is 482913",
    "messageType": "TEXT"
  }'
```

```js
// Node.js 18+ (fetch intégré)
const res = await fetch("https://api.broadnet.me/sms/sendSms", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BROADNET_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    senderId: "OmniDemo",
    destinationNumber: "447700900123",
    message: "Your OmniDemo code is 482913",
    messageType: "TEXT",
  }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const messageId = await res.text(); // identifiant du message en texte brut
```

```python
import os
import requests

r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "447700900123",
        "message": "Your OmniDemo code is 482913",
        "messageType": "TEXT",
    },
    timeout=15,
)
r.raise_for_status()
message_id = r.text  # identifiant du message en texte brut, pas du JSON
```

```php
<?php
$payload = json_encode([
    "senderId" => "OmniDemo",
    "destinationNumber" => "447700900123",
    "message" => "Your OmniDemo code is 482913",
    "messageType" => "TEXT",
]);

$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("BROADNET_TOKEN"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);
$messageId = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
echo $status . " " . $messageId . PHP_EOL;
```

Le corps d'une réponse réussie ressemble à ceci :

```text
2603121407537573731
```

Conservez cet identifiant avec votre propre enregistrement, par exemple une commande ou une tentative de connexion. C'est lui qui permet de rapprocher les statuts de livraison par la suite.

## Comment formater les numéros de téléphone ?

Utilisez l'indicatif pays suivi du numéro national, uniquement des chiffres. Le format suit le plan de numérotation international de l'ITU-T E.164, sans le signe plus.

| Saisie | Valide ? | Pourquoi |
|---|---|---|
| `447700900123` | Oui | Indicatif 44 plus numéro national |
| `+44 7700 900123` | Non | Retirez le signe plus et les espaces |
| `07700900123` | Non | Remplacez le 0 initial par l'indicatif pays |

Stockez les numéros au format E.164 (`+447700900123`) dans votre base de données et retirez le `+` au moment de construire la requête. Notre outil gratuit de formatage de numéros permet une vérification rapide.

## Comment envoyer de l'arabe, des emojis ou d'autres textes Unicode ?

Réglez `messageType` sur `UNICODE`. Tout caractère hors de l'alphabet GSM-7, comme une lettre arabe, un emoji, un guillemet typographique ou un tiret cadratin, fait basculer tout le message en Unicode.

```python
r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "971500000000",
        "message": "رمز التحقق الخاص بك هو 482913",
        "messageType": "UNICODE",
        "campaignName": "login-otp",
    },
    timeout=15,
)
```

En PHP, utilisez `JSON_UNESCAPED_UNICODE` lorsque vous appelez `json_encode`. L'encodage détermine la taille des segments, telle que définie pour le SMS dans la norme 3GPP TS 23.040 :

| `messageType` | SMS unique | Par segment en cas de découpage | À utiliser pour |
|---|---|---|---|
| `TEXT` | 160 caractères | 153 caractères | Texte n'utilisant que l'alphabet GSM-7 |
| `UNICODE` | 70 caractères | 67 caractères | Arabe, cyrillique, chinois, emojis |

La plupart des opérateurs facturent au segment : un long message en arabe coûte donc plus cher que le même texte en écriture latine. Lisez notre [guide du SMS Unicode et arabe](/fr/blog/sms-character-limits-unicode-arabic/) et essayez le compteur de caractères SMS.

## Comment compter les segments avant l'envoi ?

Appelez `POST /sms/identify` avec le message. Il renvoie l'encodage détecté, le nombre de caractères, le nombre de segments et la limite par segment.

```bash
curl -X POST https://api.broadnet.me/sms/identify \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Your OmniDemo code is 482913" }'
```

```json
{
  "message": "Your OmniDemo code is 482913",
  "messageType": "TEXT",
  "smscount": 1,
  "charCount": 28,
  "charLimit": 160
}
```

Vous pouvez transmettre `smsParts` (issu de `smscount`), `charCount` et `charLimit` dans une requête d'envoi. Le texte GSM-7 peut être étiqueté `GSM-7` dans la réponse ; envoyez-le en `TEXT`.

## Comment envoyer à de nombreux numéros ?

Utilisez `POST /sms/sendbulk`, une requête `multipart/form-data` avec un fichier de destinataires et une chaîne JSON de paramètres.

```bash
curl -X POST https://api.broadnet.me/sms/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F destinationNumberFile=@recipients.csv \
  -F 'bulkRequest={"senderId":"OmniDemo","message":"Your statement is ready in the app.","messageType":"TEXT","campaignName":"oct-statements","allowDuplicate":false}'
```

```python
import json
import os
import requests

bulk_request = {
    "senderId": "OmniDemo",
    "message": "Your statement is ready in the app.",
    "messageType": "TEXT",
    "campaignName": "oct-statements",
    "allowDuplicate": False,
}

with open("recipients.csv", "rb") as f:
    r = requests.post(
        "https://api.broadnet.me/sms/sendbulk",
        headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
        files={"destinationNumberFile": ("recipients.csv", f, "text/csv")},
        data={"bulkRequest": json.dumps(bulk_request)},
        timeout=60,
    )
print(r.json())
```

La réponse comprend `bulkSessionId` et un objet `bulkListInfo` avec `total`, `validCount`, `invalidCount` et `duplicate`. Stockez `bulkSessionId` avec la campagne. Les tâches peuvent être listées, mises en pause, reprises et abandonnées via les points de terminaison de la référence. Vous pouvez aussi vérifier les numéros avant un gros envoi avec `POST /sms/lookup` ; voir notre [guide du HLR lookup](/fr/blog/hlr-lookup-number-validation/).

## Comment recevoir le statut de livraison ?

Les statuts de livraison sont poussés vers l'URL de webhook configurée sur votre compte. Un message passe par `SUBMITTED` et `SENT` jusqu'à `DELIVERED`, ou se termine en `FAILED` ou `REJECTED`. Vous communiquez à notre équipe l'URL HTTPS publique, et les revendeurs peuvent avoir un webhook par sous-compte.

Les champs de la charge utile varient selon le canal et la spécification de l'API ne définit pas de schéma de webhook unique : journalisez d'abord le corps brut et associez les champs à partir d'un événement réel de votre compte. Un récepteur minimal stocke l'événement et accuse réception rapidement :

```js
import express from "express";

const app = express();

app.post("/webhooks/omnichannels", express.json(), async (req, res) => {
  await saveStatusEvent(req.body); // votre stockage ; traitement asynchrone
  res.sendStatus(200);             // accuser réception rapidement
});

app.listen(3000);
```

Rendez le traitement idempotent, car le même statut peut arriver deux fois, et ne laissez jamais un `SENT` tardif écraser un `DELIVERED` déjà stocké. Si votre point de terminaison était indisponible, `POST /sms/resendDlr` renvoie les accusés pour une plage de dates :

```bash
curl -X POST https://api.broadnet.me/sms/resendDlr \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2026-10-09",
    "endDate": "2026-10-10",
    "senderId": "OmniDemo",
    "messageStatus": "DELIVERED"
  }'
```

Pour en savoir plus, consultez le [guide des webhooks](/developers/webhooks/) et les statuts de livraison des messages expliqués.

## Comment gérer les erreurs et éviter les doublons ?

Traitez d'abord le statut HTTP, puis le corps de l'erreur. Ne réessayez que sur les erreurs réseau, `429` et `5xx`.

| Code | Signification | Action |
|---|---|---|
| `200` | Accepté | Stocker l'identifiant |
| `400` | Erreur de validation ou champ manquant | Corriger la requête |
| `401` / `403` | Jeton invalide ou opération non autorisée | Corriger ; ne pas réessayer |
| `429` | Limite de débit dépassée | Attendre `Retry-After` |
| `500`, `503`, `504` | Problème de serveur ou en amont | Réessayer avec backoff et jitter |

Les erreurs levées par l'API utilisent un corps JSON à cinq champs : `status`, `error`, `message`, `errorCode` et `requestUri`. La limite REST documentée par défaut est de 200 requêtes par seconde en continu ; les limites de votre compte sont confirmées avec vos identifiants.

L'API n'accepte aucune clé d'idempotence. Une requête peut aboutir alors que sa réponse est perdue, et un nouvel essai à l'aveugle envoie alors deux fois. Écrivez une ligne « en attente » portant votre propre identifiant d'opération avant l'appel, stockez l'identifiant de message renvoyé et, après un délai d'attente dépassé, cherchez un statut de webhook avant de renvoyer. Pour les envois en masse, réglez `allowDuplicate` sur `false`. Les détails figurent dans [Erreurs et limites](/developers/errors-and-limits/).

## Exemple concret : des codes de connexion pour une application régionale

« Souq Rafiq » (société fictive), enseigne de distribution aux Émirats arabes unis, envoie des codes de connexion par SMS.

1. Le service d'authentification génère un code à six chiffres, stocke un hash avec une expiration de cinq minutes et écrit une ligne d'envoi `pending`.
2. Il appelle `/sms/sendSms` avec `messageType=UNICODE` pour les utilisateurs arabophones et `TEXT` pour les anglophones.
3. Sur un `200`, il stocke l'identifiant du message.
4. Le gestionnaire de webhook marque la ligne `DELIVERED`, `FAILED` ou `REJECTED`.
5. Si le statut n'est pas `DELIVERED` après une courte attente, l'application propose un renvoi et, si c'est configuré, un autre canal. Voir le repli entre canaux.
6. Des limites sur les demandes de code par numéro et par IP protègent contre les abus ; voir [prévention du SMS pumping](/fr/blog/sms-pumping-fraud-prevention/).

## Quelles sont les erreurs courantes ?

- **Appeler `r.json()` sur la réponse d'envoi.** C'est du texte brut.
- **Mauvais noms de champs.** Utilisez `senderId`, `destinationNumber` et `message` ; des champs comme `to`, `from` ou `text` ne font pas partie de ce point de terminaison.
- **Signes plus et zéros initiaux** dans les numéros.
- **Oublier `UNICODE`** pour l'arabe, ce qui déforme le texte.
- **Sender ID non enregistrés.** Certains pays les bloquent ou les remplacent ; consultez les règles de sender ID de votre destination et demandez-nous de gérer l'enregistrement.
- **Considérer `200` comme « délivré ».**
- **Jeton dans une application mobile ou un navigateur,** où n'importe qui peut l'extraire.
- **Limites :** ce guide présente la requête courante. Les champs facultatifs comme les formats de planification doivent être confirmés avec notre équipe.

## Comment OmniChannels.ai vous aide

OmniChannels.ai envoie du SMS A2P via la connectivité opérateur directe de BroadNet, avec SMS bidirectionnel, sender ID, Unicode et arabe, HLR lookup et SMPP 3.4 pour les volumes élevés. L'API REST disponible sur `https://api.broadnet.me` utilise un jeton Bearer et couvre aussi WhatsApp, RCS et d'autres canaux, avec des statuts de livraison normalisés dans un format de webhook unique. Notre équipe prépare avec vous les enregistrements de sender ID. Consultez la [référence de l'API SMS](/developers/sms/) ou le canal SMS.
