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

# REST API endpoints for campaigns

> Create, list, start, and manage outbound calling campaigns using the Talkturo API. Includes scheduling, call windows, and contact assignment endpoints.

Campaigns let you run batch outbound calling to a list of contacts using a configured AI assistant. You create a campaign with scheduling and dialing settings, add contacts to it, then start it to begin placing calls. The API gives you full control over every step of this process, from initial creation through execution.

***

## List campaigns

`GET /api/crm/campaigns`

Returns a paginated list of campaigns for a team. You can filter by status, assistant, and whether to include soft-deleted campaigns.

### Query parameters

<ParamField query="teamId" type="string" required>
  The team ID to list campaigns for.
</ParamField>

<ParamField query="status" type="string">
  Filter campaigns by status. One of: `draft`, `scheduled`, `running`, `paused`, `completed`, `cancelled`.
</ParamField>

<ParamField query="assistantId" type="string">
  Filter campaigns assigned to a specific assistant ID.
</ParamField>

<ParamField query="deleted" type="string">
  Controls whether to include soft-deleted campaigns. One of: `exclude` (default), `include`, `only`.
</ParamField>

<ParamField query="limit" type="integer">
  Maximum number of records to return. Defaults to `50`.
</ParamField>

<ParamField query="offset" type="integer">
  Number of records to skip for pagination. Defaults to `0`.
</ParamField>

### Example request

```bash theme={null}
curl "https://<your-domain>/api/crm/campaigns?teamId=team_01j...&status=running&limit=20" \
  -H "Authorization: Bearer <token>"
```

### Response

```json theme={null}
{
  "success": true,
  "campaigns": [
    {
      "id": "camp_01j...",
      "team_id": "team_01j...",
      "assistant_id": "asst_01j...",
      "company_id": "comp_01j...",
      "name": "Q1 Outreach",
      "description": "Qualify leads from the January trade show",
      "from_number": "+12025551234",
      "status": "running",
      "call_window_start": "09:00",
      "call_window_end": "17:00",
      "call_window_timezone": "America/New_York",
      "max_concurrent_calls": 5,
      "total_contacts": 200,
      "contacts_called": 80,
      "contacts_completed": 65,
      "contacts_answered": 55,
      "created_at": "2024-01-10T09:00:00Z",
      "updated_at": "2024-01-15T14:30:00Z"
    }
  ],
  "count": 1,
  "limit": 20,
  "offset": 0
}
```

<ResponseField name="campaigns" type="array">
  Array of campaign objects.
</ResponseField>

<ResponseField name="campaigns[].id" type="string">
  Unique campaign identifier.
</ResponseField>

<ResponseField name="campaigns[].team_id" type="string">
  The team this campaign belongs to.
</ResponseField>

<ResponseField name="campaigns[].assistant_id" type="string">
  The assistant assigned to place calls in this campaign.
</ResponseField>

<ResponseField name="campaigns[].company_id" type="string">
  The company associated with this campaign.
</ResponseField>

<ResponseField name="campaigns[].name" type="string">
  Campaign name.
</ResponseField>

<ResponseField name="campaigns[].status" type="string">
  Current campaign status: `draft`, `scheduled`, `running`, `paused`, `completed`, or `cancelled`.
</ResponseField>

<ResponseField name="campaigns[].from_number" type="string">
  The phone number used as the caller ID for outbound calls.
</ResponseField>

<ResponseField name="campaigns[].call_window_start" type="string">
  Start of the daily call window in `HH:MM` format.
</ResponseField>

<ResponseField name="campaigns[].call_window_end" type="string">
  End of the daily call window in `HH:MM` format.
</ResponseField>

<ResponseField name="campaigns[].call_window_timezone" type="string">
  IANA timezone for the call window (for example, `America/New_York`).
</ResponseField>

<ResponseField name="campaigns[].max_concurrent_calls" type="integer">
  Maximum number of calls placed simultaneously.
</ResponseField>

<ResponseField name="campaigns[].total_contacts" type="integer">
  Total number of contacts in the campaign.
</ResponseField>

<ResponseField name="campaigns[].contacts_called" type="integer">
  Number of contacts where a call attempt was made.
</ResponseField>

<ResponseField name="campaigns[].contacts_completed" type="integer">
  Number of contacts where the call reached a terminal state.
</ResponseField>

<ResponseField name="campaigns[].contacts_answered" type="integer">
  Number of contacts who answered the call.
</ResponseField>

<ResponseField name="count" type="integer">
  Total number of campaigns matching the filters (before pagination).
</ResponseField>

<ResponseField name="limit" type="integer">
  The `limit` value applied to this response.
</ResponseField>

<ResponseField name="offset" type="integer">
  The `offset` value applied to this response.
</ResponseField>

***

## Create a campaign

`POST /api/crm/campaigns`

