Skip to content

Campaigns

A campaign is one AI agent, one WhatsApp number and one audience. The API gives you the directory (ids, status, connection state), the pause and resume switch, and the door for opt-in leads.

Method Path Scope
GET /campaigns campaigns:read
POST /campaigns/{id}/pause campaigns:write
POST /campaigns/{id}/resume campaigns:write
POST /campaigns/{id}/leads messages:send
Terminal window
curl "https://app.whatsetter.com/api/v1/campaigns" \
-H "Authorization: Bearer ws_live_…"
{
"data": [
{
"id": "66f1a2b3c4d5e6f7a8b9c0c1",
"campaign_id": "acme-france-1-ab12",
"name": "Alex",
"status": "active",
"purpose": "setter",
"whatsapp_connected": true,
"created_at": "2026-08-01T09:00:00.000Z"
}
]
}
Field Meaning
id The campaign document id. Accepted in every /campaigns/{id}/... path.
campaign_id The slug that leads, conversations and bookings carry in their own campaign_id. Also accepted in paths and filters.
name The agent’s display name.
status active, draft, paused, archived, or unknown for an internal value.
purpose setter (1-to-1 conversations) or group (WhatsApp groups).
whatsapp_connected true when the campaign’s number can send right now.

The list holds up to 100 campaigns, newest first. There is no cursor.

Pausing stops AI replies and sending, the same as the dashboard toggle. Resuming reactivates them.

Terminal window
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/pause" \
-H "Authorization: Bearer ws_live_…"

The response is the campaign object with its new status. Only two transitions exist:

Call Allowed from Result Otherwise
POST /campaigns/{id}/pause active paused 409 invalid_state
POST /campaigns/{id}/resume paused active 409 invalid_state

A draft campaign must be activated from the dashboard. An archived campaign cannot be resumed.

Resuming is subject to your plan’s active-campaign limit: Free and Starter 1, Business 3, Scale 10, plus any extra agents added to your plan. When the limit is full, resume answers 402 plan_limit_reached: pause another campaign or upgrade.

When someone signs up on your funnel or CRM, push them to the campaign. WhatSetter runs the same pipeline as the campaign’s sales-page webhook: phone validation and WhatsApp check, deduplication against contacts already contacted, daily first-contact quota, then an AI-written first message from the campaign’s template, the lead’s name and every key of additional_data.

Terminal window
curl -X POST "https://app.whatsetter.com/api/v1/campaigns/acme-france-1-ab12/leads" \
-H "Authorization: Bearer ws_live_…" \
-H "Content-Type: application/json" \
-d '{
"phone": "+33612345678",
"name": "Julien",
"email": "julien@example.com",
"source_url": "crm:hubspot",
"external_reference": "4471",
"additional_data": { "offer": "Pack Pro", "city": "Lyon", "budget": "500-1000" }
}'
{
"data": {
"status": "accepted",
"campaign_id": "acme-france-1-ab12",
"phone": "+33612345678",
"external_reference": "4471",
"note": "Queued into the first-contact pipeline: deduplication, daily first-contact quota and anti-ban pacing apply. The lead is created later, so no lead id exists yet…"
}
}
Field Rules
phone Required. International format, 6 to 15 digits. Echoed back with a +.
name, email Optional, cut at 255 characters.
source_url Optional, up to 255 characters. Where the lead came from. Defaults to api.
external_reference Optional, up to 255 characters. Your own record id, stored verbatim and echoed on every lead and webhook.
additional_data Optional object, up to 30 keys and 2000 characters once serialized. Used to personalize the first message, never stored, never returned. Keys named like the fields above (phone, name, email, source_url, external_reference) are ignored.

The endpoint answers 202 as soon as the lead is accepted. The lead row is created later, after deduplication and pacing, so there is no lead id yet. To follow up:

  • look the lead up with GET /leads?external_reference=4471 (or ?phone=+33612345678);
  • or subscribe to webhooks: contact.external_reference carries your id.

A contact already contacted by the campaign is deduplicated silently: no second first message, and the 202 looks the same. Over-quota leads are queued for the next window, never dropped.

Two budgets protect the number, and the API cannot bypass either:

  • Daily first contacts per campaign: opt-in leads beyond it wait for the next day.
  • Daily messages per WhatsApp number: shared with POST /messages, see Messages for the X-Quota-* headers.

On top of that, requests are limited per workspace per minute by plan (429 rate_limited with Retry-After).

HTTP code When
401 missing_api_key, invalid_api_key Key absent, unknown or revoked.
402 plan_limit_reached Resume refused: the plan’s active-campaign limit is full.
403 insufficient_scope The key lacks campaigns:read, campaigns:write or messages:send.
404 not_found Unknown campaign, or a campaign of another workspace.
409 invalid_state Pause on a non-active campaign, resume on a non-paused one, lead pushed to a non-active campaign, or a campaign that has never been opened in the dashboard.
422 validation_error Bad phone, additional_data not an object or too big, external_reference too long.
429 rate_limited Too many requests this minute. Honor Retry-After.
502 upstream_error The first-message pipeline was unreachable. Retry in a moment.