Vous cherchez Sinch Engage ? Vous êtes maintenant sur le site principal de Sinch. Retourner à Sinch Engage

Développeurs

Migrer de l’API SMS de Sinch vers l’API de conversation

Image pour Migrer de l’API SMS de Sinch vers l’API de conversation

Si votre code envoie des requêtes POST à https://us.sms.api.sinch.com/xms/v1/{service_plan_id}/batches ou appelle sms.batches.send dans un SDK Sinch, il utilise l’API SMS indépendante de Sinch, parfois appelée XMS. La fin de commercialisation de l’API SMS a eu lieu le 15 avril 2026. Les intégrations déjà basées sur celle-ci continuent de fonctionner, mais les nouvelles intégrations doivent utiliser l’API de conversation de Sinch, même sur un compte qui a déjà utilisé l’API SMS. Le API de conversation envoie le même SMS via le même abonnement et le même numéro, et le même format de requête couvre le RCS, WhatsApp et les autres canaux. Cet article mappe une intégration API SMS vers l’API de conversation point par point, à l’aide de requêtes exécutées sur les deux API avec le même abonnement. Si vous repartez de zéro, Envoyer des SMS avec l’API de conversation de Sinch en curl, Node.js et Python est la voie la plus rapide.

Ce dont vous aurez besoin

  • Votre abonnement API SMS existant et les numéros qui y sont associés
  • L’accès à l’API de conversation dans le tableau de bord Sinch (ouvrez « Conversation API » (API de conversation) dans le menu de gauche et cliquez sur « GET ACCESS » (Obtenir l’accès) si ce n’est pas encore fait)
  • curl et jq pour les exemples shell, ou Node.js 20 ou version ultérieure avec @sinch/sdk-core pour les exemples Node.js

Lier votre abonnement à une application API de conversation

Vous n’avez pas besoin d’un nouveau numéro. L’API de conversation envoie des SMS via une application, et le canal SMS de l’application pointe vers un abonnement SMS. Pointez-le vers celui que vous possédez déjà.

La liaison modifie la destination des callbacks de l’abonnement. Les URL de callback de l’abonnement doivent être supprimées avant de pouvoir le lier. Ensuite, les messages entrants sont dirigés vers le webhook de l’API de conversation de l’application, et les rapports de livraison pour les lots que vous envoyez toujours via l’API SMS ne vous parviennent que si le lot définit sa propre callback_url. Configurez d’abord le webhook de l’application et essayez-le sur un abonnement de test avant le passage en production, si vous en avez un.

Les étapes :

  1. Accédez à « Conversation API » (API de conversation), puis à « Apps » (Applications), et créez une application dans la même région que votre abonnement. L’API de conversation fonctionne aux États-Unis, dans l’UE et au Brésil. Si votre abonnement se trouve dans une autre région de l’API SMS, comme l’Australie ou le Canada, demandez à votre responsable de compte Sinch quelle région de l’API de conversation utiliser avant de commencer.
  2. Dans l’application, cliquez sur « SET UP CHANNEL » (Configurer le canal) sur la ligne SMS et choisissez votre abonnement existant. Si des URL de callback sont configurées pour l’abonnement, le tableau de bord ne le liera pas tant que vous ne les aurez pas supprimées sous SMS, « Service APIs » (API de service), « Callback URLs » (URL de callback). Cela inclut le remplacement de « Incoming URL » (URL entrante), et pas seulement de « Default URL » (URL par défaut). Configurez le webhook de l’application avant de faire cela (voir Rapports de livraison), car l’abonnement cesse d’envoyer des callbacks à votre ancien point de terminaison à partir de ce moment.
  3. Accédez à Paramètres, puis à Clés d’accès, et créez une clé d’accès. Copiez l’ID de la clé et le secret. Le secret ne s’affiche qu’une seule fois.

Copiez l’ID de l’application depuis l’application et l’ID de projet depuis « Settings » (Paramètres), « Project Settings » (Paramètres du projet). Ceux-ci remplacent l’ID d’abonnement et le jeton d’API dans votre code :