Creates a new outbound calling campaign. The campaign starts in `draft` status. Add contacts and then call the [run endpoint](#start-a-campaign) to begin dialing.

### Request body

<ParamField body="teamId" type="string" required>
  The team ID that owns this campaign.
</ParamField>

<ParamField body="assistantId" type="string" required>
  The ID of the assistant that will place calls.
</ParamField>

<ParamField body="companyId" type="string" required>
  The company ID to associate with this campaign.
</ParamField>

<ParamField body="fromNumberIds" type="array" required>
  An array of phone number IDs to use as caller IDs. Talkturo rotates across these numbers when placing calls.
</ParamField>

<ParamField body="name" type="string" required>
  A human-readable name for the campaign.
</ParamField>

<ParamField body="description" type="string">
  Optional description of the campaign's purpose.
</ParamField>

<ParamField body="scheduledStartAt" type="string">
  ISO 8601 datetime for when the campaign should start automatically. If omitted, you start the campaign manually via the run endpoint.
</ParamField>

<ParamField body="callWindowStart" type="string">
  Start of the daily calling window in `HH:MM` format (for example, `"09:00"`). Calls only go out during this window.
</ParamField>

<ParamField body="callWindowEnd" type="string">
  End of the daily calling window in `HH:MM` format (for example, `"17:00"`).
</ParamField>

<ParamField body="callWindowTimezone" type="string">
  IANA timezone for the call window (for example, `"America/New_York"`).
</ParamField>

<ParamField body="maxConcurrentCalls" type="integer">
  Maximum number of simultaneous outbound calls. Defaults to `3`.
</ParamField>

<ParamField body="maxAttemptsPerContact" type="integer">
  How many times to retry a contact who does not answer. Defaults to `3`.
</ParamField>

<ParamField body="retryDelayMinutes" type="integer">
  Minutes to wait before retrying a contact. Defaults to `60`.
</ParamField>

<ParamField body="settings" type="object">
  Additional campaign settings as a freeform object.
</ParamField>

### Example request

```bash theme={null}
curl -X POST https://<your-domain>/api/crm/campaigns \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "teamId": "team_01j...",
    "assistantId": "asst_01j...",
    "companyId": "comp_01j...",
    "fromNumberIds": ["pn_01j..."],
    "name": "Q1 Trade Show Follow-Up",
    "description": "Follow up with leads from the January trade show",
    "callWindowStart": "09:00",
    "callWindowEnd": "17:00",
    "callWindowTimezone": "America/New_York",
    "maxConcurrentCalls": 5,
    "maxAttemptsPerContact": 3,
    "retryDelayMinutes": 60
  }'
```

### Response

```json theme={null}
{
  "success": true,
  "campaign": {
    "id": "camp_01j...",
    "team_id": "team_01j...",
    "assistant_id": "asst_01j...",
    "company_id": "comp_01j...",
    "name": "Q1 Trade Show Follow-Up",
    "status": "draft",
    "call_window_start": "09:00",
    "call_window_end": "17:00",
    "call_window_timezone": "America/New_York",
    "max_concurrent_calls": 5,
    "total_contacts": 0,
    "contacts_called": 0,
    "contacts_completed": 0,
    "contacts_answered": 0,
    "created_at": "2024-01-15T10:00:00Z",
    "updated_at": "2024-01-15T10:00:00Z"
  }
}
```

***

## Add contacts to a campaign

`POST /api/crm/campaigns/{id}/contacts`

Adds one or more existing contacts to a campaign. Contacts must already exist in your CRM. Use the [contacts endpoints](/en/api-reference/contacts) to create them first if needed.

### Path parameters

<ParamField path="id" type="string" required>
  The campaign ID to add contacts to.
</ParamField>

### Request body

<ParamField body="contactIds" type="array" required>
  An array of contact ID strings to add to the campaign.
</ParamField>

### Example request

```bash theme={null}
curl -X POST https://<your-domain>/api/crm/campaigns/camp_01j.../contacts \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "contactIds": ["cont_01j...", "cont_02k...", "cont_03l..."]
  }'
```

### Response

```json theme={null}
{
  "success": true
}
```

***

## Start a campaign

`POST /api/crm/campaigns/{id}/run`

Initiates outbound calls for a campaign. Talkturo dials all contacts in `pending` or `queued` status, up to the campaign's `maxConcurrentCalls` limit. Use `dryRun: true` to preview which calls would be placed without actually dialing.

### Path parameters

<ParamField path="id" type="string" required>
  The campaign ID to start.
</ParamField>

### Request body

<ParamField body="accountSlug" type="string">
  Your account slug.
</ParamField>

<ParamField body="maxCalls" type="integer">
  Cap the number of calls started in this execution. Useful for gradual rollouts.
</ParamField>

<ParamField body="dryRun" type="boolean">
  When `true`, the API returns which calls would be started without actually placing them. Use this to verify campaign configuration before going live.
</ParamField>

### Example request

```bash theme={null}
curl -X POST https://<your-domain>/api/crm/campaigns/camp_01j.../run \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "accountSlug": "my-team",
    "maxCalls": 20
  }'
```

### Response

```json theme={null}
{
  "success": true,
  "started": 18,
  "failed": 2,
  "calls": [...],
  "errors": [
    "Contact cont_09x... has no phone number",
    "Contact cont_10y... is marked do-not-call"
  ],
  "message": "Started 18 calls",
  "dryRun": false
}
```

<ResponseField name="started" type="integer">
  Number of calls successfully initiated.
</ResponseField>

<ResponseField name="failed" type="integer">
  Number of contacts that could not be called in this run.
</ResponseField>

<ResponseField name="calls" type="array">
  Array of call objects for the calls that were started.
</ResponseField>

<ResponseField name="errors" type="array">
  Array of error message strings describing why individual contacts were skipped.
</ResponseField>

<ResponseField name="message" type="string">
  Human-readable summary of the run.
</ResponseField>

<ResponseField name="dryRun" type="boolean">
  Reflects the `dryRun` value from your request.
</ResponseField>

## Campaign status lifecycle

| Status      | Description                                               |
| ----------- | --------------------------------------------------------- |
| `draft`     | Campaign created but not yet started                      |
| `scheduled` | Campaign set to start at a future `scheduledStartAt` time |
| `running`   | Calls are actively being placed                           |
| `paused`    | Campaign temporarily stopped; can be resumed              |
| `completed` | All contacts have been reached or exhausted               |
| `cancelled` | Campaign stopped permanently                              |
