REST v2

Cuándo elegir REST v2

Elija REST v2 para nuevas integraciones de SMS, especialmente para flujos de trabajo de alto volumen o asíncronos, ya que ofrece seguimiento basado en UUID, patrones de solicitud modernos y las devoluciones de llamada DLR necesarias para una gestión fiable del estado de entrega; elija REST v1 only when you need compatibility with an existing v1 integration.

Descripción general

Nuestra API RESTv2 de Mobile Gateway le permite enviar mensajes SMS.

La diferencia entre REST y REST v2 radica en un enfoque más moderno, diseñado para la escalabilidad y la mensajería asíncrona. DLR callback Se requieren URL para recibir códigos de error.

El uso de HTTPS es obligatorio; todos los intentos de utilizar HTTP en texto plano se redirigirán a HTTPS. Los datos de las solicitudes y respuestas requieren codificación JSON. Solo se requieren los métodos HTTP GET y POST.

Lo que la API puede hacer

  • Enviar mensajes SMS a un único dispositivo móvil
  • Programar mensajes SMS para su envío posterior
  • Realizar el seguimiento de los mensajes enviados mediante identificadores UUID
  • Recuperar los detalles de los mensajes enviados
  • Recibir devoluciones de llamada (callbacks) para mensajes entrantes (MO)
  • Recibir devoluciones de llamada (callbacks) de confirmación de entrega para actualizaciones del estado del mensaje

Cómo funciona

En la práctica, la API sigue un flujo de trabajo sencillo:

  1. Autenticarse con las credenciales de la API REST v2 de Mobile Gateway.
  2. Enviar una solicitud JSON para enviar, programar o recuperar un mensaje.
  3. Almacenar el ID de mensaje (UUID) devuelto por la API.
  4. Utilizar el UUID para recuperar los detalles del mensaje o conciliar las devoluciones de llamada (callbacks) de confirmación de entrega.
  5. Configurar las URL de callback para que la aplicación pueda recibir mensajes entrantes y eventos de estado de entrega.

Cuándo utilizar la API REST v2

Utilice REST API v2 cuando su aplicación requiera una integración moderna de SMS mediante HTTPS, con procesamiento asíncrono y seguimiento de mensajes basado en UUID. Es una opción ideal para nuevos sistemas de mensajería transaccional, alertas operativas, envíos programados y flujos de trabajo de alto volumen que requieran conciliar los resultados de entrega mediante callbacks.

Por lo general, se recomienda optar por REST API v2 para nuevas integraciones. REST v1 resulta útil principalmente cuando se mantiene una integración existente que ya depende de endpoints, callbacks o formatos de respuesta propios de la versión v1.

Antes de empezar

Antes de realizar su primera solicitud, confirme lo siguiente:

  1. Dispone de credenciales para la API REST v2 de Mobile Gateway.
  2. Su URL de devolución de llamada (callback) de DLR está configurada para eventos de estado de entrega.
  3. La dirección IP de su servidor está autorizada si la lista blanca de IP está habilitada.
  4. Los números de móvil tienen formato internacional; por ejemplo, +1-829-555-1234.
  5. Sus solicitudes utilizan HTTPS y codificación JSON.

Primera ruta de solicitud exitosa

Para la mayoría de las implementaciones, la forma más rápida de validar la conectividad y la configuración es:

  1. Autenticarse utilizando las credenciales de la API REST v2.
  2. Enviar una solicitud POST sencilla a /messages con los parámetros destination y content.
  3. Confirmar la respuesta 202 Accepted y guardar el ID del mensaje (UUID) devuelto.
  4. Recuperar el mensaje mediante GET /messages?id={message_id}.

Autenticación

Se utiliza autenticación básica HTTP para todas las solicitudes. Si accede a la API sin las credenciales correctas o sin permiso para acceder a ella, recibirá una respuesta HTTP 401.

Las credenciales de su aplicación de puerta de enlace («nombre de la aplicación» y contraseña) están disponibles en la plataforma: https://omni.modicagroup.com/gateway/api_config/restv2

