Verificación OTP

Verificación en dos pasos (OTP): códigos de un solo uso por SMS, WhatsApp o llamada de voz — una sola integración para los tres canales. El parámetro channel elige el transporte en cada llamada, y el reenvío acepta otro canal con el mismo código: el clic en "No recibí el código" de tu app se resuelve repitiendo la misma petición, con cobertura total de números. WhatsApp sale por la integración oficial de SMS Masivos: sin cuenta de WhatsApp Business ni verificación de Meta. La API genera, guarda, expira y valida los códigos por ti.

El flujo completo usa un solo recurso, /v2/otp, con verbos explícitos:

  1. POST /v2/otp genera y envía el código — y también reenvía (mismo código) o rota (code_rotate: true) según el estado.
  2. POST /v2/otp/verify comprueba el código que el usuario capturó.
  3. GET /v2/otp/status consulta el estado sin efectos secundarios.
  4. DELETE /v2/otp invalida la verificación activa (no envía nada).

Usa estos endpoints para códigos de login, verificación de cuenta, 2FA y recuperación de contraseña. No construyas un sistema OTP manual sobre /sms/send: perderías la generación, expiración, validación y control de intentos que este flujo ya maneja. Guía completa en Verificación OTP.

Reglas del flujo: cada código admite 7 intentos de verificación; al agotarlos el estado pasa a locked y se destraba rotando el código (code_rotate: true). Entre envíos aplica un cooldown de 30 segundos (otp_throttled con Retry-After si no esperas). El código expira a las 24 horas por defecto, con un máximo de 3 días (expiration_date).

A diferencia del resto de la API, estos endpoints responden con status HTTP semántico: 201/200 en éxito y 4xx/5xx reales en error, siempre con un slug estable en error, una sugerencia accionable en hint y los endpoints sugeridos en next. La respuesta te dice qué hacer a continuación.

Enviar Código de Verificación (OTP)
POST /v2/otp
Invalidar Verificación (OTP)
DEL /v2/otp
Verificar Código (OTP)
POST /v2/otp/verify
Consultar Estado de Verificación (OTP)
GET /v2/otp/status

Enviar Código de Verificación (OTP)

POST https://api.smsmasivos.com.mx/v2/otp
Genera y envía un código de verificación por SMS, WhatsApp o llamada de voz. Este único endpoint maneja todo el ciclo: la primera llamada crea el código, y el botón "No recibí el código" de tu app se resuelve repitiendo la misma llamada — incluso con otro channel: el mismo código sale por el canal nuevo y cubres los números que no reciben SMS. La respuesta siempre te dice qué hizo (action) y qué sigue (next).

Para probar, basta con phone_number, country_code y company — el código llega por SMS en segundos. Con code_show: 1 la respuesta incluye el código y puedes automatizar la prueba sin leer el teléfono.

Parameters
phone_numberstringrequerido
Número de teléfono a verificar (hasta 10 dígitos, sin código de país). En México siempre son 10 dígitos.
country_codestringrequerido
Código de país, numérico. Para México envía 52.
channelenumopcional

Canal de entrega del código:

  • sms (default): mensaje de texto.
  • whatsapp: mensaje de WhatsApp oficial con plantilla fija (ignora message y company). No requiere cuenta de WhatsApp Business ni verificación de Meta: sale por la integración oficial de SMS Masivos (remitente Authenticate).
  • voice: llamada que dicta el código dígito por dígito.

En un reenvío puedes cambiar de canal: el mismo código pendiente sale por el canal nuevo (fallback).

smswhatsappvoice
companystringopcional
Nombre de tu empresa o app, mostrado al usuario en el mensaje. Obligatorio con channel: sms y voice (requisito de operadores); se ignora con whatsapp.
messagestringopcional

Texto propio del mensaje (opcional, solo sms y voice). Debe incluir los placeholders {{code}} y {{company}}, usar solo caracteres GSM-7 (sin emojis ni acentos raros) y no exceder 160 caracteres ya con el código y la empresa sustituidos.

Si no lo envías se usa el texto default: {{code}} es tu codigo de verificacion de {{company}}. No lo compartas.

code_formatenumopcional

Formato del código generado:

  • numeric (default): solo números.
  • alphanumeric: letras y números.
  • letters: solo letras.
