¿Buscas Sinch Engage? Ahora estás en el sitio web principal de Sinch. Volver a Sinch Engage

Desarrolladores

Migra de la API de SMS de Sinch a la API de conversación

Imagen para Migra de la API de SMS de Sinch a la API de conversación

Si tu código envía solicitudes a https://us.sms.api.sinch.com/xms/v1/{service_plan_id}/batches o llama a sms.batches.send en un SDK de Sinch, está usando la API de SMS independiente de Sinch, que a veces se denomina XMS. La API de SMS dejó de comercializarse el 15 de abril de 2026. Las integraciones ya creadas en ella siguen funcionando, pero las nuevas integraciones deben utilizar la API de conversación de Sinch, incluso en una cuenta que ya haya utilizado la API de SMS. La API de conversación envía el mismo SMS a través del mismo plan de servicio y número, y el mismo formato de solicitud sirve para RCS, WhatsApp y los demás canales. Este artículo detalla la migración de una integración de la API de SMS a la API de conversación paso a paso, con solicitudes ejecutadas en ambas API bajo el mismo plan de servicio. Si empiezas desde cero, Enviar SMS con la API de conversación de Sinch en curl, Node.js y Python es el camino más rápido.

Qué necesitas

  • Tu plan de servicio de la API de SMS actual y sus números
  • Acceso a la API de conversación en el panel de control de Sinch (abre «Conversation API» [API de conversación] en el menú de la izquierda y haz clic en «GET ACCESS» [Obtener acceso] si aún no lo has hecho)
  • curl y jq para los ejemplos de shell, o Node.js 20 o superior con @sinch/sdk-core para los ejemplos de Node.js

Vincula tu plan de servicio a una aplicación de la API de conversación

No necesitas un número nuevo. La API de conversación envía SMS mediante una aplicación, y el canal de SMS de la aplicación apunta a un plan de servicio de SMS. Apúntalo al que ya tienes.

La vinculación cambia adónde van los callbacks del plan de servicio. Las URL de los callbacks del plan deben eliminarse antes de poder vincularlo. Después, los mensajes entrantes van al webhook de la API de conversación de la aplicación, y los informes de entrega de los lotes que sigues enviando mediante la API de SMS solo te llegarán si el lote configura su propia callback_url. Configura primero el webhook de la aplicación y pruébalo en un plan de servicio de prueba antes de pasarlo a producción si tienes uno.

Los pasos:

  1. Ve a «Conversation API» [API de conversación], luego a «Apps» [Aplicaciones] y crea una aplicación en la misma región que tu plan de servicio. La API de conversación funciona en EE. UU., la UE y Brasil. Si tu plan de servicio está en otra región de la API de SMS, como Australia o Canadá, pregunta a tu gestor/a de cuentas de Sinch qué región de la API de conversación debes utilizar antes de empezar.
  2. En la aplicación, haz clic en «SET UP CHANNEL» [Configurar canal] en la fila de SMS y elige tu plan de servicio existente. Si el plan tiene configuradas URL de callback, el panel de control no lo vinculará hasta que las elimines en «SMS» [SMS], «Service APIs» [API de servicio], «Callback URLs» [URL de callback]. Esto incluye la anulación de «Incoming URL» [URL entrante], no solo la «Default URL» [URL predeterminada]. Configura el webhook de la aplicación antes de hacerlo (consulta Informes de entrega), porque a partir de ese momento el plan dejará de enviar callbacks a tu antiguo punto de conexión.
  3. Ve a Ajustes, luego a Claves de acceso y crea una clave de acceso. Copia el ID de la clave y el secreto. El secreto solo se muestra una vez.

Copia el ID de la aplicación en la aplicación y el ID del proyecto en «Settings» [Ajustes], «Project Settings» [Ajustes del proyecto]. Estos sustituyen al ID del plan de servicio y al token de API en tu código:

API de SMSAPI de conversación
https://{region}.sms.api.sinch.comhttps://{region}.conversation.api.sinch.com
ID del plan de servicio en la rutaID de proyecto en la ruta, ID de aplicación en el cuerpo
Token de API como token de portadorClave de acceso (ID de clave y secreto) intercambiada por un token de OAuth 2.0

El token proviene de una solicitud y dura alrededor de una hora:

                                

                                    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)
                                
                            

Los SDK solicitan y actualizan el token por ti.

Enviar un mensaje

Esta es una llamada típica de la API de SMS: un destinatario, un informe de entrega por destinatario y una referencia para vincular el informe a un pedido.

                                

                                    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"}
                                
                            