API SMSAPI de conversation
https://{region}.sms.api.sinch.comhttps://{region}.conversation.api.sinch.com
ID d’abonnement dans le chemin d’accèsID de projet dans le chemin d’accès, ID d’application dans le corps
Jeton d’API comme jeton au porteurClé d’accès (ID de clé et secret) échangée contre un jeton OAuth 2.0

Le jeton provient d’une requête et est valide pendant environ une heure :

                                

                                    export SINCH_ACCESS_TOKEN=$(curl --silent --show-error --fail-with-body \
  https://auth.sinch.com/oauth2/token \
  --user "$SINCH_KEY_ID:$SINCH_KEY_SECRET" \
  --data grant_type=client_credentials | jq -r .access_token)
                                
                            

Les SDK demandent et actualisent le jeton pour vous.

Envoyer un message

Voici un appel typique de l’API SMS : un destinataire, un rapport de livraison par destinataire et une référence pour associer le rapport à une commande.

                                

                                    curl --silent --show-error --fail-with-body \
  "https://us.sms.api.sinch.com/xms/v1/$SINCH_SERVICE_PLAN_ID/batches" \
  --header "Authorization: Bearer $SINCH_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "from": "+12025550123",
    "to": ["+15551234567"],
    "body": "Your order has shipped",
    "delivery_report": "per_recipient",
    "client_reference": "order-1042"
  }'
                                
                            
                                

                                    {"body":"Your order has shipped","canceled":false,"client_reference":"order-1042","created_at":"2026-10-28T11:57:15.529Z","delivery_report":"per_recipient","expire_at":"2026-10-31T11:57:15.529Z","flash_message":false,"from":"46765106280","id":"01M615Y8W9CRFH0SVQBS9KVK7F","modified_at":"2026-10-28T11:57:15.529Z","to":["46706855785"],"type":"mt_text"}
                                
                            

Le même message avec l’API de conversation :

                                

                                    curl --silent --show-error --fail-with-body \
  "https://us.conversation.api.sinch.com/v1/projects/$SINCH_PROJECT_ID/messages:send" \
  --header "Authorization: Bearer $SINCH_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "app_id": "YOUR_APP_ID",
    "recipient": {
      "identified_by": {
        "channel_identities": [{ "channel": "SMS", "identity": "+15551234567" }]
      }
    },
    "message": { "text_message": { "text": "Your order has shipped" } },
    "channel_properties": { "SMS_SENDER": "+12025550123" },
    "message_metadata": "order-1042"
  }'
                                
                            
                                

                                    {"message_id":"01M613S632MAAMWRVFEHPQ4YMA","accepted_time":"2026-10-28T11:19:31.682Z"}
                                
                            

Quatre éléments ont changé. from est devenu la propriété de canal SMS_SENDER. to est devenu un unique recipient, avec le nom du canal indiqué à côté du numéro. client_reference est devenu message_metadata, qui est renvoyé dans le rapport de livraison. delivery_report a disparu de la requête : les rapports de livraison proviennent d’un webhook sur l’application, abordé plus loin.

La réponse a également changé. L’API SMS renvoie un lot avec un id. L’API de conversation renvoie un message_id pour le message unique, et c’est à cet ID que les rapports de livraison font référence.

Dans Node.js, le changement se situe au niveau des options du client et de la méthode. Avant, avec l’API SMS :

                                

                                    import { SinchClient } from "@sinch/sdk-core";

// Before: the standalone SMS API, authenticated with a service plan ID and API token.
const sinchClient = new SinchClient({
  servicePlanId: process.env.SINCH_SERVICE_PLAN_ID ?? "",
  apiToken: process.env.SINCH_API_TOKEN ?? "",
  smsRegion: "us",
});

const batch = await sinchClient.sms.batches.sendTextMessage({
  sendSMSRequestBody: {
    from: "+12025550123",
    to: ["+15551234567"],
    body: "Your order has shipped",
    delivery_report: "per_recipient",
    client_reference: "order-1042",
  },
});

console.log(`Sent batch ${batch.id}`);
                                
                            

Après, avec l’API de conversation :

                                

                                    import { SinchClient } from "@sinch/sdk-core";