numericalphanumericletters
code_lengthintegeropcional
Longitud del código (4 a 10 caracteres). Por defecto 6.
code_rotatebooleanopcional
true descarta el código vigente y genera uno nuevo (nueva ronda con 7 intentos). Sin él, un código vigente se reenvía tal cual. El cooldown de 30s aplica igual.
code_showenumopcional

Devuelve el código generado en el campo code de la respuesta:

  • 0 (default): no devolver.
  • 1: devolver (pruebas/automatización del lado del servidor).
01
expiration_datestringopcional
Fecha de expiración del código, formato YYYY-MM-DD HH:mm:ss (futura). Por defecto 24 horas; máximo 3 días (si envías más, se ajusta al máximo).

Qué hace cada llamada

El endpoint decide según el estado del número — tú solo repites el POST:

Estado del númeroQué haceHTTPaction
Sin verificación activa (o expirada)Crea y envía un código nuevo.201created
Código vigenteReenvía el mismo código.200resent
Código vigente + code_rotate: trueDescarta el anterior y genera uno nuevo (7 intentos frescos).200restarted
Ya verificadoInicia un ciclo nuevo.201restarted

Entre envíos aplica un cooldown de 30 segundos (con o sin code_rotate); si no esperas, recibes 429 otp_throttled con el tiempo restante.

Dependencias entre parámetros

  • channel: sms y voice requieren company; whatsapp la ignora (plantilla oficial fija) y responde con warning.
  • message solo aplica a sms y voice, y debe incluir {{code}} y {{company}}.

code_show: 1 está pensado para pruebas y automatización del lado del servidor. Nunca reenvíes esa respuesta al navegador o a la app del usuario: si el código regresa al mismo cliente que lo va a capturar, el flujo deja de probar la posesión del teléfono.

Cómo leer los errores

Cada error llega con su status HTTP real, un slug estable en error, una sugerencia accionable en hint y los endpoints sugeridos en next:

HTTPerrorCuándo ocurreQué hacer
400otp_missing_param / otp_invalid_paramFalta un parámetro, es inválido, o enviaste uno de la API anterior (voice, whatsapp, template).El hint indica el parámetro exacto.
400otp_invalid_channelchannel no es sms, whatsapp ni voice.Corrige el valor.
400otp_message_invalidmessage sin {{code}}/{{company}}, con caracteres fuera de GSM-7, o que excede 160 caracteres ya expandido.El hint detalla la regla incumplida.
402otp_insufficient_creditsSin saldo para enviar (incluye code: sms_07).Recarga saldo.
429otp_throttledCooldown de reenvío activo.Espera resend_available_in segundos (también en el header Retry-After).
429otp_max_attemptsLa ronda está bloqueada por intentos agotados y no enviaste code_rotate.Rota el código con code_rotate: true.
502otp_send_failedEl canal no pudo entregar el mensaje.Reintenta; si persiste, contacta a soporte con el request_id.

Los errores de autenticación (auth_*) vienen de la capa común de la API y llegan con HTTP 200 y el detalle en el body — consulta Errores y límites.

curl -X POST https://api.smsmasivos.com.mx/v2/otp \
  -H "Content-Type: application/json" \
  -H "apikey: TU_API_KEY" \
  -d '{
    "phone_number": "5512345678",
    "country_code": "52",
    "company": "Mi Empresa"
  }'
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.smsmasivos.com.mx/v2/otp');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'apikey: ' . getenv('SMSMASIVOS_API_KEY')
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'phone_number' => '5512345678',
    'country_code' => '52',
    'company' => 'Mi Empresa'
]));
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status . ' ' . $response;
import requests

response = requests.post(
    'https://api.smsmasivos.com.mx/v2/otp',
    headers={
        'Content-Type': 'application/json',
        'apikey': 'TU_API_KEY'
    },
    json={
        'phone_number': '5512345678',
        'country_code': '52',
        'company': 'Mi Empresa'
    }
)
print(response.status_code, response.json())
const response = await fetch('https://api.smsmasivos.com.mx/v2/otp', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'apikey': process.env.SMSMASIVOS_API_KEY
  },
  body: JSON.stringify({
    phone_number: '5512345678',
    country_code: '52',
    company: 'Mi Empresa'
  })
});
const data = await response.json();
console.log(response.status, data);
const axios = require('axios');