El mismo mensaje con la API de conversación:

                                

                                    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"}
                                
                            

Han cambiado cuatro cosas. from se ha convertido en la propiedad de canal SMS_SENDER. to se ha convertido en un único recipient, con el canal indicado junto al número. client_reference se ha convertido en message_metadata, que se devuelve en el informe de entrega. delivery_report ha desaparecido de la solicitud: los informes de entrega provienen de un webhook en la aplicación, como se explica a continuación.

La respuesta también ha cambiado. La API de SMS devuelve un lote con un id. La API de conversación devuelve un message_id para el mensaje, y ese es el ID al que hacen referencia los informes de entrega.

En Node.js, el cambio está en las opciones del cliente y en el método. Antes, con la API de 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}`);
                                
                            

Después, con la API de conversación:

                                

                                    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}`);
                                
                            

Ambos usan @sinch/sdk-core, por lo que puedes ejecutarlos en paralelo en una misma base de código mientras transfieres los flujos. Los ejemplos omiten la validación de entrada para que la comparación sea fácil de leer. La post sobre el envío de SMS tiene la versión completa con verificaciones de entorno y validación de números.

Campo por campo

Los campos que usan la mayoría de las integraciones de la API de SMS y dónde van:

Campo de la API de SMSAPI de conversación
fromchannel_properties.SMS_SENDER, o el remitente predeterminado del plan de servicio
to (matriz)recipient (uno por solicitud), o la Batch API para muchos destinatarios
bodymessage.text_message.text
client_referencemessage_metadata, devuelto en los informes de entrega. correlation_id también llega a las respuestas entrantes
delivery_reportUn webhook MESSAGE_DELIVERY en la aplicación
callback_urlcallback_url en la solicitud. El SDK de Python lo llama event_destination_target
parametersBatch API recipient_and_params[].parameters
send_atBatch API send_after, con hasta siete días de antelación
flash_messagechannel_properties.SMS_FLASH_MESSAGE: "true"
max_number_of_message_partschannel_properties.SMS_MAX_NUMBER_OF_MESSAGE_PARTS
id del lotemessage_id por mensaje, o batch_id de la Batch API

Los valores de propiedad del canal son cadenas, por lo que SMS_FLASH_MESSAGE toma "true", no true. Si envías un SMS binario con type: mt_binary y un UDH, comprueba la Propiedades del canal de SMS para tu caso de uso antes de trasladar ese flujo.

Enviar a muchos destinatarios

La API de SMS admite hasta 1000 números en to y rellena los parameters por destinatario. En la API de conversación, messages:send toma un destinatario. Para unos pocos mensajes, itera sobre tus destinatarios y envía una solicitud a cada uno. Para una lista real, utiliza la Batch API de conversación: un mensaje, hasta 1000 destinatarios, cada uno con sus propios parámetros.

                                

                                    #!/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 sintaxis del marcador de posición es ${name}, la misma que la de los parámetros de la API de SMS. La Batch API tiene su propio host, conversationbatch.api.sinch.com. Para programar el lote, añade send_after con una hora UTC de hasta siete días de antelación. El mensaje de cada destinatario obtiene su propio message_id y su propio informe de entrega, con el ID del lote en los metadata del informe.

Usa la ruta /v1/. Los puntos de conexión de la Batch API v1alpha y v1beta dejarán de funcionar el 16 de diciembre de 2026, por lo que el código escrito para ellos también debe trasladarse a /v1/.

Informes de entrega

