Verificación OTP

Verificación en dos pasos (OTP): códigos de un solo uso por SMS, WhatsApp o llamada de voz, con una sola integración para los tres canales.

1

Solicitas el código

Tu backend llama a POST /v2/otp con el número del usuario, tu company y tu message. La API genera el código, lo inserta en tu mensaje y lo envía por el canal que elijas (channel: sms, whatsapp o voice) — solo cambias channel.

2

El usuario lo recibe e ingresa

El usuario recibe el código y lo captura en tu app. Por WhatsApp sale por nuestra integración oficial: sin cuenta de WhatsApp Business ni verificación de Meta.

3

Verificas el código

Tu backend llama a POST /v2/otp/verify con el número y el código capturado. Si el status HTTP es 200, el número quedó verificado. No tiene costo.

4

Si tu usuario no recibió el código

El clic en "No recibí el código" de tu app repite el mismo POST /v2/otp con otro channel (por ejemplo voice o whatsapp). Sale el mismo código, la verificación no se reinicia y cuesta lo mismo: un mensaje de tu saldo.

Usar estos métodos no tiene costo extra: solo se descuenta un mensaje de tu saldo cuando la API le envía el código al usuario por SMS, WhatsApp o llamada de voz (POST /v2/otp, ya sea al crear, reenviar o rotar), sin importar el canal. Verificar el código, consultar su estado o invalidarlo nunca tienen costo, sin importar cuántas veces los llames.

Los otros dos endpoints son auxiliares; en un flujo normal no los necesitas:

  • GET /v2/otp/status: solo lectura, para tu UI (contador de reenvío, intentos restantes).
  • DELETE /v2/otp: cancela una verificación en curso (limpieza en tests, cambio de número). 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.

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

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, company y message; el código llega por SMS en segundos. Con code_in_response: true la respuesta incluye el código y puedes automatizar la prueba sin leer el teléfono.

Cuerpo de la solicitud
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 nuestra integración oficial (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
companystringrequerido

Nombre de tu empresa o app. Se inserta en message mediante el placeholder {{company}}.

Si channel es whatsapp, se ignora: la plantilla oficial de WhatsApp es fija (recibes un warning avisando).

messagestringrequerido

Texto que recibe el usuario. 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.

Ejemplo armado (con code: "483920" y company: "Mi Empresa"): 483920 es tu codigo de verificacion de Mi Empresa. No lo compartas.

Si channel es whatsapp, se ignora: el texto sale por la plantilla oficial fija de WhatsApp (recibes un warning avisando).

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_in_responsebooleanopcional

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

  • false (default): no devolver.
  • true: devolver (pruebas/automatización del lado del servidor).
sandboxbooleanopcional
Modo prueba. Con true el flujo se ejecuta completo (genera y registra el código) pero el SMS no se entrega y no se descuenta saldo. Como el usuario nunca recibe el mensaje, debes enviar también code_in_response: true para obtener el código en la respuesta; si falta, responde 400 otp_missing_param.
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

  • company y message son obligatorios en toda petición, sin importar el canal — mándalos siempre igual y solo cambia channel. message debe incluir {{code}} y {{company}}.
  • channel: whatsapp reemplaza company y message por su plantilla oficial fija (recibes un warning avisando que se ignoraron); en sms y voice se usan tal cual los envías.
  • sandbox: true (modo prueba: no entrega el SMS ni descuenta saldo) requiere code_in_response: true; sin él, 400 otp_missing_param.

code_in_response: true 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",
    "message": "{{code}} es tu codigo de verificacion de {{company}}. No lo compartas."
  }'
<?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('API_KEY')
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'phone_number' => '5512345678',
    'country_code' => '52',
    'company' => 'Mi Empresa',
    'message' => '{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.'
]));
$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',
        'message': '{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.'
    }
)
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.API_KEY
  },
  body: JSON.stringify({
    phone_number: '5512345678',
    country_code: '52',
    company: 'Mi Empresa',
    message: '{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.'
  })
});
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',
    message: '{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.'
  },
  {
    headers: {
      'Content-Type': 'application/json',
      'apikey': process.env.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['API_KEY']
})
request.body = {
  phone_number: '5512345678',
  country_code: '52',
  company: 'Mi Empresa',
  message: '{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.'
}.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",
    message = "{{code}} es tu codigo de verificacion de {{company}}. No lo compartas."
};

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\","
    + "\"message\":\"{{code}} es tu codigo de verificacion de {{company}}. No lo compartas.\""
    + "}";

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": []
}

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.

Cuerpo de la solicitud
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('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.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.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['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).

Parámetros de consulta
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.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": []
}

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.

Cuerpo de la solicitud
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.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": []
}

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_in_response: true (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"
}