Sign inGet Started

Envoyer des SMS

Ce guide couvre le point de terminaison d'envoi unitaire, POST /v1/sms/messages. Construisez un payload JSON avec un destinataire, un expéditeur, un corps et une catégorie. Bird renvoie 202 Accepted avec un ID de message et effectue la remise de façon asynchrone. Chaque requête envoie un message à un seul destinataire. Pour envoyer plusieurs messages à la fois, utilisez l'envoi par lot. Pour envoyer un template au lieu de votre propre texte, fournissez un objet template à la place de text, category et from.

Avant d'envoyer : activez le pays de destination

Votre espace de travail dispose d'une liste de destinations en mode refus par défaut, initialement limitée au pays d'origine de votre organisation. Bird rejette un envoi vers tout autre pays avec 422 SMSDestinationNotEnabled avant de résoudre un expéditeur. Activez les pays que vous desservez sous SMS > Destinations dans le tableau de bord.

Un envoi minimal

Le plus petit payload de texte libre valide comprend un destinataire to, un expéditeur from, un corps text et une catégorie category.
const msg = await bird.sms.send({
  from: "+15557654321",
  to: "+14155550100",
  text: "Your verification code is 123456.",
  category: "authentication",
});
console.log(msg.id, msg.status);
Utilisez votre hôte régional (https://us1.platform.bird.com ou https://eu1.platform.bird.com) avec une clé bk_{region}_... correspondante. La réponse est le message accepté :
Exemple de code
{
  "id": "sms_01ky7qmwgpfkybj9ecrnwjx714",
  "direction": "outbound",
  "status": "accepted",
  "to": "+31612345678",
  "from": "Bird",
  "text": "Your Bird verification code is 481920. It expires in 10 minutes.",
  "category": "authentication",
  "segments": { "count": 1, "encoding": "GSM_7BIT", "characters": 64 },
  "cost": null,
  "carrier": null,
  "mcc_mnc": null,
  "sent_at": null,
  "delivered_at": null,
  "created_at": "2026-07-23T14:56:34.326Z"
}
status: accepted signifie que Bird a reçu le message et le traite ; cost vaut null parce que la tarification intervient pendant le traitement. La suite est décrite dans le modèle asynchrone.

Construire le payload

Destinataire

to est un destinataire unique au format E.164 : un + initial, l'indicatif pays et le numéro d'abonné, par exemple +31612345678. Un message est envoyé à un seul destinataire, sans cc, bcc ni tableau de destinataires. Pour joindre plusieurs personnes, envoyez un lot.

Expéditeur

from est requis pour un envoi en texte libre et correspond à l'expéditeur que le destinataire voit. Il prend l'une des deux formes suivantes, et celles qui fonctionnent dépendent du pays de destination :
  • Un identifiant d'expéditeur alphanumérique : 3 à 11 lettres, chiffres, espaces, tirets, underscores ou points, avec au moins une lettre et aucun séparateur aux extrémités, par exemple Bird ou Acme-Co. Il doit contenir une lettre : une chaîne de chiffres ponctuée telle que 555 555 est donc refusée. Certains pays exigent un enregistrement, et d'autres, dont les États-Unis, ne prennent pas en charge les expéditeurs alphanumériques. Les destinataires ne peuvent pas y répondre.
  • Un numéro détenu par votre espace de travail, au format E.164 ou en chiffres seuls. Tout from entièrement numérique est interprété comme numérique et recherché parmi vos expéditeurs, donc un numéro arbitraire que vous ne détenez pas est rejeté. Qu'il agisse comme un numéro long, un numéro gratuit ou un numéro court dépend du numéro lui-même, et non du nombre de chiffres saisis. Un from à 6 chiffres n'est pas un numéro court parce qu'il a 6 chiffres ; c'est un numéro court si le numéro que vous détenez en est un.
Un expéditeur non valide pour la destination est rejeté avec une 422 indiquant la raison (par exemple SMSAlphaNotSupported lorsque les expéditeurs alphanumériques ne sont pas disponibles). Lors d'un envoi par template, from n'est pas accepté : Bird sélectionne un expéditeur en fonction de la destination et de la catégorie.
Réclamer un identifiant d'expéditeur, consulter les exigences de chaque pays et l'enregistrer par pays sont traités dans Identifiants d'expéditeur SMS.

Corps et catégorie

text est le corps du message, au minimum un caractère. Il est facturé et remis en segments ; un envoi est limité à 12 segments (environ 1 836 caractères GSM-7, ou 804 si le corps utilise l'encodage étendu UCS-2). Un corps dépassant cette limite est rejeté avec une 422 plutôt que tronqué.
category est requis pour un envoi en texte libre et classe le message comme transactional, marketing, authentication ou service. Il indique à Bird et aux opérateurs pourquoi vous envoyez. Un code de vérification à usage unique utilise authentication ; une promotion utilise marketing. Choisissez la catégorie correspondant à l'objectif du message.

Tags et métadonnées

Les deux permettent d'associer vos propres données à un envoi, mais ils remplissent des rôles différents :
  • Les tags sont des paires {name, value} structurées (max 20 par envoi ; nom de 1 à 32 caractères, valeur de 1 à 64, ASCII [A-Za-z0-9_-] uniquement, sensible à la casse, noms uniques par envoi). Ce sont des dimensions de filtre de premier ordre : filtrez la liste de messages par tag. Utilisez-les pour des labels à faible cardinalité comme campaign ou experiment_variant.
  • metadata est un objet JSON arbitraire (max 2 Ko sérialisé). Il est stocké, renvoyé lors des lectures API, et répercuté sur chaque événement webhook, mais ce n'est pas une dimension de filtre. Utilisez-le pour du contexte aller-retour : identifiants internes, clés étrangères, tout ce que vous souhaitez récupérer avec chaque événement.
Exemple de code
{
  "tags": [{ "name": "campaign", "value": "spring-2026" }],
  "metadata": { "user_id": "usr_12345", "order_id": "ord_98765" }
}

Référence des champs

ChampTypeRequisLimites / notes
tostring (E.164)ouiUn destinataire par message
fromstringoui*Numéro E.164 détenu, identifiant d'expéditeur alphanumérique (3–11 car., au moins une lettre) ou numéro court (5–6 chiffres)
textstringoui*Au moins 1 caractère ; limité à 12 segments
categorystringoui*transactional, marketing, authentication ou service
tags{name, value}[]nonMax 20 ; nom 1–32 car., valeur 1–64 car. ; [A-Za-z0-9_-] uniquement
metadataobjectnonJSON arbitraire, max 2 Ko sérialisé
optionsobjectnonParamètres de traitement par message. smart_encoding est le seul disponible ; voir segments et encodage
* Requis pour un envoi en texte libre. Un envoi par template fournit le corps, la catégorie et l'expéditeur à partir du template, et rejette ces trois champs.

Envoyer avec un template

Au lieu de composer text, définissez l'objet template de l'envoi pour référencer l'un des templates intégrés de Bird. Le template fournit le corps, la catégorie et l'expéditeur, donc text, category, from et media_urls ne sont pas acceptés conjointement. Le catalogue, les variables de chaque template et le contrat complet d'envoi par template se trouvent dans Templates SMS.

Segments et encodage

SMS est facturé par segment. Un message compatible avec l'encodage GSM-7 dispose de 160 caractères par segment unique ; UCS-2 (déclenché par les emoji, les caractères CJK ou d'autres caractères hors GSM) descend à 70. Les messages plus longs sont découpés en segments multipart avec des limites par segment légèrement inférieures. Chaque réponse indique le segments résolu : le nombre de count facturables, l'encoding et le nombre de caractères. Les segments sont l'unité facturée ; voir coût.
Lorsque des caractères typographiques sont la seule raison pour laquelle un corps sort de GSM-7, l'encodage intelligent peut réduire son nombre de segments. Définissez options.smart_encoding sur true et Bird remplace les guillemets courbes, tirets, points de suspension et caractères similaires par des équivalents GSM-7 avant l'envoi. Il est désactivé par défaut parce qu'il modifie le corps que vous avez composé.
Pour le jeu de caractères complet, les caractères de la table d'extension qui occupent deux emplacements, le dimensionnement des emoji, ce que l'encodage intelligent remplace et l'arithmétique des segments, voir Limites de caractères.

Envoi par lot

POST /v1/sms/batches envoie jusqu'à 100 messages indépendants en une seule requête. Les requêtes par lot utilisent la politique de limitation du débit sms_batch, distincte de la politique sms_send pour les envois unitaires. Le corps est un objet JSON dont le tableau messages contient les objets de message décrits dans Construire le payload :
const result = await bird.sms.sendBatch({
  messages: [
    {
      from: "+15557654321",
      to: "+15551111111",
      text: "Hi Alice!",
      category: "marketing",
    },
    {
      from: "+15557654321",
      to: "+15552222222",
      text: "Hi Bob!",
      category: "marketing",
    },
  ],
});
La validation est tout ou rien : si un message du lot est invalide, la requête entière est rejetée avec un 422 et rien n'est envoyé, de sorte qu'un lot ne s'applique jamais partiellement. En cas de succès, la réponse 202 contient chaque message accepté dans l'ordre de soumission sous data, ainsi qu'un summary avec le accepted_count. Chaque message est ensuite indépendant : l'échec d'un destinataire n'affecte jamais les autres.

Le modèle asynchrone : ce que signifie 202

Un envoi réussi renvoie 202 Accepted avec un identifiant de message et status: accepted. Les erreurs de requête sont renvoyées immédiatement : un champ invalide, un corps dépassant la limite de segments, un pays de destination que vous n'avez pas activé ou un expéditeur invalide renvoie un 422. Un espace de travail sans solde de portefeuille reçoit un 402.
La livraison est asynchrone. Le message passe à sent lorsque Bird le transmet à l'opérateur. Un accusé de réception définit ensuite delivered, undelivered, failed ou expired via les événements et webhooks et les endpoints de lecture. Cette conception a trois conséquences :
  • Le coût est calculé après l'acceptation. Le cost d'un message est null au moment de l'acceptation et est renseigné une fois que Bird tarifie l'envoi pendant le traitement. Relisez le message, ou attendez l'événement de livraison, pour voir le montant facturé à ce stade ; coût et facturation détaille les composants et les cas où l'un reste non tarifé.
  • Un message peut être rejeté après le 202. Si la facturation échoue pendant le traitement, le message passe à rejected avec un webhook sms.rejected et vous n'êtes pas facturé ; un portefeuille épuisé apparaît sous last_error.code: insufficient_balance.
  • Les lectures peuvent brièvement suivre le 202 avec un léger décalage. Le message devient visible sur les endpoints de lecture peu après le 202, de sorte qu'un 404 immédiatement après un envoi se résout en quelques instants.

Champs réservés

Bird rejette actuellement les champs de requête suivants avec 422 SMSUnsupportedFeature :
scheduled_at, validity_period, media_urls, messaging_profile_id, broadcast_id, campaign_id, audience_id, contact_id, topic_id, personalization, options.max_price_per_segment, options.track_clicks
N'incluez pas ces champs dans un envoi.

Réessayer en toute sécurité

Envoyez l'en-tête Idempotency-Key avec une valeur unique par envoi logique. Si une requête réussit sans renvoyer de réponse, rejouez la même requête avec la même clé. Bird renvoie le résultat d'origine au lieu d'envoyer un message en double. Consultez idempotency pour le format de clé et la durée de rétention.

Coût et facturation

Les SMS sortants (SMS) sont facturés par segment. Le montant dépend du pays et de l'opérateur de destination ; certaines routes ajoutent un surcoût tiers, comme les frais d'opérateur 10DLC aux États-Unis.
Le cost d'un message décompose le montant en composants nommés. transaction_amount est le montant facturé par Bird pour acheminer le message, passthrough_amount est tout frais tiers répercuté, et amount est la somme des composants tarifés, libellée en currency_code. Un composant non encore tarifé est null plutôt que "0.00000", de sorte qu'un message dont le surcoût n'a jamais été résolu affiche amount comme le seul coût d'acheminement. La référence du message documente chaque champ.
Le surcoût est calculé au mieux. Bird le résout lors de l'enregistrement de l'accusé de réception, dans une fenêtre de temps limitée. S'il n'est pas résolu dans cette fenêtre, passthrough_amount reste null de façon permanente : Bird ne réessaye pas, et amount reste le coût d'acheminement seul.
Les SMS entrants (SMS) sont facturés sur deux lignes : le tarif entrant par segment et un surcoût opérateur entrant le cas échéant. Les deux sont indiqués dans le cost du message reçu : le tarif sous transaction_amount, le surcoût sous passthrough_amount. Contrairement à son équivalent sortant, le surcoût entrant est tarifé à l'acceptation du message et non à la livraison, de sorte qu'il n'est jamais renseigné ultérieurement.
Consultez le coût et les segments par message dans le journal SMS.

Étapes suivantes

  • Templates SMS : envoyez un template intégré et laissez Bird choisir l'expéditeur.
  • Journal SMS : trouvez un message et examinez son cycle de vie, ses segments et son coût.
  • Événements : recevez les événements de livraison dans vos systèmes.
  • Métriques SMS : surveillez le taux de livraison, le taux d'échec et le volume accepté.
  • Idempotency : réessayez en toute sécurité avec l'en-tête Idempotency-Key.
  • Envoyer votre premier SMS : une vidéo qui vous guide pas à pas dans la même configuration depuis le dashboard.