const { status, data } = await axios.post(
  'https://api.smsmasivos.com.mx/v2/otp',
  {
    phone_number: '5512345678',
    country_code: '52',
    company: 'Mi Empresa'
  },
  {
    headers: {
      'Content-Type': 'application/json',
      'apikey': process.env.SMSMASIVOS_API_KEY
    },
    validateStatus: () => true
  }
);
console.log(status, data);
require 'net/http'
require 'json'

uri = URI('https://api.smsmasivos.com.mx/v2/otp')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.path, {
  'Content-Type' => 'application/json',
  'apikey' => ENV['SMSMASIVOS_API_KEY']
})
request.body = {
  phone_number: '5512345678',
  country_code: '52',
  company: 'Mi Empresa'
}.to_json

response = http.request(request)
puts "#{response.code} #{JSON.parse(response.body)}"
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("apikey", "TU_API_KEY");

var payload = new
{
    phone_number = "5512345678",
    country_code = "52",
    company = "Mi Empresa"
};

var response = await client.PostAsJsonAsync(
    "https://api.smsmasivos.com.mx/v2/otp",
    payload
);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"{(int)response.StatusCode} {result}");
OkHttpClient client = new OkHttpClient();

String json = "{"
    + "\"phone_number\":\"5512345678\","
    + "\"country_code\":\"52\","
    + "\"company\":\"Mi Empresa\""
    + "}";

Request request = new Request.Builder()
    .url("https://api.smsmasivos.com.mx/v2/otp")
    .post(RequestBody.create(json, MediaType.parse("application/json")))
    .addHeader("apikey", "TU_API_KEY")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.code() + " " + response.body().string());
Response
{
  "success": true,
  "state": "pending",
  "action": "created",
  "message": "Código OTP creado y enviado.",
  "hint": "El código llega en segundos. Reenvía con POST /v2/otp si no llegó.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 7,
  "resend_available_in": 30,
  "warning": "channel=whatsapp usa una plantilla oficial fija; se ignoraron message/company.",
  "code": "483920",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": true,
  "state": "pending",
  "action": "created",
  "message": "Código OTP creado y enviado.",
  "hint": "El código llega en segundos. Reenvía con POST /v2/otp si no llegó.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 7,
  "resend_available_in": 30,
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "state": "pending",
  "error": "otp_incorrect_code",
  "message": "El código es incorrecto.",
  "hint": "Código incorrecto. Te quedan 3 intentos.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 3,
  "resend_available_in": 18,
  "code": "sms_07",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "state": "none",
  "error": "otp_insufficient_credits",
  "message": "Saldo insuficiente para enviar el código.",
  "hint": "Recarga saldo para enviar el código.",
  "next": [],
  "code": "sms_07"
}
{
  "success": false,
  "state": "pending",
  "error": "otp_incorrect_code",
  "message": "El código es incorrecto.",
  "hint": "Código incorrecto. Te quedan 3 intentos.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 3,
  "resend_available_in": 18,
  "code": "sms_07",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "error": "otp_internal",
  "message": "Ocurrió un error inesperado.",
  "hint": "Intenta de nuevo en unos momentos.",
  "next": []
}
{
  "success": false,
  "state": "none",
  "error": "otp_send_failed",
  "message": "No se pudo enviar el código. Intenta de nuevo.",
  "hint": "No se pudo enviar el código. Intenta de nuevo.",
  "next": []
}

Invalidar Verificación (OTP)

DEL https://api.smsmasivos.com.mx/v2/otp
Invalida la verificación activa del número (el código vigente deja de servir). No envía ningún mensaje. Útil para limpiar el estado antes de un nuevo ciclo o al dar de baja un flujo.

Este endpoint no envía ningún mensaje. Invalida el código vigente y borra el estado de verificación del número, dejándolo en none. El siguiente POST /v2/otp inicia un ciclo limpio.

Casos típicos: cancelar un flujo a petición del usuario, limpiar el estado tras un cambio de número, o resetear escenarios en tus pruebas automatizadas.

Parameters
phone_numberstringrequerido
Número cuya verificación quieres invalidar.
country_codestringrequerido
Código de país, numérico. Para México envía 52.

Si no había verificación activa, la respuesta sigue siendo 200 con action: deleted — la operación es idempotente desde el punto de vista de tu integración: después de llamarla, el estado del número siempre es none.

Los errores de autenticación (auth_*) vienen de la capa común de la API y llegan con HTTP 200 y el detalle en el body — consulta Errores y límites.

