Send OTP
This interface is used to generate a verification code by the EngageLab platform and send it according to the channel strategy specified in the template.
If you prefer to generate the verification code yourself instead of having the EngageLab platform generate it, you can call the EngageLab OTP Custom Send OTP interface.
Request URL
POST https://otp.api.engagelab.cc/v1/messages
Authentication
Please refer to Authentication to learn how to perform API authentication.
Request Example
Request Header
POST /v1/messages HTTP/1.1
Content-Type: application/json
Authorization: Basic amlndWFuZ2RldjpkZXZfc2VjcmV0
Request Body
{
"to": "+6591234567",
"template":{
"id":"test-template-1",
"language": "default",
"params": {
"key1": "value1",
"key2": "value2"
}
}
}
Request Parameters
A request object is expressed in JSON format, so the request header must include Content-Type: application/json.
| Parameter | Type | Option | Description |
|---|---|---|---|
| to | String | Required | Sending target, mobile number or email address, +6598765432, support@engagelab.com |
| end_user_ip | String | Optional | End user's IP address. Used when you need to limit the maximum requests from the same IP address across different time windows, e.g.: 10.3.5.7 |
| channel | String | Optional | Specifies the first sending channel. Values: sms/voice/zalo/viber. If omitted, routing follows the template send_channel_strategy. |
| template | JSON Object | Required | Template information, see secondary parameters below |
| |_ id | String | Required | Template ID |
| |_ language | String | Optional | Template language, supports the following languages: default (Default language) zh_CN (Simplified Chinese) zh_HK (Traditional Chinese) en (English) ja (Japanese) th (Thai) es (Spanish) If not passed, it defaults to default. |
| |_ params | JSON Object | Optional | Values for custom template variable keys. If you customized variables when creating the template, pass their values here. If not passed, they will be sent directly as variable keys, such as {{var}} |
Notes on params
- For fields preset in the template such as
from_id, if theparamsfield value is not passed, the presetfrom_idof the template will be used when the message is sent; - If a
paramsfield value is passed, such asparams:{"from_id":"12345"}, the template'sfrom_idwill be replaced with 12345 when the message is sent; - At the same time, for custom variable fields in the template content when creating the template, they are also assigned values through
params. For example, if the template content isHi {{name}}, your verify code is {{code}}, you need to assign the parameterparams:{"name":"Bob"}. - Email Channel Special Variables: For the Email channel, you can dynamically override the email subject (
subject), sender name (from_name), sender email (from_mail), etc., throughparams. For detailed advanced usage, please refer to Create Template - Email Template Variables Advanced Usage.
Response Parameters
Success Response
| Field | Type | Option | Description |
|---|---|---|---|
| message_id | String | Required | Message ID, uniquely identifies a message |
| send_channel | String | Required | Indicates the current sending channel, values are whatsapp/sms/email/voice/zalo/viber |
{
"message_id": "1725407449772531712",
"send_channel": "sms"
}
Note that the returned send_channel value does not represent the final channel delivered to the user, but only represents the channel used at this stage; for example, if the strategy configured in the template specifies that the WhatsApp channel fails to deliver and then automatically falls back to the SMS channel, the interface will return the whatsapp value. After sensing the delivery failure after a certain period of time, the system will use the SMS channel to send.
Failure Response
The HTTP status code is 4xx or 5xx, and the response body contains the following fields:
| Field | Type | Option | Description |
|---|---|---|---|
| code | int | Required | Error code, see error code description for details |
| message | String | Required | Error details |
{
"code": 5001,
"message": "sms send fail"
}
Error Codes
The table below only describes errors returned by this API during authentication, pre-send validation, and synchronous submission. Asynchronous delivery failures after a provider accepts the message are not returned by this API; obtain them via message status queries or callbacks.
Callers should use code to determine the error type. Use message to display the specific reason or for troubleshooting; do not rely on fixed message text for business logic.
| Error Code | HTTP Code | Description |
|---|---|---|
| 1000 | 500 | Internal error |
| 2001 | 401 | Authentication failed, incorrect token carried |
| 2002 | 401 | Authentication failed, token has expired or been disabled |
| 2003 | 403 | This IP is not allowed to send message. |
| 2004 | 403 | No permission to call this API |
| 3001 | 400 | Invalid request parameter format, please check if the JSON content conforms to the parameter format |
| 3002 | 400 | Incorrect request parameters, please check if the request parameters meet the requirements |
| 3003 | 400 | Incorrect request parameters, related business verification failed, please refer to the error description in the message field for details |
| 3004 | 400 | Frequency limit exceeded, for the same template and the same target user, it cannot be sent again within the validity period of the verification code |
| 3005 | 400 | Insufficient available account balance |
| 3013 | 400 | Template not approved or currently unavailable |
| 4001 | 400 | Related resource does not exist, such as using a non-existent template when sending a template message |
| 5001 | 400 | Sending failed (general/other) |
| 5011 | 400 | Invalid mobile number format |
| 5012 | 400 | Target unreachable |
| 5013 | 400 | Number is blacklisted |
| 5014 | 400 | Content does not meet specifications |
| 5015 | 400 | Message intercepted/rejected |
| 5016 | 400 | Internal sending error |
| 5017 | 400 | No sending permission for China region |
| 5018 | 400 | Mobile phone failure (powered off/out of service) |
| 5019 | 400 | User has unsubscribed |
| 5020 | 400 | Number unregistered/empty number |
| 6001 | 429 | Send frequency for the same phone number exceeded; the limit window may be per minute, hour, or calendar day |
| 6002 | 429 | Send frequency for the same end-user IP exceeded; the limit window may be per minute or hour; checked only when end_user_ip is included in the request |
| 6003 | 429 | Application global daily or monthly send volume reached the limit |
| 6006 | 403 | Sending is not allowed for the current country or region |
| 6007 | 403 | SMS verification code sending service is suspended; may apply to all countries/regions or the current country/region |
| 6008 | 429 | Daily or monthly send volume for the current country or region reached the limit |
Rate limit and send volume error notes
3004is template OTP send rate control; the limit window is based on template configuration and may not equal the OTP validity period.6001and6002are security rate controls at the phone number or end-user IP dimension.6003and6008indicate this request hit a send volume limit; after the limit is reached and the service enters a suspended state, subsequent requests may return6007.- When you receive HTTP 429, do not retry immediately in a loop; retry later, and contact an administrator or technical support if it persists.
5011through5019only cover failures identifiable during synchronous submission. Statuses such as empty numbers, powered-off phones, or carrier rejections that occur after a provider accepts the message may still be returned via asynchronous message status or callbacks.










