Create a campaign
Creates a campaign in draft status, bound to an agent, a channel and a weekly calling window.
Nothing is sent or dialed until you add contacts and call
PATCH /api/campaigns/{campaignId}/activate. A WhatsApp template or email content can be
included now, so the campaign is ready to send in one request.
These checks run before the campaign is saved, in this order:
- the agent exists in this workspace (404
AGENT_NOT_FOUND); - the agent serves the campaign’s
channel(400); - for
channel: email, the workspace has its own sending mailbox connected and selected as sender (409); - template placeholder maps and
{{token}}s in the email subject and body resolve (400); - the WhatsApp variable map only uses placeholders the template body has (400).
maxConcurrentCallsis silently lowered to the plan’s ceiling (Starter 3, Growth 10, Business 25), and the stored value is what you get back. The WhatsApp template’s approval status is not checked here; activation checks it.
Side effects. Writes the campaign row and an audit entry. No provider is called and no contact is reached.
Idempotency. Not idempotent: retrying after a timeout creates a second draft. List
campaigns before retrying, or delete the duplicate with DELETE /api/campaigns/{campaignId}.
Webhook events. audit.log_recorded for webhooks subscribed to it. See Webhooks.
Access
- Required scope:
full. Admin-only route:read/writekeys get 403; signed-in users need the admin or owner role. - Rate limit: Configuration mutations — 10 requests/min per workspace, shared with agent mutations, on top of the general API limit (120 to 600 requests/min by plan). See Rate limits.
- Plan: Counts against the plan’s active-campaign cap (Starter 1, Growth 3, Business and Enterprise unlimited). The draft does not use a slot and can be created while every slot is taken; the cap is enforced when it is activated. Creation is refused with 403
BILLING_ERRORonly when the workspace has no active plan.
Authentication
Workspace API key: jl_ followed by 64 lowercase hex characters, created by the workspace owner in the
dashboard (Settings → API Keys) and sent as Authorization: Bearer jl_.... The plaintext is shown once,
at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys.
Operations restricted to admins or owners reject keys without the full scope with 403, and say so in
their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret —
that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds.
See Authentication.
Request
Agent of this workspace. It must serve the campaign’s channel (400 otherwise); an unknown agent answers 404.
Weekly sending window, stored and returned exactly as sent (camelCase inside the object).
A call, WhatsApp template or email starts only when the local hour in timezone is
>= startHour and < endHour on an enabled day; outside it, the call or send waits for the
next window and the contact stays pending. A schedule with no upcoming window marks the
contact failed instead. A call that started inside the window may run past endHour. Days
that are left out count as disabled.
Validation: timezone must be a valid IANA zone (Invalid IANA timezone), every enabled day
needs startHour < endHour, and at least one day must be enabled
(At least one day must be enabled). The window applies to voice, WhatsApp and email campaigns;
inbound-only campaigns send nothing, so it does not limit when the agent answers.
Maximum simultaneous calls. Silently lowered to the plan’s ceiling (Starter 3, Growth 10, Business 25) and to the platform maximum.
Maximum dial attempts per contact, counting the first; unanswered, busy or unconnected calls
are redialed until this many exist. 0 or 1 disables redialing. Voice only. A plan gate
(403 BILLING_ERROR) exists for values above 0, but every plan includes retries today.
voice, whatsapp, webchat or email (see Campaign.channel). An email campaign needs
the workspace’s own mailbox connected in Integrations and selected as sender (409 otherwise).
Purpose of the campaign, used to classify outcomes (see Campaign.category for each value).
WhatsApp template (from the workspace’s templates) that makes activation send outbound messages. WhatsApp approval is checked at activation, not here.
Campaign-wide placeholder values, the same for every contact. Either an array of up to 20 strings ({{1}} is index 0) or an object keyed by index (keys up to 8 characters); values up to 500 characters.
Placeholders filled per contact, keyed by placeholder index (up to 3 characters), for example
{"1": "contact.first_name"}. A value is the token alone, meaning skip a contact that cannot
resolve it, or { token, fallback } to write the fallback instead. Skipped contacts end as
invalid. Indexes must exist in the template body (400 otherwise).
Subject for outbound email, may contain tokens. Needs emailBody too; activation refuses one without the other.
Plain-text body for outbound email, may contain tokens.
Response
The campaign was created in draft status.
A campaign row as returned by the retrieve, create, update, activate and pause endpoints.
Keys are snake_case, exactly as stored. The list endpoint returns a lighter
CampaignListItem instead.
Removed from responses (2026-09-15). retry_policy, voicemail_action and voicemail_message
were legacy columns nothing read; none of them was ever settable through this API and none is
returned any more. Redials come from max_retry_attempts and retry_interval_minutes; voicemail
detection is an agent setting (enableVoicemailDetection).