curl -X DELETE https://api.smsmasivos.com.mx/v2/otp \
  -H "Content-Type: application/json" \
  -H "apikey: TU_API_KEY" \
  -d '{
    "phone_number": "5512345678",
    "country_code": "52"
  }'
import requests

response = requests.delete(
    'https://api.smsmasivos.com.mx/v2/otp',
    headers={
        'Content-Type': 'application/json',
        'apikey': 'TU_API_KEY'
    },
    json={
        'phone_number': '5512345678',
        'country_code': '52'
    }
)
print(response.status_code, response.json())
const response = await fetch('https://api.smsmasivos.com.mx/v2/otp', {
  method: 'DELETE',
  headers: {
    'Content-Type': 'application/json',
    'apikey': process.env.SMSMASIVOS_API_KEY
  },
  body: JSON.stringify({
    phone_number: '5512345678',
    country_code: '52'
  })
});
const data = await response.json();
console.log(response.status, data);
Response
{
  "success": true,
  "state": "none",
  "action": "deleted",
  "message": "El OTP pendiente fue invalidado.",
  "hint": "No se envió ningún mensaje.",
  "next": [
    "/v2/otp"
  ],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "error": "otp_missing_param",
  "message": "Falta un parámetro obligatorio.",
  "hint": "Envía 'phone_number' (hasta 10 dígitos).",
  "next": []
}
{
  "success": false,
  "error": "otp_internal",
  "message": "Ocurrió un error inesperado.",
  "hint": "No se pudo invalidar el OTP. Intenta de nuevo.",
  "next": []
}

Verificar Código (OTP)

POST https://api.smsmasivos.com.mx/v2/otp/verify
Comprueba el código que capturó el usuario. Si coincide, el número queda verificado (state: verified). Cada código admite 7 intentos; al agotarlos la verificación se bloquea (locked) hasta rotar el código con POST /v2/otp y code_rotate: true.

Llama a este endpoint cuando el usuario capture el código que recibió. Envía el mismo phone_number y country_code que usaste al crear el código: si el status HTTP es 200, el número quedó verificado.

Parameters
phone_numberstringrequerido
El mismo número usado al enviar el código.
country_codestringrequerido
El mismo código de país usado al enviar. Para México 52.
codestringrequerido
El código que capturó el usuario.

Intentos y bloqueo

Cada código admite 7 intentos de verificación. Al agotarlos, la verificación pasa a locked (HTTP 429) y la única salida es generar un código nuevo con POST /v2/otp y code_rotate: true. Muestra attempts_remaining al usuario para que sepa cuántos intentos le quedan, y no implementes reintentos automáticos.

Cómo leer los errores

El status HTTP distingue cada caso — puedes ramificar tu código directamente sobre él:

HTTPerrorCuándo ocurreQué hacer
401otp_incorrect_codeEl código no coincide (quedan intentos).Permite reintentar; la respuesta trae attempts_remaining.
404otp_not_foundNo hay verificación activa para el número.Inicia el flujo con POST /v2/otp.
409otp_already_verifiedEl número ya estaba verificado.Trátalo como éxito, o invalida con DELETE /v2/otp para un nuevo ciclo.
410otp_code_expiredEl código venció.Genera uno nuevo con POST /v2/otp.
429otp_max_attemptsSe agotaron los 7 intentos de la ronda.Rota el código: POST /v2/otp con code_rotate: true.
400otp_missing_param / otp_invalid_paramFalta code, phone_number o country_code, o enviaste un parámetro que no aplica aquí.El hint indica el parámetro exacto.

Los errores de autenticación (auth_*) vienen de la capa común de la API y llegan con HTTP 200 y el detalle en el body — consulta Errores y límites.

curl -X POST https://api.smsmasivos.com.mx/v2/otp/verify \
  -H "Content-Type: application/json" \
  -H "apikey: TU_API_KEY" \
  -d '{
    "phone_number": "5512345678",
    "country_code": "52",
    "code": "483920"
  }'
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.smsmasivos.com.mx/v2/otp/verify');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'apikey: ' . getenv('SMSMASIVOS_API_KEY')
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'phone_number' => '5512345678',
    'country_code' => '52',
    'code' => '483920'
]));
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status . ' ' . $response;
import requests

