Download OpenAPI specification:Download
Integration API for the 2FA (two-factor authentication) and OTP (one-time password) service. The system generates a code, delivers it to the end user and you validate it with a second call. The code can travel through an ORDERED list of channels: SMS, VOICE (call with text-to-speech), EMAIL, WHATSAPP, RCS and PUSH. If the delivery through the first channel fails, the system automatically resends THE SAME code through the next channel of the list, with no action needed on your side.
This version replaces the v5 2FA/OTP API (peticionotp.php / validarotp.php), which only sent through SMS or VOICE.
In your user account you will find the API User and the API Token; both are required to make REST API requests to the API functions. For security, requests must be made with POST over HTTPS.
To use Basic Authentication you must include a header of the form: Authorization: Basic Base64StringAPI, where Base64StringAPI is the Base64 encoding of the string APIUser:APIToken. You can find your API User and API Token in your user account under Your data -> Configure account.
To generate the Base64 encoded string, simply build the string APIUser:APIToken and encode it with any base64encode function.
Normal service flow:
1.- Your application asks the user for their phone (and/or email) to validate an operation.
2.- Your application calls EnviarOTP: the system generates and sends the code.
3.- The user types the received code and your application calls ValidarOTP.
4.- If the result is 1, the operation is validated.
Requirements per channel:
Every channel you include in the cascade must be available in your account:
- SMS: always available. MENSAJE is optional (a standard text with the code is sent by default); if you provide it, it must contain [CODE].
- VOICE (voz): call with a text-to-speech locution that spells the code. Requires one of your own ACTIVE voice numbers as REMITENTE (requested from the panel).
- EMAIL: either with your own validated DOMINIO (sender of your domain) or without DOMINIO (sent through the default transactional domain of the service). ASUNTO and MENSAJEEMAIL are optional.
- WHATSAPP: requires a connected WhatsApp Business account, IDTELEFONO and the IDPLANTILLA of an AUTHENTICATION template approved by Meta (the code fills the body variable and the copy-code button).
- RCS: requires an active RCS Agent (IDAGENTE) and a template (IDPLANTILLA) that includes the (CODE) variable.
- PUSH: alert to the end user's devices linked from the panel (Alerts section). The destination is the device ALIAS (the REFPUSH parameter or the channel REF field).
Retry cascade: Delivery states are notified by each operator. If a channel reports a definitive failure, the system resends THE SAME code through the next channel of the list. When the code is validated (or expires) the cascade stops automatically.
State webhook (recommended, avoids polling):
If your account has a reports URL configured (Your data → Configure account), every state change of the code is POSTed to that URL as a JSON including Tipo:"OTP", Evento (entregado | leido | reenviado | fallido), idOTP, idEnvio, App, Destinatario/Email, Canal, CanalesFallidos, Fecha, Expira and ReferenciaUsuario (never the code). The reenviado event adds Motivo and the new Canal. With a webhook configured, ConsultarOTP only answers once the delivery is resolved (or the request is validated/expired): the right integration is webhook + ValidarOTP, with no polling loops.
Tracking in the panel:
Every OTP request shows in the panel as a single-recipient omnichannel campaign, under Omnichannel sending → Campaigns, tagged as OTP and with its own filter (OTP only), with the detail of channel, deliveries and retries.
Anti-fraud check (optional):
With ANTIFRAUDE=SI, before sending, the anti-fraud module is queried about the destination (DatosTelefono when there is a phone; DatosEmail when the destination is email only; charged as per the module catalogue). The response includes the Antifraude object with the risk (0-100) and its reasons; when the risk reaches ANTIFRAUDEMAXRIESGO the sending is rejected with Res -16. Useful against SMS pumping and recently ported numbers (SIM swap).
Anti-abuse:
For security, the same destination admits a maximum of 5 send requests every 10 minutes (Res -6 when exceeded). The number of validation attempts is limited with MAXINTENTOS (default 3). Codes are stored hashed, travel encrypted through the retry queue (never at rest in the clear) and responses never return them.
Migrating from the v5 API (peticionotp/validarotp):
Authentication changes from Correo/Passwd to API User + API Token (Basic). The default sending channel is still SMS and the MENSAJE parameter with [CODE] is kept. Fail2Voice is replaced by the cascade (add the voz channel after sms). The result codes of ValidarOTP are the same as in v5.
Response of the requests:
Most functions have a parameter called 'Resp'. This parameter defines the format of the returned response. It can be TXT, JSON or XML. We recommend always setting this parameter.
HTTP Basic authentication. Use your API User as the username and your API Token as the password (you will find them in your panel, under Your Data → Configure Account). The resulting header is Authorization: Basic base64(APIUser:APIToken). Most HTTP libraries build it automatically (curl -u, requests auth=, Ruby's basic_auth, etc.) without needing to encode the base64 by hand.
basicGenerates a one-time code and sends it to the destination through the channel cascade defined in CANALES (SMS by default). Returns idOTP to validate/query later. If a channel fails to deliver, the system automatically retries through the next channel with THE SAME code.
| Destinatario | string Example: Destinatario=34600000001 End user's phone in international format without '+' (e.g. 34600000001). Required when the cascade includes sms, voz, whatsapp or rcs. |
string Example: Email=user@example.com End user's email. Required when the cascade includes the email channel. | |
| Refpush | string Example: Refpush=customer-4471 Alias of the end user's linked device (Alerts section of the panel). Required when the cascade includes the push channel and the channel does not carry its own REF. |
| Nombre | string Example: Nombre=Pedro Aicart Recipient's name; available as the {{NOMBRE}} variable in the templates. |
| Canales | Array of strings Example: Canales=[{"Tipo":"whatsapp","IdTelefono":"572863982585983","IdPlantilla":"access_code"},{"Tipo":"sms","Remitente":"MYCOMPANY","Mensaje":"Your access code is [CODE]"}] ORDERED JSON array with the cascade channels (each type only once; maximum 6). If omitted, the code is sent by sms. Fields per element:
|
| Mensaje | string Example: Mensaje=Your verification code is [CODE]. Do not share it with anyone. Common template for the sms/voz/email/push channels that do not carry their own. It must contain [CODE] (replaced by the generated code). If omitted, each channel uses its default text. |
| Remitente | string Example: Remitente=MYCOMPANY Default sender for the sms channel (max. 11 alphanumeric characters). |
| Codigo | string Example: Codigo= Your own code generated by your application (3 to 10 alphanumeric characters). If omitted, the system generates it according to LONG and TIPO (recommended). |
| Long | integer Example: Long=6 Length of the generated code (3 to 10). |
| Tipo | integer Example: Tipo=1 Code alphabet:
|
| Maxintentos | integer Example: Maxintentos=3 Failed validation attempts before invalidating the code (0 = unlimited, maximum 10). |
| Validez | integer Example: Validez=600 Time in seconds during which the code can be validated (60 to 86400). For example 600 for 10 minutes. |
| Appid | integer Example: Appid=0 Identifier of the application making the request. It allows validating the same destination in different applications without interference. |
| Variables | Array of strings Example: Variables={"NOMBRE":"Pedro"} Extra variables for the templates (plain object {"VAR":"value"} or list [{Nombre,Valor}]): {{NOMBRE}}, WhatsApp multimedia headers... The CODE variable is always set by the system. |
| Referenciausuario | string Example: Referenciausuario=web-login Free reference for your listings (max. 50 characters). |
| Validarcanales | string Enum: "NO" "SI" Example: Validarcanales=NO SI = validates the REAL configuration of every channel before sending: RCS agent and template (including the CODE variable), email template with its HTML, WhatsApp Business account with the phone registered and the template APPROVED by Meta, and linked push devices for the alias. Meant for PRE-PRODUCTION: it adds latency and is rate-limited per minute (Res -6). Use NO in production. |
| Antifraude | string Enum: "NO" "SI" Example: Antifraude=NO SI = before sending, queries the anti-fraud module about the destination (DatosTelefono with a phone; DatosEmail when the destination is email only). The query is charged as per the module catalogue (a recent repetition is not charged). The response includes the Antifraude object; when the risk reaches ANTIFRAUDEMAXRIESGO the code is NOT sent (Res -16). If the lookup cannot be resolved (provider outage) the code IS sent anyway and Antifraude reports it. |
| Antifraudemaxriesgo | integer Example: Antifraudemaxriesgo=50 Risk (0-100) from which the sending is rejected with ANTIFRAUDE=SI. 0 = only report, never block. 50 matches the module's HIGH level. |
| Resp | string Enum: "TXT" "JSON" "XML" Example: Resp=JSON Response format of the call.
|
Parameters are sent in the body of the POST request, either as a JSON object (Content-Type application/json, RECOMMENDED) or as an application/x-www-form-urlencoded form. In the form format, array or object parameters are sent as a JSON-encoded string. Parameter names are case-insensitive. The detailed description of each parameter is in the parameters section of this operation.
| Destinatario | string |
string | |
| Refpush | string |
| Nombre | string |
| Canales | Array of any |
| Mensaje | string |
| Remitente | string |
| Codigo | string |
| Long | integer |
| Tipo | integer |
| Maxintentos | integer |
| Validez | integer |
| Appid | integer |
| Variables | Array of any |
| Referenciausuario | string |
| Validarcanales | string |
| Antifraude | string |
| Antifraudemaxriesgo | integer |
| Resp | string |
| Res required | integer <int32> Result of the requested function
|
| Error | string When Res is negative, description of the problem. |
| idOTP | integer Identifier of the OTP request. Use it in ValidarOTP and ConsultarOTP. |
| idEnvio | integer Identifier of the omnichannel campaign carrying the code (visible in the panel). |
| Canal | string Channel used by the first attempt (sms|voz|email|whatsapp|rcs|push). |
| Expira | string Date and time until which the code can be validated. |
| MaxIntentos | integer Allowed validation attempts (0 = unlimited). |
| CreditosUsados | number Credits charged for the first attempt (only the channel each attempt actually goes through is charged). |
| Antifraude | Array of arrays Only with ANTIFRAUDE=SI: result of the anti-fraud query about the destination (Riesgo with Puntos 0-100, Nivel and Motivos; Linea or the Dominio/Buzon objects for email; Creditos charged for the query). |
| Cred | number Credits available in the account after the operation. |
{- "Destinatario": "34600000001",
- "Email": "user@example.com",
- "Refpush": "customer-4471",
- "Nombre": "Pedro Aicart",
- "Canales": "[{\"Tipo\":\"whatsapp\",\"IdTelefono\":\"572863982585983\",\"IdPlantilla\":\"access_code\"},{\"Tipo\":\"sms\",\"Remitente\":\"MYCOMPANY\",\"Mensaje\":\"Your access code is [CODE]\"}]",
- "Mensaje": "Your verification code is [CODE]. Do not share it with anyone.",
- "Remitente": "MYCOMPANY",
- "Codigo": "",
- "Long": "6",
- "Tipo": "1",
- "Maxintentos": "3",
- "Validez": "600",
- "Appid": "0",
- "Variables": "{\"NOMBRE\":\"Pedro\"}",
- "Referenciausuario": "web-login",
- "Validarcanales": "NO",
- "Antifraude": "NO",
- "Antifraudemaxriesgo": "50",
- "Resp": "JSON"
}[- {
- "Res": "1",
- "Error": "",
- "idOTP": "88231",
- "idEnvio": "1024",
- "Canal": "sms",
- "Expira": "2026-09-01 10:40:00",
- "MaxIntentos": "3",
- "CreditosUsados": "1",
- "Antifraude": "{\"Servicio\":\"DatosTelefono\",\"Riesgo\":{\"Puntos\":10,\"Nivel\":\"BAJO\",\"Motivos\":[\"No risk signal detected in the number data.\"]},\"Linea\":{\"Tipo\":\"movil\",\"TipoTexto\":\"Mobile\"},\"Creditos\":1,\"Repetida\":0}",
- "Cred": "970.5"
}
]Validates the code typed by the end user. The request is located by IDOTP (recommended) or by DESTINATARIO/EMAIL + APPID (the latest request of that destination). Upon validation, the retry cascade of the code stops automatically. The result codes are the same as in the v5 API.
| Idotp | integer Example: Idotp=88231 Identifier returned by EnviarOTP. When set, DESTINATARIO/EMAIL are not needed. |
| Destinatario | string Example: Destinatario=34600000001 Phone the code was sent to, in international format without '+'. |
string Example: Email=user@example.com Email the code was sent to. | |
| Appid | integer Example: Appid=0 Application identifier used in EnviarOTP. |
| Codigo required | string Example: Codigo=430913 Code typed by the end user (3 to 10 characters). |
| Resp | string Enum: "TXT" "JSON" "XML" Example: Resp=JSON Response format of the call.
|
Parameters are sent in the body of the POST request, either as a JSON object (Content-Type application/json, RECOMMENDED) or as an application/x-www-form-urlencoded form. In the form format, array or object parameters are sent as a JSON-encoded string. Parameter names are case-insensitive. The detailed description of each parameter is in the parameters section of this operation.
| Idotp | integer |
| Destinatario | string |
string | |
| Appid | integer |
| Codigo required | string |
| Resp | string |
| Res required | integer <int32> Result of the requested function
|
| Error | string When Res is negative, description of the problem. |
| idOTP | integer Identifier of the validated request. |
| FechaValidado | string Validation date and time. |
| Intentos | integer Attempts made until validation. |
| Canal | string Channel the code was travelling through. |
| Cred | number Credits available in the account. |
{- "Idotp": "88231",
- "Destinatario": "34600000001",
- "Email": "user@example.com",
- "Appid": "0",
- "Codigo": "430913",
- "Resp": "JSON"
}[- {
- "Res": "1",
- "Error": "",
- "idOTP": "88231",
- "FechaValidado": "2026-09-01 10:32:11",
- "Intentos": "1",
- "Canal": "sms",
- "Cred": "970.5"
}
]Returns the full state of an OTP request: current channel, delivery state (pending, sent, delivered, read, resent through another channel, failed), validation and charged credits. It never returns the code.
NOT a polling function: state changes are pushed to your webhook (JSON with Tipo:"OTP"). If your account has a webhook configured, this query returns -10 until the delivery is resolved (entregado/leido/fallido webhook emitted) or the request is validated/expired, and there is a per-minute query limit (-6). Without a configured webhook it always answers.
| Idotp | integer Example: Idotp=88231 Identifier returned by EnviarOTP. When set, DESTINATARIO/EMAIL are not needed. |
| Destinatario | string Example: Destinatario=34600000001 Phone the code was sent to, in international format without '+'. The LATEST request of that destination is returned. |
string Example: Email=user@example.com Email the code was sent to. | |
| Appid | integer Example: Appid=0 Application identifier used in EnviarOTP. |
| Resp | string Enum: "TXT" "JSON" "XML" Example: Resp=JSON Response format of the call.
|
Parameters are sent in the body of the POST request, either as a JSON object (Content-Type application/json, RECOMMENDED) or as an application/x-www-form-urlencoded form. In the form format, array or object parameters are sent as a JSON-encoded string. Parameter names are case-insensitive. The detailed description of each parameter is in the parameters section of this operation.
| Idotp | integer |
| Destinatario | string |
string | |
| Appid | integer |
| Resp | string |
| Res required | integer <int32> Result of the requested function
|
| idOTP | integer Identifier of the request. |
| App | integer APPID of the request. |
| Telefono | string Destination phone (empty when the OTP was email/push only). |
string Destination email (empty when not used). | |
| Fecha | string Request date. |
| Expira | string Expiration date of the code. |
| Expirado | integer 1 when the code has already expired. |
| Canal | string Current channel of the code (sms|voz|email|whatsapp|rcs|push). |
| EstadoEnvio | string Delivery state: pendiente | enviado | entregado | leido | reenviado | fallido. |
| CanalesFallidos | string Channels that already failed for this request (CSV). |
| IntentosEnvio | integer Send attempts made (one per channel used). |
| UltimoError | string Last delivery error, if any. |
| Validado | integer 1 when the code was already validated. |
| FechaValidado | string Validation date (when Validado=1). |
| IntentosValidacion | integer Validation attempts made. |
| MaxIntentos | integer Allowed validation attempts (0 = unlimited). |
| ReferenciaUsuario | string Free reference set in EnviarOTP. |
| CreditosUsados | number Credits charged so far for this request. |
| Cred | number Credits available in the account. |
{- "Idotp": "88231",
- "Destinatario": "34600000001",
- "Email": "user@example.com",
- "Appid": "0",
- "Resp": "JSON"
}[- {
- "Res": "1",
- "idOTP": "88231",
- "App": "0",
- "Telefono": "34600000001",
- "Email": "user@example.com",
- "Fecha": "2026-09-01 10:30:00",
- "Expira": "2026-09-01 10:40:00",
- "Expirado": "0",
- "Canal": "sms",
- "EstadoEnvio": "entregado",
- "CanalesFallidos": "",
- "IntentosEnvio": "1",
- "UltimoError": "",
- "Validado": "1",
- "FechaValidado": "2026-09-01 10:32:11",
- "IntentosValidacion": "1",
- "MaxIntentos": "3",
- "ReferenciaUsuario": "web-login",
- "CreditosUsados": "1",
- "Cred": "970.5"
}
]List of the OTP requests of a period (maximum 31 days) with their delivery and validation states. It replaces the v5 CSV report: here the list arrives structured in the response itself.
| Fechadesde | string Example: Fechadesde=2026-08-01 00:00 Start of the period, YYYY-MM-DD HH:mm format (CET/CEST). If omitted: 30 days before FECHAHASTA (or before now). |
| Fechahasta | string Example: Fechahasta=2026-08-31 23:59 End of the period, YYYY-MM-DD HH:mm format (CET/CEST). If omitted: now (or 31 days after FECHADESDE). |
| Appid | string Example: Appid=-1 Filters by application identifier. -1 (default) returns all of them. |
| Max | integer Example: Max=1000 Maximum number of rows to return (1 to 5000). |
| Resp | string Enum: "TXT" "JSON" "XML" Example: Resp=JSON Response format of the call.
|
Parameters are sent in the body of the POST request, either as a JSON object (Content-Type application/json, RECOMMENDED) or as an application/x-www-form-urlencoded form. In the form format, array or object parameters are sent as a JSON-encoded string. Parameter names are case-insensitive. The detailed description of each parameter is in the parameters section of this operation.
| Fechadesde | string |
| Fechahasta | string |
| Appid | string |
| Max | integer |
| Resp | string |
| Res required | integer <int32> Result of the requested function
|
| Num | integer Number of returned requests. |
| FechaDesde | string Effective start of the queried period. |
| FechaHasta | string Effective end of the queried period. |
| Peticiones | Array of arrays List of requests. Every element includes: idOTP, App, Fecha, Expira, Telefono, Email, Canal, EstadoEnvio (pendiente|enviado|entregado|leido|reenviado|fallido), CanalesFallidos, IntentosEnvio, UltimoError, Validado, FechaValidado, IntentosValidacion, MaxIntentos, ReferenciaUsuario and CreditosUsados. The code is never included. |
| Cred | number Credits available in the account. |
{- "Fechadesde": "2026-08-01 00:00",
- "Fechahasta": "2026-08-31 23:59",
- "Appid": "-1",
- "Max": "1000",
- "Resp": "JSON"
}[- {
- "Res": "1",
- "Num": "25",
- "FechaDesde": "2026-08-01 00:00",
- "FechaHasta": "2026-08-31 23:59",
- "Peticiones": "[{\"idOTP\":88231,\"App\":0,\"Fecha\":\"2026-08-30 10:30:00\",\"Expira\":\"2026-08-30 10:40:00\",\"Telefono\":\"34600000001\",\"Email\":\"\",\"Canal\":\"sms\",\"EstadoEnvio\":\"entregado\",\"CanalesFallidos\":\"\",\"IntentosEnvio\":1,\"UltimoError\":\"\",\"Validado\":1,\"FechaValidado\":\"2026-08-30 10:31:12\",\"IntentosValidacion\":1,\"MaxIntentos\":3,\"ReferenciaUsuario\":\"web-login\",\"CreditosUsados\":1}]",
- "Cred": "970.5"
}
]