A complete reference for the Webhook Management API. These endpoints let you register a callback URL for a developer app, reveal its signing secret, send test events, and inspect, audit, and retry every delivery attempt.
- API surface:
https://karibu.briq.tz/v1/webhooks/*
- Audience: backend engineers wiring Briq delivery events into their product.
- Version:
v1
The /v1/webhooks/* routes are shared across all channels. The same routes serve sms, voice, otp, whatsapp, and email - you pick the channel with the service_type field when you create a webhook. For the WhatsApp event payloads delivered to these webhooks, see the Karibu WhatsApp API reference.
1. Overview
A webhook is a callback URL Briq POSTs event payloads to when something happens to a message you sent. To receive events you:
- Create a webhook for one of your developer apps, choosing a
service_type (e.g. whatsapp).
- Fetch the signing secret and store it, so you can verify the
X-Briq-Signature header on incoming deliveries.
- Return
2xx quickly from your endpoint. Non-2xx responses, timeouts, and connection errors are treated as failures and retried.
Each emitted event is persisted as a delivery row and attempted by Briq’s delivery engine. You can list deliveries, view a single delivery’s full payload, see aggregate stats, and manually retry failed deliveries.
One webhook per app per service_type. Each developer app may have only one webhook for a given channel. Creating a second whatsapp webhook for the same app returns 400. Delete the existing one first to free the slot.
2. Authentication & host
Base URL
| Header | Required | Notes |
|---|
X-API-Key | yes | Your developer API key. Must be active and not expired. Missing/invalid -> 401. |
Host | yes | Must be karibu.briq.tz. Other hosts are rejected with 403 outside development/sandbox environments. |
Content-Type | yes (POST/PATCH) | application/json |
All webhooks you create, read, or manage are scoped to your developer apps (resolved from the API key). A webhook owned by another user is invisible to you - reads return 404.
Response shape
These endpoints return bare resource objects (no success/data/errors envelope). Errors use the raw framework shape:
{ "detail": "Webhook not found" }
Treat any non-2xx status as a failure and read detail for the reason.
3. Endpoint reference
3.1 POST /v1/webhooks/ - Create a webhook
Registers a callback URL for a developer app. The authenticated user must own the app referenced by app_id. A signing secret is generated automatically at creation; retrieve it separately via the secret endpoint.
Body:
| Field | Type | Required | Description |
|---|
app_id | UUID | yes | ID of the developer app that will receive events. Must be an app you own. |
service_type | string | yes | Channel. One of sms, voice, otp, whatsapp, email (regex ^(sms|voice|otp|whatsapp|email)$). |
url | string (HTTPS URL) | yes | Public HTTPS URL we POST event payloads to. Must be reachable and return 2xx on success. |
Success - 201 Created:
{
"webhook_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"service_type": "whatsapp",
"url": "https://api.yourdomain.com/briq/webhooks/whatsapp",
"secret_token": "***",
"created_at": "2026-03-15T12:00:00.000000",
"updated_at": "2026-03-15T12:00:00.000000"
}
The returned secret_token is always masked as ***. Fetch the real value with the secret endpoint.
| HTTP | Cause |
|---|
| 400 | App not found, not owned by you, or a webhook for this app + service_type already exists. |
| 422 | Invalid body (bad service_type, non-HTTPS/malformed url, non-UUID app_id). |
curl -X POST "https://karibu.briq.tz/v1/webhooks/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"service_type": "whatsapp",
"url": "https://api.yourdomain.com/briq/webhooks/whatsapp"
}'
3.2 GET /v1/webhooks/all - List all webhooks for the user
Returns every webhook belonging to the authenticated user, across all developer apps and channels. Returns an empty array [] if you have none (not an error).
Success - 200 OK: an array of webhook objects (same shape as the create response).
curl "https://karibu.briq.tz/v1/webhooks/all" \
-H "X-API-Key: YOUR_API_KEY"
3.3 GET /v1/webhooks/app/{app_id} - List webhooks for an app
Lists the webhooks registered for a single developer app you own. If the app is not yours or has no webhooks, an empty array [] is returned.
Path parameter: app_id (string, required).
curl "https://karibu.briq.tz/v1/webhooks/app/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: YOUR_API_KEY"
3.4 GET /v1/webhooks/{webhook_id} - Get a webhook
Fetches a single webhook by ID. Must belong to one of your apps, otherwise 404.
Path parameter: webhook_id (string, required).
Success - 200 OK: a single webhook object.
| HTTP | Cause |
|---|
| 404 | Webhook not found or not owned by one of your apps ({"detail": "Webhook not found"}). |
curl "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-API-Key: YOUR_API_KEY"
3.5 PATCH /v1/webhooks/{webhook_id} - Update a webhook
Updates a webhook’s url and/or service_type. Both fields are optional; send only what you want to change.
Body:
| Field | Type | Required | Description |
|---|
service_type | string | no | New channel (same enum as create). |
url | string (HTTPS URL) | no | New public HTTPS callback URL. |
The signing secret is fixed at creation and is not affected by an update. Existing receivers keep verifying X-Briq-Signature with the same secret.
| HTTP | Cause |
|---|
| 404 | Webhook not found, not owned by one of your apps, or the update failed. |
| 422 | Invalid body (bad service_type or malformed/non-HTTPS url). |
curl -X PATCH "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://api.yourdomain.com/briq/webhooks/whatsapp-v2" }'
3.6 DELETE /v1/webhooks/{webhook_id} - Delete a webhook
Permanently removes a webhook. After deletion, Briq stops sending events to its URL, and the per-service_type uniqueness slot is freed (you can create a new one for the same app + channel).
Success - 204 No Content (no body).
| HTTP | Cause |
|---|
| 404 | Webhook not found or not owned by one of your apps. |
curl -X DELETE "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-API-Key: YOUR_API_KEY"
3.7 GET /v1/webhooks/{webhook_id}/secret - Reveal signing secret
Returns the webhook’s signing secret in plaintext. Use it to verify the X-Briq-Signature header (HMAC-SHA256 of the raw request body) on incoming deliveries.
Success - 200 OK:
{ "secret_token": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
| HTTP | Cause |
|---|
| 404 | Webhook not found / not owned ({"detail": "Webhook not found"}) or webhook has no secret set ({"detail": "Webhook has no secret"}). |
Treat the secret as a credential. Store it in a secret manager or environment variable; never expose it client-side. The full HMAC verification procedure (header format, raw-body handling, sample code) is documented in the WhatsApp reference -> Verifying the signature.
curl "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890/secret" \
-H "X-API-Key: YOUR_API_KEY"
3.8 POST /v1/webhooks/{webhook_id}/test - Send a test event
Enqueues a synthetic test delivery so you can confirm your endpoint is reachable and your signature verification works. Returns an event_id you can use to find the delivery.
Success - 202 Accepted:
{
"event_id": "test_9f8e7d6c5b4a3210",
"message": "Test event enqueued. Poll GET /{webhook_id}/deliveries to check status."
}
Synthetic sms.sent payload quirk. The test endpoint currently emits a synthetic sms.sent event regardless of the webhook’s service_type. For a whatsapp webhook this still verifies connectivity and signature verification, but the body is not a faithful WhatsApp event payload. A native whatsapp.* test event is upcoming.
curl -X POST "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890/test" \
-H "X-API-Key: YOUR_API_KEY"
3.9 GET /v1/webhooks/{webhook_id}/deliveries - List delivery attempts
Returns a paginated, filterable list of delivery attempts for a webhook so you can audit what was sent, the HTTP status received, and any errors.
Query parameters:
| Field | Type | Required | Description |
|---|
status | string | no | pending, delivered, failed, or exhausted. |
event_name | string | no | Filter by event name (e.g. briq.message.delivered). |
from_created_at | datetime (ISO 8601) | no | Created on or after this timestamp. |
to_created_at | datetime (ISO 8601) | no | Created on or before this timestamp. |
message_id | string | no | Filter by message ID. |
limit | int | no | Page size, 1-100. Default 50. |
offset | int | no | Items to skip, >= 0. Default 0. |
Success - 200 OK:
{
"items": [
{
"id": "d1e2f3a4-b5c6-7890-abcd-ef0123456789",
"event_id": "evt_0a1b2c3d4e5f",
"webhook_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"service_type": "whatsapp",
"event_name": "briq.message.delivered",
"status": "failed",
"attempt_count": 3,
"max_attempts": 5,
"last_status_code": 500,
"last_error": "Internal Server Error",
"next_attempt_at": "2026-03-15T12:10:00.000000",
"created_at": "2026-03-15T12:00:00.000000",
"updated_at": "2026-03-15T12:05:00.000000"
}
],
"total": 1,
"limit": 20,
"offset": 0
}
Delivery summary fields
| Field | Type | Description |
|---|
id | string | Unique delivery id. Use it with the get-one-delivery endpoint. |
event_id | string | Event id from the envelope (idempotency). |
webhook_id | string | Target webhook config id. |
app_id | string | null | Developer app id. |
service_type | string | Channel: sms, email, voice, otp, whatsapp. |
event_name | string | Event name. |
status | string | pending | delivered | failed | exhausted. |
attempt_count | int | Number of delivery attempts made. |
max_attempts | int | Maximum attempts configured. |
last_status_code | int | null | HTTP status from the last attempt. |
last_error | string | null | Last error message if failed. |
next_attempt_at | datetime | null | When the next attempt is due. |
created_at / updated_at | datetime | Timestamps. |
List items omit the url and payload fields. Use get-one-delivery for the full payload snapshot.
curl "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890/deliveries?status=failed&limit=20" \
-H "X-API-Key: YOUR_API_KEY"
3.10 GET /v1/webhooks/{webhook_id}/stats - Delivery stats
Returns aggregated delivery outcome counts over a time window, broken down by status and event name. Useful for monitoring health and spotting failure spikes.
Query parameter: since (datetime, ISO 8601, optional). Defaults to 7 days ago.
Success - 200 OK:
{
"webhook_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"since": "2026-03-01T00:00:00.000000",
"total": 124,
"by_status": { "delivered": 118, "failed": 4, "exhausted": 1, "pending": 1 },
"by_event": { "briq.message.delivered": 100, "briq.message.failed": 24 }
}
curl "https://karibu.briq.tz/v1/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890/stats?since=2026-03-01T00:00:00Z" \
-H "X-API-Key: YOUR_API_KEY"
3.11 GET /v1/webhooks/deliveries/{delivery_id} - Get one delivery
Returns the full detail for a single delivery, including the target url and the payload snapshot of the JSON body that was sent (or is queued to send).
Path parameter: delivery_id (string, required) - the id from a delivery list item.
Success - 200 OK: every delivery-summary field plus:
| Field | Type | Description |
|---|
url | string | Callback URL this delivery targets. |
payload | object | null | Snapshot of the JSON body sent or to be sent. |
| HTTP | Cause |
|---|
| 404 | Delivery not found or not owned by one of your apps. |
curl "https://karibu.briq.tz/v1/webhooks/deliveries/d1e2f3a4-b5c6-7890-abcd-ef0123456789" \
-H "X-API-Key: YOUR_API_KEY"
3.12 POST /v1/webhooks/deliveries/{delivery_id}/retry - Retry a delivery
Schedules a previously failed delivery for another attempt. Only deliveries with status failed or exhausted can be retried.
Success - 200 OK: the updated delivery detail (typically status: "pending" with next_attempt_at set).
| HTTP | Cause |
|---|
| 404 | Delivery not found or not owned by one of your apps. |
| 422 | Delivery is not in a retryable state (status is not failed or exhausted). |
Retry requeues the same delivery row - it does not create a duplicate. The same id is updated and re-attempted.
curl -X POST "https://karibu.briq.tz/v1/webhooks/deliveries/d1e2f3a4-b5c6-7890-abcd-ef0123456789/retry" \
-H "X-API-Key: YOUR_API_KEY"
4. What your endpoint must return
| Your HTTP response | Briq behavior |
|---|
| Any 2xx | Treated as success; Briq stops retrying this attempt. |
| Non-2xx, timeout, or connection failure | Treated as failure; retried with backoff up to max_attempts. |
The response body is not interpreted for success - 204 No Content or 200 OK with an empty body is sufficient. Respond quickly (acknowledge, then process asynchronously) so your endpoint isn’t marked as failing under load.
- Karibu WhatsApp API - WhatsApp send/read endpoints and the
whatsapp.sent/delivered/read/failed event payloads delivered to these webhooks.
- Webhooks (subscriber guide) - what your HTTPS endpoint receives, signature verification, idempotency, and retry behavior.
- Developer Apps - API keys and app configuration.