> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lehar.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Run your first campaign

> Create a voice campaign, add recipients, publish, start, and monitor it.

This walkthrough runs an outbound **voice** campaign end to end. For the execution mechanics behind it, see the [Campaign lifecycle deep-dive](/guides/campaign-lifecycle); for the states, the [Campaigns concept](/concepts/campaigns).

## Prerequisites

* A **published** agent — campaigns bind only published agents. See [Create & publish an agent](/guides/create-agent).
* The campaign worker and Campaign Engine running (otherwise `start` returns `503`).

Campaign management uses the `campaigns:write` / `campaigns:read` scopes — a workspace API key that carries them can run the whole flow (no admin role required).

<Steps>
  <Step title="Create the campaign">
    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/campaigns" \
      -H "X-API-KEY: $LEHAR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "March renewals",
        "campaign_type": "voice",
        "voice_agent_id": "agent_sales_hi",
        "timezone": "Asia/Kolkata",
        "schedule": {
          "business_hours": [ { "start": "09:00", "end": "18:00", "days": ["mon","tue","wed","thu","fri"] } ],
          "max_attempts": 3,
          "retry_delay_minutes": 120
        }
      }'
    ```

    The campaign starts as a `draft`.

    <Note>
      Agents are bound per channel: use `voice_agent_id` for `voice`, `whatsapp_agent_id` for `whatsapp`, and both for `whatsapp_voice`. The bound agent must be **published** and match the channel.
    </Note>
  </Step>

  <Step title="Add recipients">
    Add them one at a time, with per-recipient variables:

    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID/recipients" \
      -H "X-API-KEY: $LEHAR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "phone_number": "+919876543210", "variables": { "callee_name": "Jane", "company": "Acme" } }'
    ```

    Or bulk-upload a CSV or `.xlsx` file (multipart) to `POST /campaigns/{id}/recipients/import`. Recipients are deduplicated per `(campaign, phone)`; up to 50,000 per campaign.
  </Step>

  <Step title="Publish">
    Lock the configuration so the run is reproducible:

    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID/publish" -H "X-API-KEY: $LEHAR_API_KEY"
    ```

    After publishing, config `PATCH` is rejected (`409`) — a published campaign is a reusable template.
  </Step>

  <Step title="Start">
    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID/start" -H "X-API-KEY: $LEHAR_API_KEY"
    ```

    The status moves `scheduled` → `running`. Calls are placed within the campaign's business hours, retrying per the schedule.

    <Warning>
      `start` needs at least one recipient (else `400`) and the Campaign Engine available (else `503`). Any caller with `campaigns:write` can start a run — no admin role required.
    </Warning>
  </Step>

  <Step title="Monitor">
    Track progress and per-recipient outcomes:

    ```bash theme={null}
    curl "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID"          -H "X-API-KEY: $LEHAR_API_KEY"   # status
    curl "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID/attempts" -H "X-API-KEY: $LEHAR_API_KEY"   # per attempt
    curl "$LEHAR_BASE_URL/campaigns/$CAMPAIGN_ID/events"   -H "X-API-KEY: $LEHAR_API_KEY"   # audit log
    ```

    List responses are paged: pass `?limit=` (default 20, max 100) and `?offset=`. Attempts and recipients report `pagination.total`; the event log pages without one.

    Recipients end as `completed`, `no_answer`, or `failed`; the campaign completes `completed` (zero failures) or `failed`.
  </Step>
</Steps>

## Pause, resume, and re-run

* **Pause / resume** — `POST /campaigns/{id}/pause` halts new attempts; `POST /campaigns/{id}/start` resumes.
* **Re-run** — a finished campaign is terminal and read-only. To run it again, **clone** it (`POST /campaigns/{id}/clone`): the clone copies the config into a fresh `draft` with no recipients (its source recorded in `cloned_from_campaign_id`). Publish the clone, add a new recipient list, then `start`.

<CardGroup cols={2}>
  <Card title="Campaign lifecycle" icon="diagram-project" href="/guides/campaign-lifecycle">How a run executes under the hood.</Card>
  <Card title="WhatsApp campaigns" icon="whatsapp" href="/guides/whatsapp">Template + voice-escalation flow.</Card>
</CardGroup>