// After: the Conversation API, authenticated with a project ID and access key.
const sinchClient = new SinchClient({
  projectId: process.env.SINCH_PROJECT_ID ?? "",
  keyId: process.env.SINCH_KEY_ID ?? "",
  keySecret: process.env.SINCH_KEY_SECRET ?? "",
  conversationRegion: "us",
});

const response = await sinchClient.conversation.messages.sendTextMessage({
  sendMessageRequestBody: {
    app_id: process.env.SINCH_APP_ID ?? "",
    recipient: {
      identified_by: {
        channel_identities: [{ channel: "SMS", identity: "+15551234567" }],
      },
    },
    message: { text_message: { text: "Your order has shipped" } },
    channel_properties: { SMS_SENDER: "+12025550123" },
    message_metadata: "order-1042",
  },
});

console.log(`Sent message ${response.message_id}`);
                                
                            

Les deux utilisent @sinch/sdk-core, vous pouvez donc les exécuter côte à côte dans une même base de code pendant que vous migrez les flux. Les exemples omettent la validation des entrées pour garder la comparaison lisible. Le requête POST d’envoi de SMS contient la version complète avec des vérifications d’environnement et la validation des numéros.

Champ par champ

Les champs que la plupart des intégrations API SMS utilisent et leur nouvel emplacement :

Champ de l’API SMSAPI de conversation
fromchannel_properties.SMS_SENDER ou l’expéditeur par défaut de l’abonnement
to (tableau)recipient (un par requête), ou l’API Batch pour plusieurs destinataires
bodymessage.text_message.text
client_referencemessage_metadata, renvoyé dans les rapports de livraison. correlation_id est également transmis aux réponses entrantes
delivery_reportUn webhook MESSAGE_DELIVERY sur l’application
callback_urlcallback_url dans la requête. Le SDK Python l’appelle event_destination_target
parametersAPI Batch recipient_and_params[].parameters
send_atAPI Batch send_after, jusqu’à sept jours à l’avance
flash_messagechannel_properties.SMS_FLASH_MESSAGE: "true"
max_number_of_message_partschannel_properties.SMS_MAX_NUMBER_OF_MESSAGE_PARTS
id du lotmessage_id par message, ou batch_id via l’API Batch

Les valeurs des propriétés de canal sont des chaînes de caractères, donc SMS_FLASH_MESSAGE prend la valeur "true", et non true. Si vous envoyez des SMS binaires avec type: mt_binary et un UDH, consultez la Propriétés du canal SMS pour votre cas d’usage avant de migrer ce flux.

Envoyer à plusieurs destinataires

L’API SMS accepte jusqu’à 1 000 numéros dans to et remplit les parameters par destinataire. Sur l’API de conversation, messages:send prend un seul destinataire. Pour une poignée de messages, bouclez sur vos destinataires et envoyez une requête pour chacun. Pour une vraie liste, utilisez l’ API Batch de conversation : un message, jusqu’à 1 000 destinataires, chacun avec ses propres paramètres.

                                

                                    #!/usr/bin/env bash
# Send one templated SMS to several recipients with the Conversation Batch API.
# Requires SINCH_ACCESS_TOKEN from https://auth.sinch.com/oauth2/token.
set -euo pipefail

: "${SINCH_ACCESS_TOKEN:?Set SINCH_ACCESS_TOKEN}"
: "${SINCH_PROJECT_ID:?Set SINCH_PROJECT_ID}"
: "${SINCH_APP_ID:?Set SINCH_APP_ID}"
: "${SINCH_SMS_SENDER:?Set SINCH_SMS_SENDER}"
region="${SINCH_REGION:-us}"

body=$(jq -n \
  --arg app_id "$SINCH_APP_ID" \
  --arg sender "$SINCH_SMS_SENDER" \
  '{
    app_id: $app_id,
    message: { text_message: { text: "Hi ${name}, your order has shipped" } },
    channel_properties: { SMS_SENDER: $sender },
    recipient_and_params: [
      {
        recipient: { identified_by: { channel_identities: [{ channel: "SMS", identity: "+15551234567" }] } },
        parameters: { name: "Ana" }
      },
      {
        recipient: { identified_by: { channel_identities: [{ channel: "SMS", identity: "+15557654321" }] } },
        parameters: { name: "Sam" }
      }
    ]
  }')

