Skip to main content
Once a code is in flight, three lifecycle endpoints let you keep state coherent without rebuilding the request flow: All three are scoped to your Developer App. An OTP issued under app A cannot be touched via app B.

Resend

Issue a new OTP after invalidating the previous one. Body shape and channel-specific fields are identical to /v1/otp/request; only the path changes.
POST https://karibu.briq.tz/v1/otp/resend

Common request fields

These fields are the same on every channel:
FieldTypeRequiredDefaultNotes
phone_numberstring (E.164 digits)yesDigits only, no +.
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.
sender_id and message_template are SMS-only — they appear in the SMS tab below and are silently ignored on "call" and "whatsapp".

Success response

{
  "success": true,
  "message": "OTP resent successfully.",
  "data": { "expires_at": "2026-05-08T12:45:01.000000" },
  "status_code": 200
}
Errors mirror /request exactly. See Error scenarios.
request vs resend — what’s the difference? Functionally both invalidate any prior active OTP and dispatch a new one. Use /resend when the end user explicitly clicks “Resend code”; this lets you treat it differently in your analytics, rate-limits, or UI without changing payloads.
Switching channels on resend is allowed — e.g. user clicks “I didn’t get the SMS, send via WhatsApp instead.” Just send the new delivery_method. The previous active OTP is invalidated regardless of which channel issued it.

Channel-specific payload & code samples

Customisable 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.
curl -X POST https://karibu.briq.tz/v1/otp/resend \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "255712345678",
    "app_key": "YOUR_APP_KEY",
    "delivery_method": "sms",
    "sender_id": "BRIQ OTP",
    "message_template": "Your verification code is {code}. It expires in {expiry} minutes."
  }'

Invalidate

Force-expire any active OTP for a phone scoped to your Developer App. Useful on logout, security events (suspicious activity, password change), or when the user changes their phone number.
POST https://karibu.briq.tz/v1/otp/invalidate

Request body

FieldTypeRequired
phone_numberstring (E.164 digits)yes
app_keystringyes

Success response

{
  "success": true,
  "message": "OTP invalidated successfully.",
  "data": null,
  "status_code": 200
}
Idempotent. Calling this when there is no active OTP also returns 200 — it simply has nothing to invalidate. Safe to fire from a logout handler without checking state first.

Code samples

curl -X POST https://karibu.briq.tz/v1/otp/invalidate \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "255712345678",
    "app_key": "YOUR_APP_KEY"
  }'

Status

Inspect the currently active OTP for a phone, scoped to your Developer App, without triggering a send. Useful for UI countdowns, diagnostics, and idempotent UX (e.g. “an OTP was already sent — please check your phone”).
GET https://karibu.briq.tz/v1/otp/status

Query parameters

ParamRequired
phone_numberyes
app_keyyes

Success response

{
  "success": true,
  "message": "OTP status retrieved.",
  "data": {
    "is_valid": true,
    "expires_at": "2026-05-08T12:45:01.000000",
    "remaining_attempts": 3
  },
  "status_code": 200
}

No active OTP

{
  "success": false,
  "message": "No active OTP found.",
  "data": null,
  "status_code": 404
}
The HTTP response body wraps status_code: 404, but the underlying HTTP response itself is 200 OK. Inspect body.success and body.status_code, not the raw HTTP status, when handling this endpoint.

Code samples

curl -G https://karibu.briq.tz/v1/otp/status \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "phone_number=255712345678" \
  --data-urlencode "app_key=YOUR_APP_KEY"

Best practices

  • Use /status to drive countdown UI, not speculative resends. Polling is cheap; firing duplicate /request calls invalidates the in-flight code and confuses the user.
  • Always invalidate on logout. It’s idempotent — no need to check state first.
  • Treat is_valid: true, remaining_attempts: 0 as a locked OTP. The user has burned all 3 attempts and must resend.
For full payload tables, error matrices, and the canonical reference, see the Karibu OTP API reference.