Skip to main content
Use POST /v1/otp/request to generate a fresh numeric OTP and deliver it to a phone via SMS (default), voice call, or WhatsApp. The endpoint is scoped to a Developer App you own — every request must include your app_key. Calling it always invalidates any prior unused, unexpired OTP for the same (phone, app) before issuing the new one, so there is never more than one active OTP for a phone within an app. Each channel has its own payload shape. The fields sender_id and message_template are SMS-only — they exist for SMS branding/wording control and are silently ignored on "call" and "whatsapp". Voice reads the code via TTS; WhatsApp routes through the platform-managed briq_otp template with automatic sender resolution. Default to "sms" for the broadest reach. Use "call" for SMS-restricted regions or accessibility needs, and "whatsapp" for app-installed users with chat-first habits.

Endpoint

POST https://karibu.briq.tz/v1/otp/request
Headers: X-API-Key (required), Content-Type: application/json (required), X-App-ID (optional — must match the API key’s bound app if both are scoped).

Common request fields

These fields are the same on every channel:
FieldTypeRequiredDefaultNotes
phone_numberstring (E.164 digits)yesDigits only, no +. e.g. 255712345678.
app_keystringyesFrom your Developer App.
delivery_methodstringyes (recommended)"sms"One of "sms", "call", "whatsapp".
otp_lengthintno6Length of the generated code.
minutes_to_expireintno10TTL in minutes.

Success response

The same shape on every channel:
{
  "success": true,
  "message": "OTP Code sent successfully.",
  "data": { "expires_at": "2026-05-08T12:34:56.000000" },
  "status_code": 200
}
The plaintext code is never returned. The recipient receives it via SMS, voice call, or WhatsApp only. Don’t try to capture or log it on the server.

Channel-specific payload & code samples

Default channel. Customisable per call via sender_id and message_template.Channel-specific fields:
FieldTypeRequiredDefaultNotes
sender_idstringnoOTP_DEFAULT_SENDER_IDThe SMS sender ID shown to the recipient. Must be approved for your account.
message_templatestringnoserver defaultMust contain {code}. {expiry} is also substituted. Falls back if {code} missing.
Exact payload:
{
  "phone_number": "255712345678",
  "app_key": "YOUR_APP_KEY",
  "delivery_method": "sms",
  "otp_length": 6,
  "minutes_to_expire": 10,
  "sender_id": "BRIQ OTP",
  "message_template": "Your verification code is {code}. It expires in {expiry} minutes."
}
curl -X POST https://karibu.briq.tz/v1/otp/request \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "255712345678",
    "app_key": "YOUR_APP_KEY",
    "delivery_method": "sms",
    "otp_length": 6,
    "minutes_to_expire": 10,
    "sender_id": "BRIQ OTP",
    "message_template": "Your verification code is {code}. It expires in {expiry} minutes."
  }'

Error responses

HTTPCauseShape
400invalid phone, send failure, unsupported delivery_method, WhatsApp dispatcher errors (NO_DEFAULT_SENDER, TEMPLATE_NOT_APPROVED)envelope with success: false and a message
401missing/expired X-API-Key{"detail": "Invalid or expired API key"}
403wrong host, app_key not yours, app_key mismatch with the bound app, workspace not dev-accessible{"detail": "..."}
422malformed body (e.g. non-digit phone, missing fields)FastAPI validation error
For the full cross-endpoint error reference, see Error scenarios.

Best practices

  • Validate the phone client-side before calling the API: digits-only, country code present, plausible length.
  • Store data.expires_at so your UI can drive a countdown timer; consider polling /v1/otp/status instead of triggering re-sends speculatively.
  • Cascade channels for reliability. A common pattern: try "whatsapp" first; on a dispatcher 400, fall back to "sms"; offer "call" as a manual third option.
  • Don’t promise custom WhatsApp wording. The briq_otp template is fixed by Meta — sender_id and message_template are silently ignored on "whatsapp" and "call".
  • Rate-limit your own users. The API does not enforce per-phone request limits — your application should.
  • Never log the plaintext code. It only exists in transit to the recipient.

What’s next