curl --silent --show-error --fail-with-body \
  "https://$region.conversationbatch.api.sinch.com/v1/projects/$SINCH_PROJECT_ID/messages" \
  --header "Authorization: Bearer $SINCH_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --data "$body"
echo
                                
                            
                                

                                    {"batch_id":"01M613S8XFQAP5EAX93J9QHX1W","send_after":"2026-10-28T11:19:34Z"}
                                
                            

La syntaxe des espaces réservés est ${name}, identique à celle des paramètres de l’API SMS. L’API Batch possède son propre hôte, conversationbatch.api.sinch.com. Pour planifier le lot, ajoutez send_after avec une heure UTC jusqu’à sept jours à l’avance. Le message de chaque destinataire obtient son propre message_id et son propre rapport de livraison, avec l’ID du lot dans les metadata du rapport.

Utilisez le chemin d’accès /v1/. Les points de terminaison v1alpha et v1beta de l’API Batch cesseront de fonctionner le 16 décembre 2026, le code écrit pour ceux-ci doit donc également être migré vers /v1/.

Rapports de livraison

Sur l’API SMS, vous définissez delivery_report sur chaque lot et obtenez les rapports à l’URL de callback de l’abonnement. Sur l’API de conversation, les rapports sont envoyés aux webhooks de l’application, et vous les choisissez par déclencheur. Ajoutez-en un avec MESSAGE_DELIVERY pour les rapports et MESSAGE_INBOUND pour les réponses :

                                

                                    curl --silent --show-error --fail-with-body \
  "https://us.conversation.api.sinch.com/v1/projects/$SINCH_PROJECT_ID/webhooks" \
  --header "Authorization: Bearer $SINCH_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "app_id": "YOUR_APP_ID",
    "target": "https://example.com/sinch/callbacks",
    "target_type": "HTTP",
    "triggers": ["MESSAGE_DELIVERY", "MESSAGE_INBOUND"]
  }'
                                
                            

Un rapport de livraison se présente ainsi :

                                

                                    {
  "app_id": "YOUR_APP_ID",
  "project_id": "YOUR_PROJECT_ID",
  "message_delivery_report": {
    "message_id": "01M613S632MAAMWRVFEHPQ4YMA",
    "conversation_id": "",
    "status": "DELIVERED",
    "channel_identity": {
      "channel": "SMS",
      "identity": "46706855785",
      "app_id": "",
      "nrs_data": { "mcc": "240", "mnc": "07", "country": "SE" }
    },
    "contact_id": "",
    "metadata": "order-1042",
    "processing_mode": "DISPATCH"
  }
}
                                
                            

La liste des statuts est plus courte que celle de l’API SMS. Un SMS passe de QUEUED_ON_CHANNEL à DELIVERED ou FAILED. Un rapport FAILED contient un champ reason avec un code et une description expliquant la cause de l’échec. Votre recherche sur client_reference devient une recherche sur metadata.

Le numéro de téléphone dans channel_identity.identity est renvoyé sans le + initial, même si vous l’avez envoyé à +46706855785. L’API SMS fait de même dans ses rapports, le code qui effectue déjà une correspondance sur le recipient continue donc de fonctionner une fois qu’il lit le nouveau champ. contact_id et conversation_id sont vides car l’application s’exécute en mode Dispatch.

Sinch effectue de nouvelles tentatives sur un webhook qui ne renvoie pas de code 2xx, gardez donc le gestionnaire idempotent : utilisez message_id et status pour ignorer les rapports que vous avez déjà traités.

Messages entrants

Les réponses à votre numéro arrivent sur le webhook de l’application avec le déclencheur MESSAGE_INBOUND. Le texte se trouve sous message.contact_message.text_message.text et le numéro de l’expéditeur sous message.channel_identity.identity. Si votre code pour l’API SMS lit body et from depuis un callback entrant, ce sont les deux chemins à modifier.

