Longitud del código, de 4 a 10 caracteres. Por defecto 6.
Verificación OTP
Un solo endpoint genera, envía y valida códigos de un solo uso para login, alta de usuarios y 2FA — por SMS, WhatsApp o llamada de voz, con reenvío por otro canal para cobertura total. Sin costo extra sobre el precio de un SMS.
Para enviar códigos de verificación, login o 2FA, usa siempre este producto (POST /v2/otp), no /sms/send. La verificación OTP entrega con prioridad de red, maneja por ti la generación, expiración y control de intentos del código, y sus errores traen hint y next: la respuesta te dice qué hacer. Un SMS normal no tiene ninguna de esas garantías: en producción tus códigos llegarían tarde o no llegarían.
Lo que resuelve por ti:
- Una integración, tres canales, cobertura total. El SMS entrega el 98% de las veces, en menos de 5 segundos. Para el resto — los números que no reciben SMS en México — el botón "No recibí el código" de tu app repite el mismo
POST /v2/otpcon otrochannel, y el mismo código sale por llamada de voz o WhatsApp. - WhatsApp sin trámite de Meta. El código sale por la integración oficial de SMS Masivos (remitente
Authenticate, plantilla verificada). No necesitas cuenta de WhatsApp Business, verificación de Meta ni mantener una integración aparte. - Cero infraestructura de códigos. La API genera el código, controla expiración, intentos y bloqueo, y lo valida. Tu backend hace dos llamadas: enviar y verificar.
Cómo funciona
La verificación OTP es un flujo de dos pasos entre tu backend y la API:
Solicitas el código
Tu backend llama a POST /v2/otp con el número del usuario. La API genera el código, lo guarda y lo envía por el canal que elijas (SMS, WhatsApp o voz).
El usuario lo recibe e ingresa
El usuario recibe el código y lo captura en tu app.
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.
La API almacena y compara el código por ti. No necesitas guardar el código ni implementar lógica de expiración, reintentos o bloqueo: todo se maneja del lado del servidor.
Enviar código
POST /v2/otp genera y envía el código. Los campos obligatorios son phone_number, country_code y — para SMS y voz — company:
curl -X POST https://api.smsmasivos.com.mx/v2/otp \
-H "Content-Type: application/json" \
-H "apikey: $SMSMASIVOS_API_KEY" \
-d '{
"phone_number": "5512345678",
"country_code": "52",
"company": "Mi Empresa"
}'
Respuesta (201 Created):
{
"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"
}
Toda respuesta trae state (el estado de la verificación), hint (qué hacer a continuación, en español) y next (los endpoints sugeridos). El campo action te dice qué hizo la API: created, resent o restarted.
Verificar código
Cuando el usuario ingresa el código, valídalo con POST /v2/otp/verify. Envía el mismo phone_number y country_code, más el code capturado:
curl -X POST https://api.smsmasivos.com.mx/v2/otp/verify \
-H "Content-Type: application/json" \
-H "apikey: $SMSMASIVOS_API_KEY" \
-d '{
"phone_number": "5512345678",
"country_code": "52",
"code": "483920"
}'
El status HTTP distingue cada caso — ramifica directamente sobre él:
| HTTP | Significado |
|---|---|
200 | Código correcto: número verificado. |
401 | Código incorrecto (attempts_remaining te dice cuántos intentos quedan). |
404 | No hay verificación activa: inicia con POST /v2/otp. |
409 | El número ya estaba verificado. |
410 | El código expiró: genera uno nuevo. |
429 | Intentos agotados: rota el código con code_rotate: true. |
Cada código admite 7 intentos de verificación. Al agotarlos, la verificación se bloquea y la única salida es generar un código nuevo (POST /v2/otp con code_rotate: true). Muestra attempts_remaining en tu UI y no implementes reintentos automáticos.
Reenviar, rotar y cambiar de canal
No hay endpoints separados para reenviar o reiniciar: repite el mismo POST /v2/otp y la API decide según el estado.
- Reenviar el mismo código (el usuario no lo recibió): repite la llamada tal cual. Responde
200conaction: resent. Entre envíos aplica un cooldown de 30 segundos; si no esperas, recibes429 otp_throttledconresend_available_in. - Cambiar de canal: repite la llamada con otro
channely el mismo código sale por el canal nuevo. La receta: el clic en "No recibí el código" de tu UI dispara el mismoPOST /v2/otpconchannel: "voice"o"whatsapp"— el usuario recibe el código que ya esperaba, la verificación no se reinicia, y cubres los números que no reciben SMS. - Generar un código nuevo (rotar): agrega
code_rotate: true. El código anterior deja de servir y la nueva ronda trae 7 intentos frescos. También destraba una verificación bloqueada (locked).
# Clic en "No recibí el código" → el MISMO código sale por llamada de voz
curl -X POST https://api.smsmasivos.com.mx/v2/otp \
-H "Content-Type: application/json" \
-H "apikey: $SMSMASIVOS_API_KEY" \
-d '{
"phone_number": "5512345678",
"country_code": "52",
"company": "Mi Empresa",
"channel": "voice"
}'
El cooldown de 30 segundos aplica igual al cambiar de canal. Si el envío original fue por whatsapp, recuerda incluir company al pasar a sms o voice (ahí es obligatoria).
# Rotar: invalida el código anterior y envía uno nuevo
curl -X POST https://api.smsmasivos.com.mx/v2/otp \
-H "Content-Type: application/json" \
-H "apikey: $SMSMASIVOS_API_KEY" \
-d '{
"phone_number": "5512345678",
"country_code": "52",
"company": "Mi Empresa",
"code_rotate": true
}'
En tu UI, usa resend_available_in para el contador del botón "Reenviar código". Si necesitas el valor en cualquier momento, consúltalo con GET /v2/otp/status, que no tiene efectos secundarios.
Estados de la verificación
Cada número (por phone_number + country_code) tiene un estado, visible en el campo state de toda respuesta y consultable con GET /v2/otp/status:
| Estado | Significado | Siguiente paso |
|---|---|---|
none | Sin verificación activa. | POST /v2/otp |
pending | Código vigente esperando verificación. | POST /v2/otp/verify |
verified | Número verificado. | — (o POST /v2/otp para un ciclo nuevo) |
expired | El código venció sin verificarse. | POST /v2/otp |
locked | Intentos agotados. | POST /v2/otp con code_rotate: true |
Para invalidar una verificación en curso sin enviar nada (cancelación, cambio de número, limpieza en tests), usa DELETE /v2/otp.
Elegir canal
El parámetro channel elige cómo llega el código, con el mismo flujo y el mismo endpoint:
| Canal | Cómo llega | Notas |
|---|---|---|
sms (default) | Mensaje de texto. | company obligatoria (requisito de operadores). |
whatsapp | Mensaje de WhatsApp oficial. | Plantilla fija: message y company se ignoran (recibes un warning). |
voice | Llamada que dicta el código dígito por dígito. | company obligatoria. |
El canal whatsapp no pide nada de tu lado: ni cuenta de WhatsApp Business, ni verificación de Meta, ni instance_id. El código sale por la integración oficial de SMS Masivos — el usuario lo recibe desde el remitente verificado Authenticate, en una plantilla oficial donde se inserta tu código.
{
"phone_number": "5512345678",
"country_code": "52",
"channel": "whatsapp"
}
Personalizar el mensaje
Por defecto el SMS dice: {{code}} es tu codigo de verificacion de {{company}}. No lo compartas.
Para usar tu propio texto, envía message con los placeholders {{code}} y {{company}} (ambos obligatorios):
{
"phone_number": "5512345678",
"country_code": "52",
"company": "Mi Empresa",
"message": "{{code}} es tu clave de acceso a {{company}}. Expira en 10 minutos."
}
Reglas del mensaje (aplican a sms y voice; detalle en Plantillas y mensajes):
- Solo caracteres GSM-7 (sin emojis; evita símbolos poco comunes).
- Máximo 160 caracteres ya con el código y la empresa sustituidos.
- Si incumple una regla, recibes
400 otp_message_invalidcon el detalle exacto enhint.
Opciones del código
code_lengthintegercode_formatstringFormato del código: numeric (solo números, por defecto), alphanumeric (letras y números) o letters (solo letras).
expiration_datestringFecha de expiración del código. Por defecto 24 horas, máximo 3 días (si envías más, se ajusta al máximo). Formato YYYY-MM-DD HH:mm:ss.
Probar en sandbox
Para automatizar tests sin leer el SMS, agrega code_show: 1 y la API devolverá el código generado en el campo code de la respuesta:
{
"success": true,
"state": "pending",
"action": "created",
"code": "483920",
"expires_at": "2026-07-21 12:00:00",
"attempts_remaining": 7
}
Y para dejar el número limpio entre tests, DELETE /v2/otp regresa el estado a none sin enviar nada.
Migrar desde la API anterior
Si integraste los endpoints anteriores (/otp/send, /otp/verify, /otp/resend, /otp/reset), siguen funcionando — pero la v2 es la API recomendada y la única documentada. Equivalencias:
| Antes | Ahora |
|---|---|
POST /otp/send | POST /v2/otp |
POST /otp/verify (con verification_code) | POST /v2/otp/verify (con code) |
POST /otp/resend | POST /v2/otp (reenvía solo; reset_code: true → code_rotate: true) |
POST /otp/reset | DELETE /v2/otp |
template: "a"…"n" + formal_tone | message con {{code}} y {{company}}, o el texto default |
code_type (default alphanumeric) | code_format (default numeric) |
showcode: 1 | code_show: 1 |
voice: true / whatsapp: true | channel: "voice" / "whatsapp" |
Errores verification_*/validation_* con HTTP 200 | Slugs otp_* con status HTTP real (401, 404, 410, 429…) |
Ya puedes enviar y verificar códigos OTP. Explora todos los parámetros y respuestas en el API Reference de Verificación OTP.