En la API de SMS, configuras delivery_report en cada lote y obtienes los informes en la URL de callback del plan de servicio. En la API de conversación, los informes van a los webhooks de la aplicación y tú los eliges por disparador. Añade uno con MESSAGE_DELIVERY para los informes y MESSAGE_INBOUND para las respuestas:

                                

                                    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 informe de entrega tiene este aspecto:

                                

                                    {
  "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 lista de estados es más corta que la de la API de SMS. Un SMS pasa de QUEUED_ON_CHANNEL a DELIVERED o FAILED. Un informe con el estado FAILED tiene un reason con un código y una descripción que indican el motivo. Tu búsqueda de client_reference se convierte en una búsqueda en metadata.

El número de teléfono en channel_identity.identity se devuelve sin el + inicial, incluso si lo enviaste a +46706855785. La API de SMS hace lo mismo en sus informes, por lo que el código que ya coincide con recipient seguirá funcionando una vez que lea desde el campo nuevo. contact_id y conversation_id están vacíos porque la aplicación se ejecuta en modo Dispatch.

Sinch reintenta un webhook que no devuelve un código 2xx, así que mantén el controlador de forma idempotente: usa message_id y status para omitir los informes que ya has procesado.

Mensajes entrantes

Las respuestas a tu número llegan al webhook de la aplicación con el disparador MESSAGE_INBOUND. El texto está en message.contact_message.text_message.text y el número del remitente en message.channel_identity.identity. Si tu código de la API de SMS lee body y from desde un callback entrante, esas son las dos rutas que debes cambiar.

Una vez vinculado el plan de servicio, su URL de callback predeterminada apunta a la API de conversación, y las respuestas a sus números van al webhook de la API de conversación de la aplicación. Siguen apareciendo en la lista de entradas de la API de SMS (GET /xms/v1/{service_plan_id}/inbounds), por lo que el código que lee esa lista sigue funcionando durante el traslado.

Traslada un flujo cada vez

Algunas decisiones hacen que el traslado sea menos arriesgado.

Empieza con las notificaciones salientes

Las notificaciones unidireccionales, como las actualizaciones de envío y los recordatorios, necesitan muy pocos cambios: un envío y un informe de entrega. Traslada estas primero y mantén los flujos bidireccionales en la API de SMS hasta que el webhook esté configurado y probado. Ambas API funcionan con el mismo plan de servicio durante el traslado.

Asigna su propia callback_url a los envíos de la API de SMS durante el traslado

Una vez que se ha vinculado el plan de servicio, su URL de callback predeterminada pertenece a la API de conversación. Los informes de entrega de los mensajes que sigues enviando mediante la API de SMS no llegan al webhook de tu aplicación, y el plan no tiene otra URL de callback adonde enviarlos. Configura callback_url en cada lote de la API de SMS que todavía necesite informes, y estos seguirán llegando a tu punto de conexión en el formato de la API de SMS. También puedes obtenerlos con GET /xms/v1/{service_plan_id}/batches/{batch_id}/delivery_report.

Mantén los valores de client_reference en message_metadata

Si tus informes, tu base de datos o una herramienta de asistencia se basan en client_reference, pon el mismo valor en message_metadata. De este modo, los informes de ambas API se asignan a los mismos registros durante el traslado, y nada de lo que ocurra después tiene que saber qué API ha enviado el mensaje.

Envía a números de teléfono con identified_by

Las nuevas aplicaciones de la API de conversación se ejecutan en modo Dispatch, que no almacena contactos. Esto coincide con la forma en que funciona la API de SMS: envías a un número y recibes un informe para ese número. identified_by con el número de teléfono funciona en cualquier modo, de forma que no tienes que cambiar tu modelo de datos para trasladarte.

Solución de problemas

  • 404 de la API de conversación. La región de la URL no coincide con la región de la aplicación. Solo se puede acceder a la aplicación en la región en la que la creaste.
  • El canal de SMS informa de errores. La aplicación y el plan de servicio deben estar en la misma región. Si difieren, vuelve a crear la aplicación en la región del plan de servicio y configura el canal de SMS allí.
  • Los callbacks han dejado de llegar a tu antiguo punto de conexión. Al realizar la vinculación, se han eliminado las URL de callback del plan. En los mensajes entrantes y los envíos a la API de conversación, comprueba que la aplicación tenga un webhook con los disparadores MESSAGE_DELIVERY y MESSAGE_INBOUND y que devuelva un 2xx. Para los lotes que sigues enviando mediante la API de SMS, configura callback_url en el lote, como se describe en Traslada un flujo cada vez. Para ver a qué apunta el plan, abre «SMS«, «Service APIs» (API de servicio), selecciona el plan y busca en «Callback URLs» (URL de callback).
  • Los envíos de contact_id fallan. La aplicación está en modo Dispatch, que no almacena contactos. En su lugar, envía con identified_by y el número de teléfono.
  • 400 de la Batch API sobre parámetros. Un marcador de posición del mensaje no tiene valor para uno de los destinatarios. Cada ${name} en el texto necesita una clave coincidente en los parameters de cada destinatario.

Próximos pasos

Una vez implementada la aplicación, puedes añadir RCS o WhatsApp a esta, proporcionar al destinatario una identidad para cada canal en channel_identities, enumerar los canales en channel_priority_order y recurrir al SMS como alternativa para los destinatarios que no los tengan. La página de conceptos clave explica cómo funciona la alternativa.

Recursos adicionales