Validate, launch, pause, resume, cancel, and retry campaigns — through the Briq dashboard or the developer API.
Once your campaign has audiences, content, and at least one run, you can validate it, launch it, and control its in-flight state. The dashboard exposes all of this through the campaign view’s action buttons; the developer API exposes the same operations as a small set of POST endpoints.This page covers:
Validation (pre-flight check)
Launch (go live)
Runtime controls — pause, resume, cancel
Retry (rerun a failed or cancelled run on the still-pending recipients)
Dashboard: sign in at https://briq.tz/login, open the campaign, and click Validate in the action bar. The UI shows green for a clean validation, or a list of issues to fix. The Launch button runs the same checks automatically, so most teams only invoke Validate explicitly while iterating on content or audience filters.Developer API:POST /v1/campaign/{campaign_id}/validateThe endpoint is read-only — it does not mutate campaign state, so it is safe to call repeatedly (for example, from a “Looks good?” preview screen in your own admin tool).
Validation failures do NOT return an HTTP error. This endpoint always returns 200 OK. A failed validation is signalled by data.valid: false and a populated data.issues[] array. Branch on body.data.valid, never on the HTTP status.
Same envelope, with data.valid: false and human-readable strings in data.issues[]:
{ "success": true, "data": { "valid": false, "issues": [ "Audience is empty", "Run 'run_789' has no scheduled_at" ], "estimated_cost": {} }, "errors": null, "request_id": "req_01HXXXXXXXXXXXXXXXXXXXXXXX"}
estimated_cost is in service units, not currency. The map is keyed by channel and reports SMS parts, voice minutes, or push notifications — never a money amount. Do not render these numbers with a currency symbol. To show a monetary estimate, multiply by your account’s per-unit rates client-side.
Dashboard: on the campaign view at https://briq.tz/login, click Launch. The dashboard auto-validates the campaign, marks it ready, and triggers the earliest pending run. If validation fails, you see the same issue list as the Validate panel — fix the issues and click Launch again.Developer API:POST /v1/campaign/{campaign_id}/launchLaunch is a composite operation: it validates the campaign, marks it ready, and triggers a run in one call.
After launch returns, the worker’s pickup cron claims the run on its next tick — typically within seconds — and begins dispatching in batches of 1000 recipients.
Recurring template runs. For a recurring template run (one where recurrence_index is null), launch materialises the child occurrences and retires the template. From that point on, each occurrence has its own run_id and lifecycle.
No ready run is available: "No 'ready' run available for this campaign".
401
UNAUTHORIZED
Missing or invalid API key.
403
FORBIDDEN
API key does not own this campaign.
404
NOT_FOUND
campaign_id does not exist, or run_id does not belong to it.
409
CONFLICT
Validation failed at launch time. See special envelope below.
409
CONFLICT
The targeted run is already in running, completed, failed, or cancelled and cannot be re-triggered.
500
INTERNAL_ERROR
Unhandled server error.
Validation-failed 409 uses a special dual envelope. Both data and errors are populated — the validation result lives in data.issues[], and errors[] is just the protocol-level marker.
Dashboard: on the running campaign view at https://briq.tz/login, use the Pause and Resume buttons. Pause halts in-flight runs after the current batch; Resume flips them back to scheduled and reschedules them for immediate pickup.
POST /v1/campaign/{campaign_id}/pauseStops in-flight runs mid-flight. Internally, the server sets a Redis flag and flips active runs — those in running or the internal claimed state — to paused. The endpoint is idempotent: calling pause on an already-paused campaign returns 200 OK.Runs that were scheduled or ready at pause time are not touched — they remain dormant on their own schedule and will pick up normally unless you also cancel.
Pause is not instantaneous. The worker finishes the current 1000-recipient batch before halting. After the pause call returns, you may still see a few hundred additional sent_count reach recipients. Do not rely on pause as a “stop sending now” guarantee — for that, use cancel.
POST /v1/campaign/{campaign_id}/resumeClears the pause flag and flips paused runs back to scheduled. The endpoint is idempotent: calling resume on a campaign that was never paused is a no-op (the Redis pause key is deleted whether it existed or not).
Resume is “go-now” — the original scheduled_at is NOT preserved. Resume rewrites the run’s scheduled_at to the current time so the worker picks it up on the next tick.The rationale: a run paused at noon yesterday with a scheduled_at of noon yesterday would otherwise sit idle until noon tomorrow, because the worker only claims runs whose scheduled_at is in the past but within the pickup window. Go-now is the only safe resume behaviour.If you need to honour the original schedule, save it client-side before pausing and re-PATCH it after resume.
Dashboard: on the campaign view at https://briq.tz/login, click Cancel campaign. A confirmation dialog warns that cancellation is permanent before the action commits.Developer API:POST /v1/campaign/{campaign_id}/cancel
Cancel is sticky — there is no way back. Once a campaign is cancelled, none of pause, resume, launch, retry, or PATCH will revive it. To send the remaining recipients you must either retry the individual cancelled runs (see the next section) or create a new campaign.
Sets the Redis cancel flag so the worker stops claiming new batches.
Flips every non-terminal run (ready, scheduled, claimed, running, paused) to cancelled.
Marks the parent campaign cancelled.
Refunds unsent reservations synchronously. Failures here are logged and retried by an out-of-band reconciler cron — the campaign stays cancelled either way.
Messages already dispatched before cancel cannot be unsent. Only the unsent reservation portion is refunded.
Dashboard: at https://briq.tz/login, open the run’s detail view (any run in failed or cancelled state) and click Retry run. The dashboard skips recipients whose messages already reached SENT or DELIVERED and reruns the rest.Developer API:POST /v1/campaign/{campaign_id}/runs/{run_id}/retryRetry creates a new run row with a new id, the same content, and a filtered recipient list. The new run is created in scheduled state with scheduled_at = now(), so the worker’s next pickup tick claims it.
The returned run_id is new — not the original. Keep both for audit. The new run’s snapshot includes a retry_of_run_id field pointing back at the source run.
The retry recipient list is built by joining campaign_recipients.provider_message_id to messages.message_id. Any recipient whose latest message status is SENT or DELIVERED is excluded from the retry. Everything else — PENDING, FAILED, never-dispatched — is included.