Skip to main content
Briq OTP codes are internally called flakes. In addition to the synchronous /v1/otp/verify response, you can register an optional per-request callback URL to receive async notifications when verification succeeds or fails. This is separate from registered app webhooks (SMS delivery events). Flake callbacks are one-off: you pass callback_url on a specific request, resend, or verify call — no webhook registration in the dashboard is required.

When to use callbacks

Callbacks are best-effort. Always use the synchronous /v1/otp/verify response as the source of truth for granting access. Treat callbacks as notifications, not as the primary auth decision.

How it works

  1. Request or resend — pass optional callback_url and callback_secret. Karibu associates them with this OTP for its lifetime (minutes_to_expire, default 10 minutes), scoped to the Developer App bound to your X-API-Key and the phone number.
  2. Verify — you get the normal synchronous /verify response first. If a callback URL was set on request/resend (or passed again on verify), Karibu also sends an async webhook to that URL shortly after.
  3. Your endpoint — receives a JSON flake.verified or flake.failed envelope. Respond with 2xx; Karibu retries on failure.
Calling /v1/otp/invalidate, or issuing a new /request or /resend, replaces the callback association for that (phone, app) pair.

Request fields

Available on POST /v1/otp/request, POST /v1/otp/resend, and POST /v1/otp/verify: On verify, you may pass callback_url without callback_secret — Karibu reuses the secret from the original request/resend when available.

Events

The plaintext OTP code is never included in callback payloads.

flake.verified payload

flake.failed payload (max attempts)

Outbound request shape

Signature verification matches registered webhooks: HMAC-SHA256 over the raw request body bytes.

Testing callbacks end-to-end

Use a public HTTPS request inspector (e.g. webhook.site) or your own staging endpoint.

Step 1 — capture a callback URL

  1. Open webhook.site (or similar) and copy your unique HTTPS URL.
  2. Optionally choose a test secret, e.g. test-callback-secret-123.

Step 2 — request an OTP with callback

Use an API key bound to your Developer App — the examples below need only X-API-Key.
The synchronous response is unchanged — you still only get expires_at, not the code.

Step 3 — verify the code

Submit the code the recipient received:
Within a few seconds, your inspector should receive a POST with event: "flake.verified".

Step 4 — verify the signature (optional)

If you set callback_secret, confirm X-Briq-Signature matches HMAC-SHA256 of the raw body. See Webhooks → Verifying signatures.

Step 5 — test failure callback

Request a new OTP (same callback_url), then call /verify three times with wrong codes. On the third failure you should receive flake.failed with reason: "max_attempts".

API playground

The Karibu OTP API reference documents callback_url and callback_secret on request, verify, and resend. Use the interactive playground on those endpoints with a bound API key and a webhook.site URL.
422 on bad URLs. http:// URLs, localhost, and hostnames that resolve to private IPs are rejected at request validation time with a 422 body error — before any OTP is sent.

Best practices

  • Return 2xx quickly from your callback handler. Briq retries on non-2xx responses with exponential backoff.
  • Make handlers idempotent — use data.flake_id or envelope id to deduplicate.
  • Do not block login on callbacks — proceed from the synchronous verify response; process the webhook asynchronously.
  • Rotate callback_secret per environment (staging vs production) and store it server-side only.
  • Use resend to update the callback — a new callback_url on /resend replaces the callback target for the new OTP window.

What’s next