Necesitará un nombre de usuario y una contraseña para obtenerlas.

Si aún no dispone de estos datos, póngase en contacto con support@modicagroup.com.

Direcciones IP autorizadas

Puede incluir las direcciones IP o los rangos de IP de sus servidores en la lista de permitidos utilizando el botón «Add IP Address» (Añadir dirección IP) situado bajo la sección «Authorised IP Addresses» (Direcciones IP autorizadas).

Nota importante: una vez que se haya añadido una o varias direcciones IP o rangos de IP, se rechazarán las conexiones provenientes de cualquier otra dirección IP; cualquier intento de conexión desde una IP que no figure en la lista dará lugar a un error de autenticación.

Base URI

Todo el acceso a la API se realiza a través de HTTPS y desde:

https://api.modicagroup.com/rest/sms/v2

Versiones

La versión de la API REST es actualmente la v2.

Accept: application/json

Especificación OpenAPI

La especificación OpenAPI (Swagger) se puede encontrar en here.

Puede ver ejemplos de código y un desglose de la especificación. here.

Códigos de error

Pueden producirse los siguientes errores:

Código Descripción
send_failed No se pudo poner el mensaje en cola debido a un error desconocido.
invalid_json Datos JSON no válidos en el cuerpo de la solicitud
missing_attrib Falta un atributo obligatorio
invalid_attrib Valor de atributo no válido
400 Marca de tiempo programada no válida (debe cumplir con RFC3339)
422 Marca de tiempo programada no válida (no debe ser anterior al momento actual)

Cadenas de fecha

Fecha completa más horas, minutos, segundos y zona horaria.

YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
     YYYY = four-digit year
     MM   = two-digit month (01=January, etc.)
     DD   = two-digit day of month (01 through 31)
     hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
     mm   = two digits of minute (00 through 59)
     ss   = two digits of second (00 through 59)
     s    = one or more digits representing a decimal fraction of a second
     TZD  = time zone designator (Z or +hh:mm or -hh:mm)

Enviando mensajes

SEnvío a un único destino

Para enviar un mensaje MT a un único teléfono móvil, envíe una solicitud POST:

POST /messages

{
  "destination": "+6412345678",
  "content": "El contenido de tu mensaje SMS con un texto muy largo https://a.urltoshorten.com/thatislongerthanthemaximummessagelength?withparameters=likethisone integrado en el texto"
}
infoEl formato del número debe ser el formato internacional e.g. +64211234567 / +61414123456 / +18123456789. El formato internacional suele implicar eliminar el cero inicial (de los números locales) y sustituirlo por el código de país precedido de un signo más ( + ).
infoSegún las instrucciones de URI base anteriores, todo el acceso a la API se realiza a través de HTTPS y se accede desde https://api.modicagroup.com/rest/sms/v2 – e.g. the full URI to send MT messages is https://api.modicagroup.com/rest/sms/v2/messages

Atributos opcionales:

{
  "scheduled": str: 2017-05-05T10:00:00+12:00,
  "source": str:short-code,
  "reference": str:alt-reference,
  "class": str:application-class,
  "mask": str:source-mask,
  "sms_class": int:0-3,
  "expires": str: 2017-05-05T10:00:00+12:00
}
infoEl atributo class tiene como valor predeterminado mt_message.
infoEl límite máximo para los mensajes programados es de 60 días.

En caso de éxito:

HTTP/1.1 202 Accepted
Content-Type: application/json

{"id":"1e41f423-24cf-4fa2-9a8a-888c30653305","status":"accepted","detail":"+6412345678"}
infoTodos los ID de mensaje se devolverán como UUID.

En caso de error de validación:

HTTP/1.1 400 Bad Request

{
  "error": str:error-code
  "error-desc": [str:error-desc]
}
{
  "error-desc": "Invalid scheduled timestamp (must be less than 60 days)",
  "error": "invalid_attrib"
}

