One-Time Passwords (OTPs)
One-Time Passwords (OTPs) enable verification flows where you need to confirm control of a phone number or authorize a sensitive action. Generate a time-limited token, deliver it by SMS, and verify the recipient's submission.
The OTP transaction object
An OTP transaction represents a complete verification session from token generation through delivery and verification. Each transaction tracks delivery status, expiration time, and verification attempts.
Properties
- Name
status- Type
- string
- Description
Current transaction status. Possible values are
canceled,expired,pending,pending_delivery,pending_verification, andverified.pending_deliverymeans transmission details are not available yet;pending_verificationmeans the message was sent and the transaction is waiting for a verification attempt.
Initiate OTP transaction
Generate a one-time password, deliver it to an international phone number by SMS, and return a typed transaction ID for verification. Use an idempotency key so a retry does not send a second token.
Required attributes
Optional attributes
Request
curl https://api.zebo.dev/otp/initiate \
-H "Authorization: Bearer $COMMERCE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: otp-login-67890" \
-d '{
"message_template": "Your {service} code is {token}.",
"purpose": "transaction_confirm",
"recipient": "+233241234567",
"sender": "Acme",
"service_name": "Acme Bank",
"token_alphabet_type": "numeric",
"token_size": 6,
"validity_duration_in_minutes": 10
}'
{
"transaction": {
"expires_at": "2026-08-28T10:10:00Z",
"full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
"id": "ot_<TRANSACTION_ID>",
"initiated_at": "2026-08-28T10:00:00Z",
"status": "pending_verification",
"transmission": {
"recipient": "+233241234567",
"sender_id": "Acme",
"sent_at": "2026-08-28T10:00:01Z",
"sent_via": "sms",
"status": "sent"
}
}
}
Verify OTP
Record a verification attempt for a user-submitted token. An HTTP 200 response means the attempt was recorded; it does not mean the token matched. Authorize the user or action only when verification_attempt.result.verdict is pass.
Required attributes
Request
response=$(curl https://api.zebo.dev/otp/verify \
-H "Authorization: Bearer $COMMERCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipient": "+233241234567",
"token": "<OTP_CODE_FROM_USER>",
"transaction_id": "ot_<TRANSACTION_ID>"
}')
jq -e '.verification_attempt.result.verdict == "pass"' <<< "$response"
A failed match still returns HTTP 200 with a fail verdict. This response excerpt intentionally omits the submitted token; do not log verification request or response bodies.
{
"verification_attempt": {
"attempted_at": "2026-08-28T10:03:00Z",
"id": "ov_<ATTEMPT_ID>",
"recipient": "+233241234567",
"result": {
"detail": "token_mismatch",
"verdict": "fail"
}
},
"transaction": {
"expires_at": "2026-08-28T10:10:00Z",
"full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
"id": "ot_<TRANSACTION_ID>",
"initiated_at": "2026-08-28T10:00:00Z",
"status": "pending_verification",
"transmission": {
"recipient": "+233241234567",
"sender_id": "Acme",
"sent_at": "2026-08-28T10:00:01Z",
"sent_via": "sms",
"status": "sent"
}
}
}
Lookup OTP transaction
Retrieve details of an existing OTP transaction by its ID. Check transaction status, delivery state, and verification status.
Required attributes
Request
curl https://api.zebo.dev/otp/lookup \
-H "Authorization: Bearer $COMMERCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"transaction_id": "ot_<TRANSACTION_ID>"
}'
{
"transaction": {
"expires_at": "2026-08-28T10:10:00Z",
"full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
"id": "ot_<TRANSACTION_ID>",
"initiated_at": "2026-08-28T10:00:00Z",
"status": "pending_verification",
"transmission": {
"recipient": "+233241234567",
"sender_id": "Acme",
"sent_at": "2026-08-28T10:00:01Z",
"sent_via": "sms",
"status": "sent"
}
}
}
Cancel OTP transaction
Cancel an active OTP transaction to prevent further verification attempts. Cancel when a user requests a new OTP, when suspicious activity is detected, or when the authentication flow is abandoned. Canceled transactions cannot be verified even if the token hasn't expired.
Required attributes
Optional attributes
Request
curl https://api.zebo.dev/otp/cancel \
-H "Authorization: Bearer $COMMERCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "user_requested_new_code",
"transaction_id": "ot_<TRANSACTION_ID>"
}'
{
"transaction": {
"cancel_reason": "user_requested_new_code",
"canceled_at": "2026-08-28T10:02:00Z",
"created_at": "2026-08-28T10:00:00Z",
"delivered_at": "2026-08-28T10:00:01Z",
"full_message": "Your Acme Bank code is {token}.",
"id": "ot_<TRANSACTION_ID>",
"mechanism": "sms",
"recipient": "+233241234567",
"sender": "Acme",
"status": "canceled",
"verifiable_until": "2026-08-28T10:10:00Z"
}
}