response = requests.post(
    'https://api.smsmasivos.com.mx/v2/otp/verify',
    headers={
        'Content-Type': 'application/json',
        'apikey': 'TU_API_KEY'
    },
    json={
        'phone_number': '5512345678',
        'country_code': '52',
        'code': '483920'
    }
)
if response.status_code == 200:
    print('Número verificado')
else:
    print(response.status_code, response.json())
const response = await fetch('https://api.smsmasivos.com.mx/v2/otp/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'apikey': process.env.SMSMASIVOS_API_KEY
  },
  body: JSON.stringify({
    phone_number: '5512345678',
    country_code: '52',
    code: '483920'
  })
});
const data = await response.json();
console.log(response.status, data);
const axios = require('axios');

const { status, data } = await axios.post(
  'https://api.smsmasivos.com.mx/v2/otp/verify',
  {
    phone_number: '5512345678',
    country_code: '52',
    code: '483920'
  },
  {
    headers: {
      'Content-Type': 'application/json',
      'apikey': process.env.SMSMASIVOS_API_KEY
    },
    validateStatus: () => true
  }
);
console.log(status, data);
require 'net/http'
require 'json'

uri = URI('https://api.smsmasivos.com.mx/v2/otp/verify')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.path, {
  'Content-Type' => 'application/json',
  'apikey' => ENV['SMSMASIVOS_API_KEY']
})
request.body = {
  phone_number: '5512345678',
  country_code: '52',
  code: '483920'
}.to_json

response = http.request(request)
puts "#{response.code} #{JSON.parse(response.body)}"
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("apikey", "TU_API_KEY");

var payload = new
{
    phone_number = "5512345678",
    country_code = "52",
    code = "483920"
};

var response = await client.PostAsJsonAsync(
    "https://api.smsmasivos.com.mx/v2/otp/verify",
    payload
);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"{(int)response.StatusCode} {result}");
OkHttpClient client = new OkHttpClient();

String json = "{"
    + "\"phone_number\":\"5512345678\","
    + "\"country_code\":\"52\","
    + "\"code\":\"483920\""
    + "}";

Request request = new Request.Builder()
    .url("https://api.smsmasivos.com.mx/v2/otp/verify")
    .post(RequestBody.create(json, MediaType.parse("application/json")))
    .addHeader("apikey", "TU_API_KEY")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.code() + " " + response.body().string());
Response
{
  "success": true,
  "state": "verified",
  "action": "verified",
  "message": "Código verificado correctamente.",
  "hint": "",
  "next": [],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "error": "otp_missing_param",
  "message": "Falta un parámetro obligatorio.",
  "hint": "Envía 'code' (el código que ingresó el usuario).",
  "next": []
}
{
  "success": false,
  "state": "pending",
  "error": "otp_incorrect_code",
  "message": "El código es incorrecto.",
  "hint": "Código incorrecto. Te quedan 3 intentos.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "attempts_remaining": 3
}
{
  "success": false,
  "state": "none",
  "error": "otp_not_found",
  "message": "No hay una verificación activa para este número.",
  "hint": "No hay una verificación activa. Inícia con POST /v2/otp.",
  "next": [
    "/v2/otp"
  ]
}
{
  "success": false,
  "state": "verified",
  "error": "otp_already_verified",
  "message": "Este número ya está verificado.",
  "hint": "Este número ya está verificado.",
  "next": []
}
{
  "success": false,
  "state": "expired",
  "error": "otp_code_expired",
  "message": "El código OTP expiró.",
  "hint": "El código expiró. Solicita uno nuevo con POST /v2/otp.",
  "next": [
    "/v2/otp"
  ]
}
{
  "success": false,
  "state": "locked",
  "error": "otp_max_attempts",
  "message": "Se superó el máximo de intentos de verificación.",
  "hint": "Se agotaron los intentos. Genera un código nuevo con POST /v2/otp (code_rotate=true).",
  "next": [
    "/v2/otp"
  ],
  "attempts_remaining": 0
}
{
  "success": false,
  "error": "otp_internal",
  "message": "Ocurrió un error inesperado.",
  "hint": "Intenta de nuevo en unos momentos.",
  "next": []
}

Consultar Estado de Verificación (OTP)

