Skip to navigation

Create a campaign

View as Markdown

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). maxConcurrentCalls is 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/write keys 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_ERROR only when the workspace has no active plan.

Authentication

AuthorizationBearer

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.

ScopeGET / HEADPOST / PUT / PATCH / DELETEAdmin-only routes
readYesNoNo
writeYesYesNo
fullYesYesYes

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

This endpoint expects an object.
agentIdstringRequiredformat: "uuid"

Agent of this workspace. It must serve the campaign’s channel (400 otherwise); an unknown agent answers 404.

namestringRequired1-200 characters
Display name.
productContextstringRequired10-5000 characters
What the campaign is about, given to the agent. At least 10 characters after trimming.
targetAudiencestringRequired1-1000 characters
Who the contacts are, given to the agent.
scheduleobjectRequired

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.

maxConcurrentCallsintegerOptional1-500Defaults to 10

Maximum simultaneous calls. Silently lowered to the plan’s ceiling (Starter 3, Growth 10, Business 25) and to the platform maximum.

maxRetryAttemptsintegerOptional0-10Defaults to 3

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.

retryIntervalMinutesintegerOptional5-1440Defaults to 60
Minutes between a missed call and its redial.
channelenumOptionalDefaults to voice

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).

Allowed values:
categoryenumOptionalDefaults to sales

Purpose of the campaign, used to classify outcomes (see Campaign.category for each value).

whatsappTemplateIdstringOptionalformat: "uuid"

WhatsApp template (from the workspace’s templates) that makes activation send outbound messages. WhatsApp approval is checked at activation, not here.

whatsappTemplateVariableslist of strings or map from strings to stringsOptional

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.

whatsappTemplateVariableMapmap from strings to strings or objectsOptional

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).

emailSubjectstringOptional1-300 characters

Subject for outbound email, may contain tokens. Needs emailBody too; activation refuses one without the other.

emailBodystringOptional1-20000 characters

Plain-text body for outbound email, may contain tokens.

Response

The campaign was created in draft status.

dataobject

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).

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
404
Not Found Error
409
Conflict Error
429
Too Many Requests Error