Ejemplo de envío de mensaje SMS

Este ejemplo envía un mensaje SMS utilizando la API REST v2.

curl -v \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -u 'gw_username:abcde12345' \
  -d '{"destination": "+64211234567", "content": "Hello world!"}' \
  https://{apiDomainName}/rest/sms/v2/messages
const credentials = btoa("gw_username:abcde12345");

const response = await fetch("https://{apiDomainName}/rest/sms/v2/messages", {
  method: "POST",
  headers: {
    "Accept": "application/json",
    "Authorization": `Basic ${credentials}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    destination: "+64211234567",
    content: "Hello world!"
  })
});

const result = await response.json();
import requests
import json
from base64 import b64encode

uri = 'https://{apiDomainName}/rest/sms/v2/messages'
username = "gw_username"
password = "abcde12345"

# Token de autorización
def basic_auth(username, password):
    token = b64encode(f"{username}:{password}".encode('utf-8')).decode("ascii")
    return f'Basic {token}'

headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization' : basic_auth(username, password)
}

json_payload = json.dumps({
  "destination": "+64211234567",
  "content": "Hello world!"
})

response = requests.post(uri, headers=headers, data=json_payload)

if response.status_code == 202:
    print(response.json())
else:
    print("Error:", response.status_code, response.text)
<?php
$payload = json_encode([
    "destination" => "+64211234567",
    "content" => "Hello world!"
]);

$ch = curl_init("https://{apiDomainName}/rest/sms/v2/messages");
curl_setopt($ch, CURLOPT_USERPWD, "gw_username:abcde12345");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Accept: application/json",
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
require "json"
require "net/http"
require "uri"

uri = URI("https://{apiDomainName}/rest/sms/v2/messages")
request = Net::HTTP::Post.new(uri)
request.basic_auth("gw_username", "abcde12345")
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request.body = {
  destination: "+64211234567",
  content: "Hello world!"
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

String token = Base64.getEncoder()
    .encodeToString("gw_username:abcde12345".getBytes(StandardCharsets.UTF_8));

String payload = """
{
  "destination": "+64211234567",
  "content": "Hello world!"
}
""";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://{apiDomainName}/rest/sms/v2/messages"))
    .header("Accept", "application/json")
    .header("Authorization", "Basic " + token)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(payload))
    .build();

HttpResponse<String> response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes("gw_username:abcde12345"));

var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://{apiDomainName}/rest/sms/v2/messages");
request.Headers.Accept.ParseAdd("application/json");
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
request.Content = new StringContent(
    """{"destination":"+64211234567","content":"Hello world!"}""",
    Encoding.UTF8,
    "application/json");

var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();

Output:

{'id': '287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c', 'status': 'accepted', 'detail': '+64211234567'}

Recuperación de un mensaje SMS

Para recuperar un mensaje, envíe una solicitud GET:

GET /messages?id=[str:message-id]

If a match is found:

HTTP/1.1 200 OK
Location: https://api.modicagroup.com/rest/sms/v2/messages?id=[str:message-id]

{
  "id": str:message-id,
  "source": str:mobile-number|short-code,
  "destination": str:mobile-number|short-code,
  "content": str:text-message
  "status": str:status
}

Additional attributes are added if available:

{
  "reference": str:alt-reference,
}

If not found:

HTTP/1.1 404 Not Found

Obtener ejemplo de mensaje SMS

Este ejemplo recupera un mensaje SMS utilizando la API REST v2.

curl -v \
  -H 'Accept: application/json' \
  -u 'gw_username:abcde12345' \
  'https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c'
const credentials = btoa("gw_username:abcde12345");

const response = await fetch("https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c", {
  method: "GET",
  headers: {
    "Accept": "application/json",
    "Authorization": `Basic ${credentials}`
  }
});

const message = await response.json();
import requests
import json
from base64 import b64encode

uri = 'https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c'
username = "gw_username"
password = "abcde12345"

# Token de autorización
def basic_auth(username, password):
    token = b64encode(f"{username}:{password}".encode('utf-8')).decode("ascii")
    return f'Basic {token}'

headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization' : basic_auth(username, password)
}

response = requests.get(uri, headers=headers)

if response.status_code == 200:
    print(response.json())
else:
    print("Error:", response.status_code, response.text)
<?php
$ch = curl_init("https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c");
curl_setopt($ch, CURLOPT_USERPWD, "gw_username:abcde12345");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
require "json"
require "net/http"
require "uri"

uri = URI("https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c")
request = Net::HTTP::Get.new(uri)
request.basic_auth("gw_username", "abcde12345")
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

message = JSON.parse(response.body)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

String token = Base64.getEncoder()
    .encodeToString("gw_username:abcde12345".getBytes(StandardCharsets.UTF_8));

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c"))
    .header("Accept", "application/json")
    .header("Authorization", "Basic " + token)
    .GET()
    .build();

HttpResponse<String> response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes("gw_username:abcde12345"));

var request = new HttpRequestMessage(
    HttpMethod.Get,
    "https://{apiDomainName}/rest/sms/v2/messages?id=287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c");
request.Headers.Accept.ParseAdd("application/json");
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);

var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();

Output:

{'id': '287c3a15-c9a8-4a14-b6de-e7a3f06b9b0c', source: '202', destination: '+64211234567', 'reference': '', 'content': 'Hello world!', 'status': 'accepted'}

Devolución de llamada MO

Solo recibirás mensajes MO si has configurado una URL de callback para MO en tu API Configuration.

Recomendamos utilizar https:// para tus URL de devolución de llamada.

infoImportante: Si su URL de devolución de llamada incluye credenciales de autenticación, asegúrese de que todos los caracteres especiales estén correctamente codificados para URL. Para obtener más información, visite https://www.w3schools.com/tags/ref_urlencode.asp
warningNOTA: El certificado de seguridad debe coincidir con el nombre de dominio que se está utilizando; los certificados autofirmados no se verificarán y generarán errores.

Cuando se recibe un mensaje MO dirigido a usted, se realiza una solicitud POST a la URL de callback de MO; dicho callback incluirá los detalles del mensaje MO como un objeto JSON en el cuerpo de la solicitud POST.

POST callback-url

{
  "id": str($uuid):message-id,
  "source": str:mobile-number,
  "destination": str:short-code,
  "content": str:text-message,
  "operator": str:operator-name
}
infoTodos los ID de mensaje se devolverán como UUID.

En caso de que el mensaje sea una respuesta a un mensaje MT, se añade un atributo adicional “reply_to” (solo cuando se utiliza una secuencia numérica y el mensaje MO es una respuesta a un mensaje MT):

{
  "reply_to": str:message-id
}

Si el mensaje contiene un campo reply_to y el mensaje MT incluía una referencia, se añadirá un parámetro adicional:

{
  "reference": str:reference
}

Si el mensaje del terminal contiene contenido binario, se proporcionará un atributo adicional:

{
  "encoding": str:encoding-type
}

Se proporcionará el valor “base64” para los mensajes que contengan datos binarios. El contenido se suministrará codificado en base64; es necesario decodificarlo para obtener los datos originales. NOTA: Los mensajes SMS estándar con contenido en GSM de 7 bits o Unicode no incluirán este parámetro.

Si el mensaje del terminal se envió como un mensaje concatenado (multiparte) y no llegaron todas sus partes, se proporcionarán dos atributos adicionales:

{
  "total_parts": int:total-parts,
  "received_parts": int:received-parts
}

“total_parts” es la cantidad de partes que componían el mensaje y “received_parts” es cuántas de esas partes llegaron antes de dejar de esperar las restantes. Ambos atributos se proporcionan siempre juntos, y “received_parts” siempre será menor que “total_parts”.

El contenido suministrado es lo que se pudo armar con las partes que sí llegaron, por lo que falta parte del texto que escribió el remitente. Las partes que se perdieron no son necesariamente las últimas, por lo que el contenido puede empezar o terminar a mitad de una oración, o presentar un vacío intermedio. NOTA: Los mensajes que llegaron completos no incluirán estos parámetros, se hayan enviado como mensaje concatenado o no.

Si procesa el contenido como datos estructurados (por ejemplo, JSON), lo más probable es que un mensaje incompleto no se pueda analizar. Estos atributos le permiten distinguir un mensaje incompleto de un contenido que realmente está mal formado.

Devolución de llamada de DLR

Solo recibirá mensajes de estado DLR si ha configurado una URL de devolución de llamada DLR en su API Configuration.

Recomendamos utilizar https:// para las URL de devolución de llamada.

infoImportante: Si su URL de devolución de llamada incluye credenciales de autenticación, asegúrese de que todos los caracteres especiales estén correctamente codificados para URL. Para obtener más información, visite https://www.w3schools.com/tags/ref_urlencode.asp
warningNOTA: El certificado de seguridad debe coincidir con el nombre de dominio que se está utilizando; los certificados autofirmados no se verificarán y generarán errores.

Cuando se recibe un mensaje DLR para usted, se realiza una solicitud POST a la URL de callback de DLR; dicho callback incluirá los detalles del estado del DLR como un objeto JSON en el cuerpo de la solicitud POST.

POST callback-url

{
  "message_id": str($uuid):message-id,
  "status": str:dlr-status
  "detail": str:detail
}
infoTodos los ID de mensaje se devolverán como UUID.

En caso de que el mensaje MT contenga una referencia, se añade un atributo «reference» adicional:

{
  "reference": str:alt-reference
}

Estado del mensaje DLR

A continuación se presentan los códigos de estado devueltos en los DLR que admite nuestra pasarela de mensajería.

Estado Descripción
sent El mensaje ha sido enviado por el transportista.
received El mensaje ha sido recibido.
rejected El operador rechazó el mensaje.
expired El operador no pudo entregar el mensaje en el plazo especificado; por ejemplo, cuando el teléfono estaba apagado.

Cannot_Route (Error al enrutar el mensaje)

Un error Cannot_Route (Error al enrutar el mensaje) indica que el Mobile Gateway no puede enrutar tu mensaje. La causa más común es usar la versión incorrecta de la API REST para tu Gateway.

Antes de investigar más a fondo, confirma lo siguiente:

  1. Estás utilizando la versión correcta de la API REST (RESTv1 o RESTv2) para tu Gateway.

  2. El número de móvil de destino es válido y está soportado por tu Gateway.

  3. Su Gateway está configurado para enviar mensajes al país de destino. Este error puede ocurrir si el envío de mensajes a ese país no está habilitado en la configuración de su API.

  4. La fuente configurada (ID del remitente o número virtual) coincide con la configuración de tu Gateway.

  5. La clase de mensaje es válida para la configuración de tu Gateway. Por ejemplo, no envíes un SMS usando una clase de mensaje de correo electrónico u otra clase que tu Gateway no esté configurado para aceptar.

Si el problema persiste después de verificar la configuración de tu Gateway y los parámetros de la solicitud, por favor contacta a <mailto:{{< supportEmail >}}> para obtener más asistencia.

Estado del mensaje omnicanal

A continuación se presentan los códigos de estado que admite nuestra pasarela de mensajes y que pueden visualizarse en los informes de Omni; no todos los operadores admiten la totalidad de estos códigos.

Estado Descripción
submitted Mensaje enviado correctamente al operador para su entrega
sent El mensaje ha sido enviado por el transportista
received El mensaje ha sido recibido
frozen Un error transitorio ha bloqueado este mensaje
rejected El operador rechazó el mensaje
failed La entrega del mensaje ha fallado debido a un problema de conectividad del operador
dead Mensaje asesinado por una administradora
expired El operador no pudo entregar el mensaje en el plazo especificado; por ejemplo, cuando el teléfono estaba apagado.