---
title: "Create campaign"
method: POST
path: "/api/v1/campaigns"
tags: ["campaigns"]
---

# Create campaign

`POST /api/v1/campaigns`

## Request

- Base URL: `https://app.blueticked.com`
- URL: `https://app.blueticked.com/api/v1/campaigns`
- Auth: HTTP bearer

Create, schedule, validate, or queue a bulk WhatsApp campaign.

A campaign dispatches real sends, so (on top of `campaigns:write`) the key must be authorised to send on the campaign's channel: the umbrella `messages:send`, or the channel's least-privilege send scope (`whatsapp:send` / `sms:send` / `email:send`).

Set test_mode: true to validate audience counts without queueing.

Pass business_id when creating campaigns for one managed business.

WhatsApp templates are attached to a specific WhatsApp number; pass channel_id to choose the sending number explicitly.

Email campaigns require `subject` (supports {{n}} variables) and may pass `document_source` to attach a per-recipient PDF.

A WhatsApp statement run uses a template with a DOCUMENT header and `document_source`: `mode: "url_field"` with `field_key` (a contact custom field holding the https URL for each recipient), `mode: "url"` for one file to everyone, or `mode: "library"` for files uploaded in the dashboard (matched to contacts by phone or a custom field in the filename, kept 90 days). `filename_template` (for example "Statement {{first_name}}.pdf") is required for a DOCUMENT header.

`missing_policy` decides a recipient with no document: "skip" sends to everyone else and marks that recipient failed with document_missing; "block" refuses a campaign sent now with 400 validation_failed and details.missing_count, and nothing is created.

A scheduled campaign is checked when it fires, not when you create it: the call answers 202 with status "scheduled". If a recipient then has no document under "block", the campaign is closed unsent and a campaign_blocked alert in the workspace names the missing count.

Email campaigns may pass `block_content`, a block-editor document (`{ version: 1, blocks: [...] }` with heading/text/button/image/divider/spacer/columns/hero/social/video/html blocks), instead of `body`; it compiles to branded HTML plus a plain-text part per recipient at send time. Pass either `body` or `block_content`, not both.

An email `template_id` that references a block-designed template carries its design automatically; an inline `block_content` overrides it.

Audience accepts `{ type: "all" }`, `{ type: "list", list_id }` or `{ type: "segment", segment_id }`. Pass a segment id to target a smart audience evaluated at send time.

To schedule, set `mode: "schedule"` and `scheduled_at` (ISO 8601, at most 90 days ahead); the response `status` is then `scheduled`. Sends less than 30s out collapse back to immediate.

Optional fields: `description` (internal label), `preheader` (email preview text, supports {{n}}), `unique_entries` (default true; dedupes recipients that match twice) and `engagement_limit` (cap the number of recipients).

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `name` string, required
  - `description` string, nullable
  - `business_id` string, uuid, nullable
  - `channel_id` string, uuid, nullable
  - `channel` 'whatsapp' | 'sms' | 'email', required
  - `audience` union, required
    - object
      - `type` 'all', required
    - object
      - `type` 'list', required
      - `list_id` string, uuid
      - `listId` string, uuid
    - object
      - `type` 'segment', required
      - `segment_id` string, uuid
      - `segmentId` string, uuid
    - object
      - `type` 'table', required
      - `table_id` string, uuid
      - `tableId` string, uuid
      - `status` string
  - `body` string
  - `subject` string, nullable
  - `preheader` string, nullable
  - `template_id` string, uuid, nullable
  - `block_content` unknown
  - `template_variables` object
  - `document_source` unknown
  - `mode` 'now' | 'schedule'
  - `scheduled_at` string, date-time, nullable
  - `test_mode` boolean
  - `unique_entries` boolean
  - `engagement_limit` integer, nullable

## Response `202`

Success

- object
  - `campaign_id` string, uuid, required
  - `status` string, required
  - `message_count` number, required
  - `queued` boolean, required
  - `request_id` string, required

## Other responses

- `400`: Validation failed
- `401`: Unauthorized: missing or invalid API key
- `402`: Insufficient wallet balance
- `403`: Forbidden: scope, plan limit, or suspension
- `404`: Not found
- `409`: Conflict (idempotency-key reuse or resource in use)
- `413`: Request body above the endpoint's size limit
- `422`: Understood but refused: the request is well-formed, the action is not permitted for this resource
- `429`: Rate limited
- `500`: Internal error
- `502`: An upstream provider refused or failed the request
- `503`: Channel or send queue unavailable

---

[API](https://skmtc.dev/blueticked/apis/blueticked-api.md) · [All operations](https://skmtc.dev/blueticked/apis/blueticked-api/llms.txt) · [OpenAPI document](https://skmtc.dev/blueticked/apis/blueticked-api/revisions/07132284f4ff?raw)