GET https://api.smsmasivos.com.mx/v2/otp/status
Devuelve el estado actual de la verificación de un número sin efectos secundarios: no envía mensajes, no consume intentos, no reinicia nada. Úsalo para decidir qué mostrar en tu UI (habilitar el botón de reenvío, mostrar intentos restantes, etc.).

Consulta de solo lectura: no envía mensajes, no consume intentos, no altera el estado. Ideal para construir tu UI de verificación:

  • resend_available_in te dice cuándo habilitar el botón de "Reenviar código" (0 = ya disponible).
  • attempts_remaining te dice cuántos intentos mostrarle al usuario.
  • state te dice qué pantalla corresponde: captura de código (pending), éxito (verified), pedir código nuevo (expired, locked) o iniciar flujo (none).

Los parámetros van como query string (es un GET).

Query parameters
phone_numberstringrequerido
Número cuyo estado quieres consultar.
country_codestringrequerido
Código de país, numérico. Para México 52.

Los errores de autenticación (auth_*) vienen de la capa común de la API y llegan con HTTP 200 y el detalle en el body — consulta Errores y límites.

curl -X GET "https://api.smsmasivos.com.mx/v2/otp/status?phone_number=5512345678&country_code=52" \
  -H "apikey: TU_API_KEY"
import requests

response = requests.get(
    'https://api.smsmasivos.com.mx/v2/otp/status',
    headers={'apikey': 'TU_API_KEY'},
    params={
        'phone_number': '5512345678',
        'country_code': '52'
    }
)
print(response.json())
const params = new URLSearchParams({
  phone_number: '5512345678',
  country_code: '52'
});
const response = await fetch(
  `https://api.smsmasivos.com.mx/v2/otp/status?${params}`,
  { headers: { apikey: process.env.SMSMASIVOS_API_KEY } }
);
const data = await response.json();
console.log(data);
Response
{
  "success": true,
  "state": "pending",
  "message": "Estado actual del OTP.",
  "hint": "Hay un código activo. Verifícalo con POST /v2/otp/verify o reenvíalo con POST /v2/otp.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 5,
  "resend_available_in": 12,
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
{
  "success": false,
  "error": "otp_missing_param",
  "message": "Falta un parámetro obligatorio.",
  "hint": "Envía 'phone_number' (hasta 10 dígitos).",
  "next": []
}
{
  "success": false,
  "error": "otp_internal",
  "message": "Ocurrió un error inesperado.",
  "hint": "Intenta de nuevo en unos momentos.",
  "next": []
}

Objeto de respuesta

Estructura de la respuesta que devuelven estos endpoints.

Atributos
successboolean
stateenum
Estado de la verificación después del envío. Siempre pending: hay un código activo esperando verificación.pending
actionenum

Qué hizo la API con tu solicitud:

  • created: primera verificación para el número (o la anterior ya había expirado). HTTP 201.
  • resent: reenvió el mismo código vigente. HTTP 200.
  • restarted: generó un código nuevo e inició otra ronda (con code_rotate: true, o tras una verificación completada). HTTP 200 o 201.
createdresentrestarted
messagestring
Descripción del resultado en español.
hintstring
Sugerencia accionable sobre el siguiente paso.
nextarray<string>
Endpoints sugeridos como siguiente paso del flujo.
expires_atstring
Fecha de expiración del código (YYYY-MM-DD HH:mm:ss, hora del centro de México).
attempts_remaininginteger
Intentos de verificación disponibles para este código (máximo 7 por ronda).
resend_available_ininteger
Segundos que deben pasar antes de poder reenviar o rotar el código (cooldown de 30s).
warningstring
Solo cuando aplica: aviso no bloqueante, por ejemplo al enviar message/company con channel: whatsapp (se ignoran, la plantilla de WhatsApp es fija).
codestring
El código generado. Solo cuando envías code_show: 1 (pruebas/automatización).
request_idstring
UUID para seguimiento de la petición.
Objeto de respuesta
{
  "success": true,
  "state": "pending",
  "action": "created",
  "message": "Código OTP creado y enviado.",
  "hint": "El código llega en segundos. Reenvía con POST /v2/otp si no llegó.",
  "next": [
    "/v2/otp/verify",
    "/v2/otp"
  ],
  "expires_at": "2026-07-21 12:00:00",
  "attempts_remaining": 7,
  "resend_available_in": 30,
  "warning": "channel=whatsapp usa una plantilla oficial fija; se ignoraron message/company.",
  "code": "483920",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}