Omnichannel 2FA / OTP API (7.0)

Download OpenAPI specification:Download

INTRODUCTION

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.

AUTHENTICATION

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.

THINGS TO KEEP IN MIND

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.

basicAuth

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.

Security Scheme Type: HTTP
HTTP Authorization Scheme: basic

Send OTP

/EnviarOTP

Generates 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.

Authorizations:
basicAuth
query Parameters
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.

Email
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:
Tipo (required) - sms | voz | email | whatsapp | rcs | push
sms: Remitente (max. 11 alphanumeric chars) and Mensaje with [CODE]; both optional (a default text exists).
voz: Remitente (one of your own active voice numbers, required), Mensaje with [CODE] (optional; the code is spelled automatically), Lenguaje (TTS language, default es) and DetectarContestador (0|1).
email: Dominio (your own validated domain; empty = default service domain), Remitente (address of the domain), Asunto and MensajeEmail with [CODE] (optional) or IdPlantilla.
whatsapp: IdTelefono (Meta phone_id) and IdPlantilla (APPROVED authentication template; the code fills {{1}} and the copy button).
rcs: IdAgente and IdPlantilla (numeric; the template must include the (CODE) variable).
push: Ref (device alias; REFPUSH is used when missing), Titulo, Mensaje with [CODE], Aplicacion (source slug, default otp), Nivel (critico|alto|normal|bajo). For example:


                  [
                    { "Tipo": "whatsapp", "IdTelefono": "572863982585983", "IdPlantilla": "access_code" },
                    { "Tipo": "sms", "Remitente": "MYCOMPANY", "Mensaje": "Your access code is [CODE]" },
                    { "Tipo": "voz", "Remitente": "34910000001" }
]
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:
1 - Digits only
2 - Uppercase letters only
3 - Uppercase letters and digits
4 - Uppercase, lowercase and digits

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.
JSON - The response is returned as JSON
XML - The response is returned as XML
TXT - The response is returned as plain text

Request Body schema:

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
Email
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

Responses

Response Schema:
Array
Res
required
integer <int32>

Result of the requested function
1 Code generated and sent.
-1 Authentication error.
-2 Not enough credits (you will get Necesarios and Cred).
-3 Error in the request data (you will get Error with the description).
-4 Misconfigured channel (Error contains the channel and the reason; with VALIDARCANALES=SI the check reaches templates, Meta and push devices).
-6 Request limit reached — per destination, or of VALIDARCANALES=SI (you will get Espera in seconds).
-8 The destination is not valid (unknown international prefix).
-12 The code could not be sent through any channel (Error contains the last reason).
-16 Destination rejected by the ANTIFRAUDE=SI check (you will get Antifraude with the risk and its reasons).

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.

Request samples

Content type
{
  • "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"
}

Response samples

Content type
[
  • {
    }
]

Validate OTP

/ValidarOTP

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.

Authorizations:
basicAuth
query Parameters
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 '+'.

Email
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.
JSON - The response is returned as JSON
XML - The response is returned as XML
TXT - The response is returned as plain text

Request Body schema:

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
Email
string
Appid
integer
Codigo
required
string
Resp
string

Responses

Response Schema:
Array
Res
required
integer <int32>

Result of the requested function
1 Validation SUCCESSFUL (you will get FechaValidado and Intentos).
-1 Authentication error.
-2 There is no OTP request with this data.
-3 Error in the request data (you will get Error).
-4 The code has expired.
-5 Code already validated (you will get Fecha with the validation date).
-6 Maximum number of failed attempts exceeded.
-7 The code must have between 3 and 10 characters.
-8 Incorrect code (you will get IntentosRestantes when there is a limit).
-9 Invalid destination.

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.

Request samples

Content type
{
  • "Idotp": "88231",
  • "Destinatario": "34600000001",
  • "Email": "user@example.com",
  • "Appid": "0",
  • "Codigo": "430913",
  • "Resp": "JSON"
}

Response samples

Content type
[
  • {
    }
]

Query OTP

/ConsultarOTP

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.

Authorizations:
basicAuth
query Parameters
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.

Email
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.
JSON - The response is returned as JSON
XML - The response is returned as XML
TXT - The response is returned as plain text

Request Body schema:

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
Email
string
Appid
integer
Resp
string

Responses

Response Schema:
Array
Res
required
integer <int32>

Result of the requested function
1 Request found.
-1 Authentication error.
-2 There is no OTP request with this data.
-3 Error in the request data (you will get Error).
-6 Per-minute query limit reached (you will get Espera in seconds).
-9 Invalid destination.
-10 Your account has a webhook configured and the delivery is not resolved yet: wait for the webhook (Tipo:OTP) instead of polling.

idOTP
integer

Identifier of the request.

App
integer

APPID of the request.

Telefono
string

Destination phone (empty when the OTP was email/push only).

Email
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.

Request samples

Content type
{
  • "Idotp": "88231",
  • "Destinatario": "34600000001",
  • "Email": "user@example.com",
  • "Appid": "0",
  • "Resp": "JSON"
}

Response samples

Content type
[
  • {
    }
]

OTP requests report

/GetReportOTP

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.

Authorizations:
basicAuth
query Parameters
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.
JSON - The response is returned as JSON
XML - The response is returned as XML
TXT - The response is returned as plain text

Request Body schema:

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

Responses

Response Schema:
Array
Res
required
integer <int32>

Result of the requested function
1 List returned.
-1 Authentication error.
-3 Error in the request data (you will get Error).
-4 FECHAHASTA must be greater than FECHADESDE and the maximum range is 31 days.

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.

Request samples

Content type
{
  • "Fechadesde": "2026-08-01 00:00",
  • "Fechahasta": "2026-08-31 23:59",
  • "Appid": "-1",
  • "Max": "1000",
  • "Resp": "JSON"
}

Response samples

Content type
[
  • {
    }
]