Skip to main content
OTP (one-time passwords) are short, time-limited numeric codes sent to a user’s phone to confirm identity for sign-in, registration, or sensitive actions. Briq’s OTP API generates the code, delivers it via SMS, voice call, or WhatsApp, and then verifies what the user submits — all scoped to a Developer App you own. This page is the integrator’s overview: what to set up, the rules the API enforces, and how the pieces fit together. For payload-level detail, see the Karibu OTP API reference.

Prerequisites

To use OTP services you need:
  1. A workspace with developer_access = true. Toggle this in the Briq UI under workspace settings, or see Workspaces.
  2. A Developer App linked to that workspace. Each app gives you an app_key (sent in every OTP request body) and an app_id (optional X-App-ID header). See Developer Apps.
  3. An active developer API key (X-API-Key header). Generate one in the Briq dashboard.
  4. Recipient phone numbers in E.164 digits-only format (no +, no spaces) — e.g. 255712345678.
The app_key is a credential. Hold it server-side; never ship it to untrusted clients. Have your frontend call your backend, which then calls Karibu.

Behavioral rules to internalize

These rules drive correct UX and prevent the most common integration bugs. Read them once before writing code.
RuleDetail
Single active OTP per (phone, app)request and resend invalidate any prior unused, unexpired OTP for the same phone + app before issuing a new one. There is never more than one active OTP for a phone within an app.
Hashed at restOTP codes are bcrypt-hashed in the database. The plaintext is delivered only via SMS/call to the recipient. The server will never return it in any response.
3-attempt cap on verifyAfter 3 wrong codes the OTP is auto-locked (marked used) and remaining_attempts becomes 0. The user must request a new OTP.
Phone formatE.164 digits only, no +. Invalid input → 400 "Invalid phone number".
Cross-app isolationVerify, resend, invalidate, and status all operate only on OTPs issued under the same Developer App. An OTP issued under app A cannot be touched via app B.
Default expiry10 minutes. Configure per call via minutes_to_expire.
Default OTP length6 digits. Configure per call via otp_length.
Delivery channel"sms" (default), "call", or "whatsapp". Each has its own payload shape — see the per-channel tabs in Requesting OTP codes.
Channel-specific fieldssender_id and message_template are SMS-only — silently ignored on "call" and "whatsapp". Voice reads the code via TTS; WhatsApp uses the approved briq_otp template.

End-to-end flow

A typical phone-verification flow:
  1. User enters phone in your UI → your backend calls POST /v1/otp/request with the appropriate delivery_method. → see Requesting OTP codes.
  2. User receives SMS, voice call, or WhatsApp message with the plaintext code.
  3. User submits code in your UI → your backend calls POST /v1/otp/verify. → see Validating OTP codes.
    • On success: true → mark phone verified and continue.
    • On success: false → drive the UX off data.remaining_attempts.
  4. User clicks “Resend” → your backend calls POST /v1/otp/resend (which invalidates the prior code automatically). You may switch channels here — e.g. retry on WhatsApp after an SMS didn’t arrive. → see Managing OTP lifecycle.
  5. User logs out / changes phone → your backend calls POST /v1/otp/invalidate.
  6. Optional: poll GET /v1/otp/status to drive countdown timers or detect that an OTP is already in-flight before issuing a new one.

Standard response envelope

Every OTP endpoint returns the same JSON envelope:
{
  "success": true,
  "message": "Human-readable summary",
  "data": { /* endpoint-specific payload, or null */ },
  "status_code": 200
}
Inspect body.success and body.status_code rather than the raw HTTP status — /v1/otp/status returns HTTP 200 wrapping status_code: 404 when no active OTP exists. Auth, host, and validation errors (401/403/422) follow FastAPI’s {"detail": "..."} shape instead — they bypass the envelope.
For complete payload tables, error matrices, and copy-pasteable client snippets in cURL, Python, Node.js, and PHP, see the Karibu OTP API reference.
Need to send WhatsApp messages beyond OTP, such as notifications, templates, media, or interactive flows? See the WhatsApp guide.