Une fois l’abonnement lié, son URL de callback par défaut pointe vers l’API de conversation, et les réponses à ses numéros sont dirigées vers le webhook de l’API de conversation de l’application. Elles apparaissent toujours dans la liste des messages entrants de l’API SMS (GET /xms/v1/{service_plan_id}/inbounds), de sorte que le code qui lit cette liste continue de fonctionner pendant la migration.

Migrer un flux à la fois

Quelques choix permettent de rendre la migration moins risquée.

Commencer par les notifications sortantes

Les notifications unidirectionnelles, telles que les mises à jour d’expédition et les rappels, nécessitent le moins de modifications : un envoi et un rapport de livraison. Migrez-les en premier et conservez les flux bidirectionnels sur l’API SMS jusqu’à ce que le webhook soit en place et testé. Les deux API fonctionnent avec le même abonnement pendant que vous effectuez la migration.

Donner aux envois de l’API SMS leur propre callback_url pendant la migration

Une fois l’abonnement lié, son URL de callback par défaut appartient à l’API de conversation. Les rapports de livraison pour les messages que vous envoyez toujours via l’API SMS n’atteignent pas le webhook de votre application, et l’abonnement n’a aucune autre URL de callback vers laquelle les envoyer. Définissez callback_url sur chaque lot de l’API SMS nécessitant encore des rapports, et ils continueront d’arriver à votre point de terminaison au format de l’API SMS. Vous pouvez également les récupérer avec GET /xms/v1/{service_plan_id}/batches/{batch_id}/delivery_report.

Conserver les valeurs de client_reference dans message_metadata

Si vos rapports, votre base de données ou un outil de support se basent sur client_reference, placez la même valeur dans message_metadata. Les rapports des deux API correspondront alors aux mêmes enregistrements lors de la migration, et aucun élément en aval n’a besoin de savoir quelle API a envoyé le message.

Envoyer à des numéros de téléphone avec identified_by

Les nouvelles applications de l’API de conversation s’exécutent en mode Dispatch, qui ne stocke pas les contacts. Cela correspond au fonctionnement de l’API SMS : vous envoyez à un numéro et obtenez un rapport pour ce numéro. L’utilisation de identified_by avec le numéro de téléphone fonctionne dans les deux modes, vous n’avez donc pas à modifier votre modèle de données pour effectuer la migration.

Résolution de problèmes

  • Erreur 404 de l’API de conversation. La région indiquée dans l’URL ne correspond pas à celle de l’application. L’application n’est accessible que dans la région où vous l’avez créée.
  • Le canal SMS signale des erreurs. L’application et l’abonnement doivent se trouver dans la même région. Si elles diffèrent, recréez l’application dans la région de l’abonnement et configurez-y le canal SMS.
  • Les callbacks n’arrivent plus à votre ancien point de terminaison. L’association a supprimé les URL de callback de l’abonnement. Pour les messages entrants et les envois via l’API de conversation, vérifiez que l’application possède un webhook avec les déclencheurs MESSAGE_DELIVERY et MESSAGE_INBOUND, et qu’il renvoie un code 2xx. Pour les lots que vous envoyez toujours via l’API SMS, définissez callback_url sur le lot, comme décrit dans Migrer un flux à la fois. Pour voir vers quoi l’abonnement pointe, ouvrez SMS, « Service APIs » (API de service), sélectionnez l’abonnement et regardez sous « Callback URLs » (URL de callback).
  • L’envoi avec contact_id échoue. L’application est en mode Dispatch, qui ne stocke pas les contacts. Envoyez plutôt avec identified_by et le numéro de téléphone.
  • Erreur 400 de l’API Batch concernant les paramètres. Un espace réservé dans le message n’a pas de valeur pour l’un des destinataires. Chaque ${name} du texte nécessite une clé correspondante dans les parameters de chaque destinataire.

Prochaines étapes

Une fois l’application en place, vous pouvez y ajouter le RCS ou WhatsApp, attribuer au destinataire une identité pour chaque canal dans channel_identities, lister les canaux dans channel_priority_order et vous rabattre sur le SMS pour les destinataires qui n’en disposent pas. Le page des concepts clés explique le fonctionnement du repli.

Ressources complémentaires