Skip to main content
Campaigns are how Briq organizes bulk messaging into reusable, schedulable units — each one bundles an audience, content, and one or more runs that decide when the message actually goes out. The primary surface for managing campaigns is the Briq dashboard; the API documented here exists for integrators who need to automate or embed the same workflow into their own systems.

What a campaign is made of

A campaign is a parent record with three logical children. None of them are useful in isolation — the campaign only sends when all three are present and validated.
  • Audiences — one or more contact groups attached to the campaign. These are the recipients. A campaign with no audiences cannot be launched.
  • Content — the message body or template for the campaign, one row per channel. SMS, voice, and WhatsApp each have their own content row. You cannot attach two content rows for the same channel to the same campaign.
  • Runs — the scheduled executions of the campaign. A run can be single-shot (fire once at a specific time) or recurring (a cron-style schedule). A campaign with no run will never send anything, no matter how complete its audience and content are.

Dashboard vs API — when to use which

The dashboard is the default surface for campaigns. Reach for the API only when you genuinely need automation — most teams ship every campaign they will ever run from the dashboard alone.
SurfaceUse it when
Dashboard (briq.tz/login)Day-to-day campaigns, marketing sends, one-off announcements, manual scheduling, reviewing analytics, and pausing or cancelling live runs.
API (https://karibu.briq.tz)CI/CD-driven sends, programmatic recurring drops, CRM-triggered campaigns, server-driven retry or cancel orchestration, and embedding campaign management inside your own product.
If you are not sure which one you need, use the dashboard. Everything described on the API subpages is available there with no code.

Lifecycle at a glance

Every campaign moves through a fixed set of states. The dashboard surfaces them in the campaign header; the API returns them on GET /v1/campaign/{id}/status.
draft → configured → ready → scheduled → running → completed
                                                 → failed
                                                 → cancelled
                                                 → paused (reversible)
StatusMeaning
draftCampaign record exists but has no audience or content yet. Not launchable.
configuredAudience and content are attached. Has not been validated yet.
readyValidation passed. Eligible to be launched.
scheduledLaunched with a future run time; waiting for the scheduler to pick it up.
runningThe engine has claimed the run and is actively dispatching messages.
pausedA running campaign was paused. Reversible — resume returns it to running.
completedAll scheduled work finished. Terminal.
failedThe run ended in an error state. Terminal.
cancelledOperator-cancelled. Terminal and sticky — see below.
Two rules are worth memorizing:
  1. Editing a ready or scheduled campaign drops it back to configured. Any change to audiences, content, or runs invalidates the pre-flight check. You must call /validate again (dashboard does this automatically when you re-open the launch panel) before you can launch.
  2. cancelled is sticky. There is no un-cancel. Cancelling refunds unsent message reservations and closes the campaign permanently. If you need to send again, clone the campaign.

Run status

Each individual run inside a campaign has its own status, separate from the campaign-level status. This is what powers per-run analytics and retry decisions.
Run statusMeaning
pendingRun is created and waiting for its scheduled time.
runningEngine has claimed the run and is dispatching messages.
completedRun finished and all messages were dispatched.
failedRun terminated in error before completing.
cancelledRun was cancelled before or during execution.
Internally the engine uses a claimed state when a worker picks up a run. The API never exposes this — claimed is always translated to running in responses. Treat running as the only “in-flight” state you need to handle.

The dashboard walkthrough (high level)

If you are using the dashboard — which is the recommended path — the flow is five steps:
  1. Open your workspace at briq.tz/login and switch to the workspace that owns the campaign.
  2. Click “New Campaign” and give it a name and description.
  3. Add audiences by selecting one or more existing contact groups.
  4. Add content for each channel you intend to use (SMS, voice, WhatsApp). The dashboard enforces the one-row-per-channel rule.
  5. Schedule a run and click Launch. The dashboard runs validation behind the Launch button — if anything is missing or inconsistent it tells you exactly which field to fix — and then moves the campaign through the same lifecycle states described above.
You never need to touch the API for any of this.

The API walkthrough (high level)

If you do need to automate, the seven calls below are the canonical sequence. Each subpage walks through the payloads, error cases, and idempotency rules in detail.
1. POST /v1/campaign                              — create
2. POST /v1/campaign/{id}/audiences               — attach contact groups
3. POST /v1/campaign/{id}/content                 — attach message/template
4. POST /v1/campaign/{id}/runs                    — schedule a run
5. POST /v1/campaign/{id}/validate                — pre-flight check
6. POST /v1/campaign/{id}/launch                  — go live
7. GET  /v1/campaign/{id}/status                  — poll for progress
The three campaign subpages cover these in order:
  • Building a campaign — creating the campaign record and attaching audiences, content, and runs.
  • Launch control — validating, launching, pausing, resuming, cancelling, and retrying.
  • Observability — status polling, analytics, and run-level detail.

Authentication snapshot

Every campaign API call is authenticated the same way:
  • X-API-Key (required) — your developer API key. The key must be in ACTIVE state; revoked or expired keys return 401 UNAUTHORIZED.
  • X-App-ID (optional but recommended) — the UUID of the developer app to attribute the call to. Send this when your API key is linked to multiple developer apps so Briq can disambiguate which one is calling.
When the API key is workspace-scoped (through its linked developer app), every campaign call is sandboxed to that workspace — you cannot list, read, or modify campaigns in any other workspace using that key. Attempting to do so returns 403 FORBIDDEN. The developer host is https://karibu.briq.tz. See Developer Apps for how keys and app IDs are issued, and Workspaces for how scoping works.

Response envelope

Every campaign endpoint returns the same JSON envelope:
{
  "success": true,
  "data": { },
  "errors": null,
  "request_id": "<uuid>"
}
Three rules to internalize:
  • success mirrors HTTP status. true on 2xx, false on 4xx and 5xx. Branch on success rather than re-parsing the status code.
  • On error, data is null and errors is an array of { code, message, field } objects. field is populated for validation errors so you can map the failure back to the specific input.
  • Always log request_id. It is how Briq support correlates your call to internal traces. Include it in any support ticket.

Error codes at a glance

CodeHTTPMeaning
VALIDATION_FAILED400 / 422Body, query, or current campaign state failed validation.
UNAUTHORIZED401API key missing, invalid, expired, or revoked.
FORBIDDEN403Authenticated but not allowed — workspace ownership or app scope mismatch.
NOT_FOUND404Resource does not exist or is soft-deleted.
CONFLICT409State precondition not met — duplicate content for a channel, missing validation on launch, or a run already in flight.
INTERNAL_ERROR500Unexpected server error. Retry with backoff and report request_id if it persists.
DEPRECATED410The endpoint has been removed. Migrate to the replacement listed in the response message.

Best practices

  • Use the dashboard for one-off sends. The API is for automation — every dashboard action has an API equivalent, but not every API workflow is worth the engineering cost when a human will only do it once.
  • Always validate before launching. The dashboard does this automatically; via the API, call /validate before /launch so failures surface as actionable field errors instead of a launch-time CONFLICT.
  • Treat cancelled as permanent. It refunds unsent message reservations and cannot be undone. Clone the campaign if you need to send again.
  • Log every request_id. Support cannot trace a call without it. Persist it alongside whichever business object you correlate to the campaign.
  • Poll /status no faster than every 5–15 seconds, and back off entirely once the campaign reaches a terminal state (completed, failed, cancelled). For real-time progress, prefer Webhooks over polling.