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

# Get campaign statistics

> Returns the statistics of one campaign, calculated exactly like the Statistics page of the app: call volumes, sessions, connection & conversion rates, callback rate, a dispositions breakdown and a per-agent breakdown.

Outbound and inbound calls are both included by default (inbound calls are linked to a campaign when the caller is one of its leads). Without a period, the whole campaign history is used. See [Get Statistics](https://docs.reachedapp.com/rest-api/statistics/get-stats) for the meaning of each metric.

## Request

```text theme={null}
GET /v1/campaigns/:id/stats
```

### Path parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `id` | `uuid` | Yes | The campaign ID |

### Query parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `period` | `string` | No | Preset period: `today`, `yesterday`, `this_week`, `last_week`, `this_month`, `last_month`, `last_7_days`, `last_30_days`, `all_time` (default: `all_time`) |
| `date_from` | `string` | No | Custom start day (`YYYY-MM-DD`, included). Cannot be combined with `period` |
| `date_to` | `string` | No | Custom end day (`YYYY-MM-DD`, included). Defaults to today |
| `timezone` | `string` | No | Timezone used to cut days, as an IANA name (default: `Europe/Paris`) |
| `direction` | `string` | No | `all` (default), `outbound` or `inbound` |

### Example

```bash cURL theme={null}
curl -X GET \
  "https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/campaigns/c1d2e3f4-.../stats?period=last_30_days&direction=all" \
  -H "Authorization: Bearer rchd_live_xxxxxxxxxxxx"
```

```javascript JavaScript theme={null}
const campaignId = 'c1d2e3f4-...';

const response = await fetch(
  `https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/campaigns/${campaignId}/stats?period=last_30_days`,
  {
    headers: {
      'Authorization': 'Bearer rchd_live_xxxxxxxxxxxx'
    }
  }
);

const { data } = await response.json();
```

```python Python theme={null}
import requests

campaign_id = 'c1d2e3f4-...'

response = requests.get(
    f'https://kdjmltmhxvvmiuehafgl.supabase.co/functions/v1/api-gateway/v1/campaigns/{campaign_id}/stats',
    headers={'Authorization': 'Bearer rchd_live_xxxxxxxxxxxx'},
    params={'period': 'last_30_days'}
)

data = response.json()['data']
```

***

## Response

### Top-level fields

| Field | Type | Description |
| - | - | - |
| `total_leads` | `integer` | Total leads enrolled in the campaign |
| `called_leads` | `integer` | Distinct leads called at least once |
| `total_calls` | `integer` | Every line dialed |
| `sessions` | `integer` | Dialing attempts. With parallel dialing, several lines dialed together count as one session |
| `calls_per_session` | `float` | `total_calls / sessions` |
| `answered_calls` | `integer` | Sessions where a real person was put through to the agent (voicemails and answering machines excluded) |
| `connection_rate` | `float` | `answered_calls / sessions × 100` (%) |
| `conversations` | `integer` | Connected calls lasting 60 seconds or more |
| `appointments` | `integer` | Calls with the `appointment-scheduled` disposition |
| `conversion_rate` | `float` | `appointments / answered_calls × 100` (%) |
| `total_talk_time_seconds` | `integer` | Time spent talking on connected calls |
| `avg_talk_time_seconds` | `integer` | Average talk time per connected call |
| `voicemails_reached` | `integer` | Calls that ended on a voicemail (`voicemail`, `voicemail-left`) |
| `voicemails_avoided` | `integer` | Voicemails or answering machines detected and skipped automatically |
| `callback_rate` | `float` | Share of called leads who called back afterwards (%) |
| `dispositions` | `array` | Breakdown of call outcomes — see below |
| `agents` | `array` | Per-agent performance — see below |
| `period` | `object` | The period actually used: `preset`, `date_from`, `date_to`, `timezone` |
| `direction` | `string` | The direction filter actually used |

Rates are percentages rounded to one decimal.

### `dispositions` array

| Field | Type | Description |
| - | - | - |
| `disposition` | `string` | The outcome label (e.g. `no-answer`, `appointment-scheduled`) |
| `count` | `integer` | Number of calls with that outcome |
| `percentage` | `float` | Share of `total_calls` (%) |

### `agents` array

| Field | Type | Description |
| - | - | - |
| `agent_id` | `uuid` | User ID of the agent |
| `first_name` | `string` | Agent first name |
| `last_name` | `string` | Agent last name |
| `email` | `string` | Agent email address |
| `total_calls` | `integer` | Lines dialed by this agent in the campaign |
| `sessions` | `integer` | Dialing attempts by this agent |
| `answered_calls` | `integer` | Sessions put through to this agent |
| `connection_rate` | `float` | `answered_calls / sessions × 100` (%) |
| `conversations` | `integer` | Conversations (≥ 60 s) |
| `appointments` | `integer` | Appointments booked by this agent |
| `conversion_rate` | `float` | `appointments / answered_calls × 100` (%) |
| `total_talk_time_seconds` | `integer` | Cumulative talk time in seconds |

### Example response

```json theme={null}
{
  "data": {
    "total_leads": 350,
    "called_leads": 280,
    "total_calls": 412,
    "sessions": 300,
    "calls_per_session": 1.37,
    "answered_calls": 96,
    "connection_rate": 32.0,
    "conversations": 41,
    "appointments": 9,
    "conversion_rate": 9.4,
    "total_talk_time_seconds": 9540,
    "avg_talk_time_seconds": 92,
    "voicemails_reached": 38,
    "voicemails_avoided": 71,
    "callback_rate": 6.4,
    "dispositions": [
      { "disposition": "no-answer", "count": 214, "percentage": 51.9 },
      { "disposition": "voicemail-avoided", "count": 71, "percentage": 17.2 },
      { "disposition": "voicemail-left", "count": 38, "percentage": 9.2 },
      { "disposition": "not-interested", "count": 35, "percentage": 8.5 },
      { "disposition": "appointment-scheduled", "count": 9, "percentage": 2.2 }
    ],
    "agents": [
      {
        "agent_id": "u1a2b3c4-...",
        "first_name": "Sophie",
        "last_name": "Bernard",
        "email": "sophie@company.com",
        "total_calls": 210,
        "sessions": 152,
        "answered_calls": 52,
        "connection_rate": 34.2,
        "conversations": 23,
        "appointments": 5,
        "conversion_rate": 9.6,
        "total_talk_time_seconds": 5120
      },
      {
        "agent_id": "u9x8y7z6-...",
        "first_name": "Thomas",
        "last_name": "Petit",
        "email": "thomas@company.com",
        "total_calls": 202,
        "sessions": 148,
        "answered_calls": 44,
        "connection_rate": 29.7,
        "conversations": 18,
        "appointments": 4,
        "conversion_rate": 9.1,
        "total_talk_time_seconds": 4420
      }
    ],
    "period": {
      "preset": "last_30_days",
      "date_from": "2026-02-19",
      "date_to": "2026-03-21",
      "timezone": "Europe/Paris"
    },
    "direction": "all"
  }
}
```

***

## Errors

| Status | Code | Description |
| - | - | - |
| `400` | `bad_request` | Invalid period, dates, timezone or direction |
| `401` | `unauthorized` | Missing or invalid API key |
| `404` | `not_found` | Campaign not found or does not belong to your account |
| `500` | `internal` | Unexpected server error |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.