Validate OTP
Verifies a basic or advance OTP. Both use the same endpoint, distinguished by otp_type — advance additionally requires the transaction_id the code was bound to.
Endpoint
POST /api/v1/saas-sotp/validate-sotp
Content-Type: application/jsonBasic OTP
Verifies a code generated from the client secret and time alone, with no transaction context.
Parameters:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
partner_id | string | Yes | — | The partner id. |
partner_key | string | Yes | — | The partner key. |
token | string | Yes | — | The registration token generated by Register. |
app_id | string | Yes | — | The app id, used for tracking. |
otp | string | Yes | — | The OTP generated by the SDK from the key returned by Activate. |
otp_type | string | Yes | — | basic when verifying a basic Soft OTP. |
curl --location --request POST '<BASE_URL>/saas-sotp/validate-sotp' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"partner_id": "{{partner_id}}",
"partner_key": "{{partner_key}}",
"token": "{{token}}",
"app_id": "{{app_id}}",
"otp": "123456",
"otp_type": "basic"
}'Advance OTP
Verifies a code bound to one transaction through its challenge key.
Parameters:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
partner_id | string | Yes | — | The partner id. |
partner_key | string | Yes | — | The partner key. |
token | string | Yes | — | The registration token generated by Register. |
app_id | string | Yes | — | The app id, used for tracking. |
otp | string | Yes | — | The OTP generated by the SDK from the key returned by Activate. |
otp_type | string | Yes | — | advance when verifying an advance Soft OTP. |
transaction_id | string | Yes | — | The unique transaction id on the partner side. |
curl --location --request POST '<BASE_URL>/saas-sotp/validate-sotp' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"partner_id": "{{partner_id}}",
"partner_key": "{{partner_key}}",
"token": "{{token}}",
"app_id": "{{app_id}}",
"transaction_id": "{{transaction_id}}",
"otp": "123456",
"otp_type": "advance"
}'WARNING
Use advance for anything that moves money. A basic OTP proves only that the user holds the device — it is not bound to the amount or the recipient, so a code captured during one action can authorize a different one.
Response
{
"success": true,
"code": 1,
"message": "Success"
}| Field | Type | Description |
|---|---|---|
success | bool | Request status. |
code | int | The status code — 1 means the OTP is valid. |
message | string | The status or error message. |
Validate this on your backend and convert it into your own status code before returning anything to the app.
Errors
| Code | Description |
|---|---|
103 | Thông tin Partner không chính xác — Partner details are incorrect. |
121 | Yêu cầu vượt giới hạn. Vui lòng thử lại sau ít phút. — Request limit exceeded. |
123 | Yêu cầu vượt giới hạn. Vui lòng thử lại sau ít phút. — Request limit exceeded. |
124 | OTP không hợp lệ — Invalid OTP. |
126 | Có lỗi xảy ra vui lòng thử lại — An error occurred, please retry. |
129 | Token không hợp lệ — Invalid token. |
190108 | Tài khoản chưa hoạt động — Account not activated. |
190203 | Không tìm thấy transaction — Transaction not found. Advance OTP only. |
Repeated 124 responses that the user believes are correct usually mean clock drift, not a wrong code — call Sync Time.
Next Steps
- Sync Time — diagnose repeated invalid-OTP failures
- Create Transaction — mint the challenge key an advance OTP needs