POST /v3/request when you want OTP.ID to generate and deliver the one-time code on your behalf. You choose the channel, destination, and optional parameters — OTP.ID handles code generation and delivery. The code is never returned in the API response; it travels only to the end user via the chosen channel. On success you receive a transaction ID (otp_id) you’ll use later to verify what the user enters.
Endpoint
Request Headers
Request Body
string
required
The delivery channel for the OTP. Accepted values:
whatsapp— WhatsApp messagesms— SMS text messageemail— Email messagemisscall— Missed call (the OTP code is derived from the caller’s number)whatsapp_inbound— User sends a WhatsApp message to OTP.ID to verify (see WhatsApp Inbound)
string
required
The destination phone number or email address. Required for all channels except
whatsapp_inbound.- Phone numbers: digits only, minimum 10 characters (e.g.
"6281234567890") - Email: a valid email address (e.g.
"user@example.com")
string
Alternative field for the destination email address. Used as a fallback when
number is empty and channel is email. If both number and email are provided, number takes precedence.string
The brand name included in the OTP message (e.g.
"MyApp"). Defaults to the brand_name configured on your merchant account.integer
Number of digits in the generated OTP. Accepted range:
4–8. Defaults to 6. Values outside this range are clamped to the nearest bound — not rejected.integer
Time-to-live in seconds before the OTP expires. Accepted range:
60–900. Defaults to 300 (5 minutes). Values outside this range are clamped to the nearest bound — not rejected.string
Your own idempotency key for this transaction. If you submit a request with an
external_id that already exists, OTP.ID returns the original otp_id without sending a new message and without changing your balance. See Idempotency below.Response Fields
string
The unique transaction ID assigned by OTP.ID. Use this value in subsequent calls to
POST /v3/verify and GET /v3/otp/{otp_id}. Format: OTP + YYYYMMDD + 4 letters + 6 digits (e.g. OTP20260807ABCD000001).string
Current delivery status of the transaction:
sent/success— code was delivered to the destinationpending— used forwhatsapp_inboundwhile awaiting the user’s replyfailed— vendor delivery failed (see Delivery Failures)
string
The channel used to deliver the OTP, echoed from your request.
string
The destination address used, echoed from your request.
integer
Transaction cost in IDR. This field is present even when delivery fails. No charge is applied when delivery fails — see Delivery Failures.
integer
Your account balance in IDR after this transaction. Unchanged if the delivery failed or if this was an idempotency replay.
string
The datetime at which this OTP expires, in
YYYY-MM-DD HH:MM:SS format (WIB, UTC+7).object
Present only for
whatsapp_inbound transactions. Contains the instructions your user needs to verify themselves.Examples
WhatsApp Inbound
For
whatsapp_inbound, do not pass a number. Show the user the verification.wa_link (or the wa_number + message pair) and have them tap/send it from their own WhatsApp. OTP.ID matches the inbound message to this transaction automatically — no call to POST /v3/verify is needed.Special Behaviors
Delivery Failures
When the OTP.ID vendor accepts your request but ultimately fails to deliver the message (e.g. the number is unreachable), the API still returns HTTP 200 with"status": "failed". Your balance is not deducted. Check data.status in your application logic — do not rely solely on the HTTP status code.
Example — delivery failure (HTTP 200):
Idempotency
If you provide anexternal_id and a request with that ID was already processed, OTP.ID returns the original otp_id in the response without sending a new message and without changing last_balance. This lets you safely retry requests after network timeouts. The response body is otherwise identical to the original.
WhatsApp Inbound
Whenchannel is whatsapp_inbound, the number field is optional. Omitting it means OTP.ID will accept the verification reply from any WhatsApp number that sends the matching token — useful when you do not yet know the user’s number. The transaction transitions to verified automatically when the matching message arrives.
Error Responses
All errors follow the shape{"success": false, "data": null, "error": {"code": "...", "message": "..."}}.
Example — insufficient balance:

