Prerequisites
To use OTP services you need:- A workspace with
developer_access = true. Toggle this in the Briq UI under workspace settings, or see Workspaces. - A Developer App linked to that workspace. See Developer Apps.
- An active developer API key (
X-API-Keyheader) bound to that Developer App — at key creation or via the attach endpoint. Karibu resolves the app from the key; bound keys need onlyX-API-Keyon every OTP call. - Recipient phone numbers in E.164 digits-only format (no
+, no spaces) — e.g.255712345678.
Bind every OTP API key to a Developer App and keep it server-side. Never expose your API key to client apps or browsers — have your frontend call your backend, which then calls Karibu with
X-API-Key only.Legacy integrations with an unbound API key may scope requests via the optional X-App-ID header or an app_key field in the body. New integrations should bind the key instead.Behavioral rules to internalize
These rules drive correct UX and prevent the most common integration bugs. Read them once before writing code.End-to-end flow
A typical phone-verification flow:- User enters phone in your UI → your backend calls
POST /v1/otp/requestwith the appropriatedelivery_method. → see Requesting OTP codes. - User receives SMS, voice call, or WhatsApp message with the plaintext code.
- 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 offdata.remaining_attempts.
- On
- 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. - User logs out / changes phone → your backend calls
POST /v1/otp/invalidate. - Optional: poll
GET /v1/otp/statusto drive countdown timers or detect that an OTP is already in-flight before issuing a new one. - Optional: pass
callback_urlonrequestorresendif you want asyncflake.verified/flake.failednotifications at your HTTPS endpoint when the user verifies. → see Flake lifecycle callbacks.
Standard response envelope
Every OTP endpoint returns the same JSON envelope: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.