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

# Create and Manage Bulk Outbound Calling Campaigns via API

> Learn how to create a Scalysis campaign, upload contacts or CSV data, then start, pause, and resume bulk outbound calling at scale.

Campaigns let you dial hundreds — or thousands — of contacts in a single operation without triggering each call individually. You define the contact list and script up front, then use the campaign control endpoint to start, pause, or resume dialing on demand. This guide walks you through creating a campaign with a contacts array or a raw CSV string, then managing its lifecycle from `not_started` all the way to `completed`.

## Prerequisites

* **API key** from your [Scalysis dashboard](https://app.scalysis.com).
* **Script ID** for the AI script the campaign will use.
* A list of customer phone numbers you want to dial.

***

<Steps>
  <Step title="Create the campaign">
    Send a `POST` request to `/api/v1/campaigns` with your script ID and contact list. You can supply contacts either as a structured JSON array or as a raw CSV string — pick whichever fits your workflow.

    ### Option A — contacts array

    Each object in `contacts[]` must include `customerPhone`. All other fields are optional but recommended.

    ```bash theme={null}
    curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{
        "scriptId": 2207,
        "name": "July COD Confirmations",
        "kind": "cod",
        "startImmediately": false,
        "maxConcurrency": 5,
        "contacts": [
          {
            "customerPhone": "919149874123",
            "customerName": "Rahul Sharma",
            "orderNumber": "ORD-1001",
            "orderNotes": "Fragile item, handle with care"
          },
          {
            "customerPhone": "919876543210",
            "customerName": "Priya Mehta",
            "orderNumber": "ORD-1002"
          }
        ]
      }'
    ```

    ### Option B — CSV text

    Pass your CSV data as a raw string in `csvText`. By default, Scalysis reads phone numbers from a column named `phone_number`; use `phoneColumn` to point to a different column header.

    <CodeGroup>
      ```bash Default phone_number column theme={null}
      curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns' \
        -H 'Authorization: Bearer YOUR_API_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "scriptId": 2207,
          "name": "July COD Confirmations",
          "kind": "cod",
          "startImmediately": false,
          "csvText": "phone_number,name,order\n919149874123,Rahul,ORD-1001\n919876543210,Priya,ORD-1002"
        }'
      ```

      ```bash Custom column name theme={null}
      curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns' \
        -H 'Authorization: Bearer YOUR_API_KEY' \
        -H 'Content-Type: application/json' \
        -d '{
          "scriptId": 2207,
          "name": "July COD Confirmations",
          "kind": "cod",
          "startImmediately": false,
          "csvText": "mobile,name,order\n919149874123,Rahul,ORD-1001\n919876543210,Priya,ORD-1002",
          "phoneColumn": "mobile"
        }'
      ```
    </CodeGroup>

    **Request fields reference:**

    | Field                   | Type    | Required              | Description                                                                        |
    | ----------------------- | ------- | --------------------- | ---------------------------------------------------------------------------------- |
    | `scriptId`              | number  | ✅ Yes                 | Script the AI will run for every contact.                                          |
    | `contacts`              | array   | ✅ Yes (or `csvText`)  | Array of contact objects. Each must have `customerPhone`.                          |
    | `csvText`               | string  | ✅ Yes (or `contacts`) | Raw CSV string. Use instead of `contacts[]`.                                       |
    | `phoneColumn`           | string  | No                    | CSV column containing phone numbers. Defaults to `phone_number`.                   |
    | `name` / `campaignName` | string  | No                    | Human-readable label shown in the dashboard.                                       |
    | `kind`                  | string  | No                    | Campaign type: `"cod"`, `"list"`, or `"ndr"`.                                      |
    | `startImmediately`      | boolean | No                    | If `true`, dialing begins as soon as the campaign is created. Defaults to `false`. |
    | `maxConcurrency`        | number  | No                    | Maximum simultaneous calls. Useful for rate-limiting.                              |

    <Tip>
      Set `startImmediately: false` when creating a campaign. This gives you time to review the contact count in the response before committing to a live dial run — especially useful for large lists where a CSV parsing issue could otherwise affect thousands of contacts.
    </Tip>

    <Note>
      Keep each campaign creation request to roughly **2,000 contacts or fewer**. For larger lists, split them across multiple campaigns and stagger the start times.
    </Note>
  </Step>

  <Step title="Note the campaign_id from the response">
    A successful create request returns HTTP **200** with the following body:

    ```json theme={null}
    {
      "success": true,
      "action": "create_campaign",
      "kind": "cod",
      "campaign_id": "camp_9f3a21b7",
      "name": "July COD Confirmations",
      "state": "not_started",
      "contact_count": 2,
      "started": false,
      "message": "Campaign created successfully"
    }
    ```

    | Field           | Description                                                                                |
    | --------------- | ------------------------------------------------------------------------------------------ |
    | `campaign_id`   | **Save this.** Required for all subsequent control and status requests.                    |
    | `state`         | Current lifecycle state — see the states table below.                                      |
    | `contact_count` | Number of contacts Scalysis parsed from your input. Verify this matches your expectations. |
    | `started`       | `false` when `startImmediately` was omitted or set to `false`.                             |
  </Step>

  <Step title="Start the campaign">
    When you're ready to begin dialing, send a control request with `action: "start"`:

    ```bash theme={null}
    curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns/camp_9f3a21b7/control' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{"action": "start"}'
    ```

    Expected response:

    ```json theme={null}
    {
      "success": true,
      "action": "start",
      "campaign_id": "camp_9f3a21b7",
      "state": "running",
      "message": "Campaign started successfully"
    }
    ```

    Scalysis will now begin dialing contacts in order, respecting any `maxConcurrency` limit you set.
  </Step>

  <Step title="Monitor or pause the campaign">
    If you need to stop dialing mid-run — for example, due to off-hours restrictions or an issue with your script — send a `pause` action:

    ```bash theme={null}
    curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns/camp_9f3a21b7/control' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{"action": "pause"}'
    ```

    Expected response:

    ```json theme={null}
    {
      "success": true,
      "action": "pause",
      "campaign_id": "camp_9f3a21b7",
      "state": "paused",
      "message": "Campaign paused successfully"
    }
    ```

    Any calls already in progress will complete naturally. No new calls are placed while the campaign is paused.
  </Step>

  <Step title="Resume the campaign">
    Ready to continue? Send a `resume` action and Scalysis picks up where it left off:

    ```bash theme={null}
    curl -sS -X POST 'https://app.scalysis.com/api/v1/campaigns/camp_9f3a21b7/control' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{"action": "resume"}'
    ```

    Expected response:

    ```json theme={null}
    {
      "success": true,
      "action": "resume",
      "campaign_id": "camp_9f3a21b7",
      "state": "running",
      "message": "Campaign resumed successfully"
    }
    ```
  </Step>
</Steps>

***

## Campaign states

| State         | Meaning                                                  |
| ------------- | -------------------------------------------------------- |
| `not_started` | Campaign created but dialing has not begun.              |
| `running`     | Calls are actively being placed.                         |
| `paused`      | Dialing is temporarily halted; can be resumed.           |
| `completed`   | All contacts have been dialed. No further action needed. |
| `stopped`     | Campaign was permanently stopped and cannot be resumed.  |
