SmartOTP Overview
SmartOTP is CAKE's soft-token service: a partner app registers a device, activates it with a client secret key, and then generates TOTP codes offline. Codes come in two strengths — basic OTP derived from the secret and time, and advance OTP additionally bound to a specific transaction through a challenge key.
INFO
Every sample in this documentation uses the same fictional identity — Nguyễn Văn A, NID 001xxxxxxxxx, user_id user_00000001, ref_id ref_00000001. Credentials, tokens and keys appear as <PLACEHOLDER>. None of it is real data; replace it all with your own values.
Prerequisites
| What | Description |
|---|---|
| Partner ID | Identifies your organization. Sent in every request body as partner_id. Provided by CAKE. |
| Partner Key | The secret paired with your Partner ID. Sent in every request body as partner_key. Provided by CAKE. |
| Base URL | Issued by CAKE per partner, in the form https://<HOSTNAME>/api/v1. |
| Mobile SDK | The SOTP SDK embedded in your app holds the secret, validates the PIN, and generates codes. |
| Firebase push token | Required at activation so the server can push challenge keys to the device. |
WARNING
Every request must use https, never http — the partner_key travels in the request body, so a plaintext request discloses your partner credential.
Samples throughout this documentation write the base URL as <BASE_URL> — substitute the value above.
Core Concepts
Key Derivation
| Field | Type | Description |
|---|---|---|
| Client secret key | string | Hashed from user_id, device_id and registration_id (unique_id) with the server's private key. Returned by Activate as key. |
| Challenge key | string | Hashed from user_id, device_id, registration_id, app_id, transaction_id, transaction_amount and unique_id with the server's private key. Returned by Create Transaction. |
OTP Types
| Field | Type | Description |
|---|---|---|
basic | string | Generated from TOTP using the client secret key and the current time. Not bound to any transaction. |
advance | string | Generated from TOTP using the client secret key, the challenge key and the current time. Bound to one specific transaction. |
Advance OTP is what makes the code non-transferable: because the challenge key encodes the transaction amount and ID, a code captured for one transfer cannot authorize a different one.
TOTP parameters
Returned by Activate and Sync Time:
| Field | Type | Description |
|---|---|---|
algorithm | string | HmacSHA512. |
period | int | Seconds a code stays valid — 15. |
length | int | Number of digits — 6. |
type | string | totp. |
issuer | string | SOTP. |
A 15-second period is much shorter than the 30-second default most authenticator apps assume. Clock drift matters — call Sync Time when validation starts failing.
Authentication
The API is JSON-based and authorized by partner_id and partner_key sent in the body of each call, not in a header.
POST /api/v1/saas-sotp/get-status HTTP/1.1
Host: <HOSTNAME>
Content-Type: application/json
Accept: application/json
Accept-Charset: utf-8
partner_id={{partner_id}}&partner_key={{partner_key}}&token={{token}}Most requests also require the device's token, generated by Register. The two exceptions are Register itself and Activate.
WARNING
partner_id and partner_key are backend credentials and must never ship inside your mobile app. The device-scoped token is what the app is allowed to hold. Proxy every SmartOTP call through your own Partner API.
How It Works
sequenceDiagram
autonumber
participant User
participant App as Mobile App + SDK
participant PA as Partner API
participant SOTP as Soft-OTP API
Note over App,SOTP: Phase 1 — Register and activate
App->>PA: Begin Smart OTP setup
PA->>SOTP: POST /register
SOTP-->>PA: registration_id, activation_key, token
PA->>SOTP: POST /activate (+ push_token)
SOTP-->>PA: key, period, algorithm, length
PA-->>App: TOTP config + secret
Note over App: SDK stores secret behind the user's PIN
Note over User,SOTP: Phase 2 — Advance OTP for a transaction
User->>App: Enter amount, receiver, description
App->>PA: Create transaction
PA->>SOTP: POST /create-transaction
SOTP-->>PA: challenge_key
SOTP-->>App: challenge_key pushed via Firebase
PA-->>App: transaction_id, otp_type
User->>App: Enter PIN
App->>App: isValidPin, then generateSmartOTP(pin, challenge_key)
User->>App: Confirm transaction
App->>PA: transaction_id + OTP
PA->>SOTP: POST /validate-sotp (otp_type advance)
SOTP-->>PA: code 1 Success
PA-->>App: Approved
Phase 1 — Register and activate
- Your Partner API calls Register, which returns
registration_id, a one-timeactivation_key, and the devicetoken. - It then calls Activate with the
activation_keyand the device's Firebasepush_token. The response carries the client secretkeyand the TOTP configuration. - The SDK stores the secret on the device, protected by the user's PIN.
Phase 2 — Basic OTP
For a login or a low-risk action, the app validates the PIN and generates a code with no transaction context:
SdkSoft.isValidPin(pin = "pin") // false → show an error, ask again
val otp = SdkSoft.generateSmartOTP(pin = "PIN")Your Partner API then calls Validate OTP with otp_type: "basic".
Phase 3 — Advance OTP
- The user enters the transaction details and your Partner API records the transaction.
- Your Partner API calls Create Transaction. The Soft-OTP API generates the
challenge_key, returns it, and pushes it to the device via Firebase. - Your Partner API returns
transaction_idandotp_typeto the app — plus thechallenge_keyitself when push notifications are switched off. - The app validates the PIN and generates the bound code:
SdkSoft.isValidPin(pin = "pin")
val otp = SdkSoft.generateSmartOTP(pin = "PIN", challenge_key = "fake_challenge_key")- The user confirms; the app sends
transaction_idand the OTP to your Partner API. - Your Partner API calls Validate OTP with
otp_type: "advance"and thetransaction_id, then converts the result into its own status code for the app.
Phase 4 — Sync time
TOTP depends on the device clock. When the user opens the app, the SDK can call Sync Time through your Partner API to check period and client_timestamp against the server and return the server timestamp.
Shared Response Envelope
{
"success": true,
"code": 1,
"message": "Success",
"data": {}
}| Field | Type | Description |
|---|---|---|
success | bool | Request status. |
code | int | The status code. 1 means success — not 0 as in CAKE's eKYC, NFC and FaceAuthen APIs. |
message | string | The status or error message. |
data | object | Endpoint-specific payload. Some endpoints return fields at the top level instead. |
WARNING
Success on this API is code: 1. If you already integrate CAKE eKYC, NFC or FaceAuthen, note those use code: 0 for success — reusing a shared response handler across both will misread every SmartOTP result.
Error Codes
Messages are returned in Vietnamese, reproduced verbatim below.
| Code | Message |
|---|---|
1 | Success (OTP hợp lệ) |
3 | Parameter invalid |
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. |
125 | OTP hết hạn sử dụng. — OTP expired. |
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. |
190001 | Thông tin không hợp lệ, device_id đã kích hoạt Soft-OTP. — Device already activated. |
190005 | SmartOTP đang kích hoạt trên một thiết bị khác. — SmartOTP is active on another device. |
190108 | Tài khoản chưa hoạt động. — Account not activated. |
190201 | Không thể tạo transaction hoặc transaction_id đã tồn tại. — Cannot create transaction, or the ID already exists. |
190203 | Không tìm thấy transaction. — Transaction not found. |
190301 | Period không chính xác. — Incorrect period. |
190303 | Client time không chính xác. — Incorrect client time. |
Next Steps
- Register — create a device registration and get the activation key
- Activate — activate the device and receive the client secret
- Get Status — check a device's SmartOTP status
- Retire — deactivate a device's SmartOTP
- Create Transaction — mint a challenge key for advance OTP
- Get Transaction — read a transaction and its challenge key
- Get Latest Transaction — read the most recent transaction
- Sync Time — reconcile the device clock with the server
- Validate OTP — verify a basic or advance OTP
- Testing — generate codes with Google Authenticator or a Python script
- Error Codes — the full API error reference