---
title: "One campaign in full, with a page of its people"
method: GET
path: "/api/v1/campaigns/{id}"
---

# One campaign in full, with a page of its people

`GET /api/v1/campaigns/{id}`

## Request

- Base URL: `https://www.easeclaw.com`
- URL: `https://www.easeclaw.com/api/v1/campaigns/{id}`
- Auth: HTTP bearer

Its settings, funnel counts, where its people came from, and a page of prospects carrying each person's drafted invite note and first message. Filter by state to see exactly what is waiting on a decision. Requires an outreach-scope API key (Pro plan or higher).

## Path parameters

- `id` string, uuid, required

## Query parameters

- `state` 'sourced' | 'qualified' | 'rejected' | 'awaiting_approval' | 'invite_approved' | 'invite_sent' | 'accepted' | 'dm_awaiting_approval' | 'dm_approved' | 'dm_sent' | 'done' | 'stale' | 'withdrawn' | 'stopped' | 'failed': Where one person stands in a campaign.
- `limit` integer
- `offset` integer

## Response `200`

The campaign, its counts, and one page of prospects

- object
  - `campaign` Campaign
    - `id` string, uuid
    - `project_id` string, uuid
    - `name` string
    - `source_type` 'competitor_harvest' | 'signal' | 'profile_urls' | 'csv' | 'basic_search' | 'sales_navigator' | 'recruiter' | 'my_network': Where a campaign's people come from. Defaults to competitor_harvest.
    - `source_ref` string, nullable: What this campaign sources from, per source_type. Null for signal campaigns (their source is the project) and for the multi-ref kinds, where provenance is recorded per person instead.
    - `source_params` object, nullable: basic_search only: the search descriptor it re-runs from
    - `signal_min_score` integer, nullable
    - `icp` object, nullable: This campaign's own targeting; null means it inherits the project's ICP
    - `status` 'draft' | 'sourcing' | 'review' | 'active' | 'paused' | 'done' | 'stopped'
    - `mode` 'autopilot' | 'copilot': Who approves what goes out: autopilot: the agent approves inside the owner's limits; copilot: every batch waits for the owner. Neither mode is reachable from this API: it decides who approves, and this surface is not either of them.
    - `invite_note_mode` 'none' | 'custom'
    - `invite_note_template` string, nullable
    - `first_message_template` string, nullable
    - `accept_wait_days` integer
    - `followup_wait_days` integer
    - `withdraw_after_days` integer, nullable: null = auto-withdraw off
    - `email_handoff_enabled` boolean
    - `email_handoff_campaign_id` string, nullable
    - `meeting_link` string, uri, nullable
    - `goal` 'meeting' | 'reply' | 'share_link' | 'null', nullable
    - `tone` 'friendly' | 'professional' | 'direct' | 'casual' | 'null', nullable
    - `language` 'en-US' | 'en-GB' | 'fr' | 'de' | 'es' | 'nl' | 'null', nullable
    - `exclude_first_degree` boolean
    - `split_messages` boolean
    - `email_fallback_days` integer, nullable: null = email fallback off
    - `daily_quota` integer, nullable
    - `created_at` string, date-time
    - `updated_at` string, date-time
  - `stats` CampaignStats: The funnel, counted. `replied` and `meetings` are counted off their own timestamps rather than off a state. A reply moves somebody to `done`, and a meeting is marked by a human.
    - `campaign_id` string, uuid
    - `prospects` integer
    - `sourced` integer
    - `qualified` integer
    - `rejected` integer
    - `awaiting_approval` integer
    - `invite_approved` integer
    - `invite_sent` integer
    - `accepted` integer
    - `dm_awaiting_approval` integer
    - `dm_approved` integer
    - `dm_sent` integer
    - `done` integer
    - `stale` integer
    - `stopped` integer
    - `failed` integer
    - `withdrawn` integer
    - `replied` integer
    - `handed_off` integer
    - `awaiting_email` integer
    - `meetings` integer
    - `last_activity_at` string, date-time, nullable
  - `sourceStats` object[], nullable: The same counts grouped by where each person came from. NULL means the view could not be read, distinct from an empty list.
  - `prospects` CampaignProspect[]
    - `id` string, uuid
    - `state` 'sourced' | 'qualified' | 'rejected' | 'awaiting_approval' | 'invite_approved' | 'invite_sent' | 'accepted' | 'dm_awaiting_approval' | 'dm_approved' | 'dm_sent' | 'done' | 'stale' | 'withdrawn' | 'stopped' | 'failed': Where one person stands in a campaign.
    - `score` integer, nullable: How well this person fits the campaign's targeting
    - `signal` string, nullable
    - `intent_score` integer, nullable
    - `source_meta` object, nullable: Where this person came from
    - `invite_note` string, nullable: What will go out for this person; null means the campaign template
    - `first_message` string, nullable
    - `state_changed_at` string, date-time, nullable
    - `invite_sent_at` string, date-time, nullable
    - `replied_at` string, date-time, nullable
    - `email_handoff_at` string, date-time, nullable
    - `meeting_at` string, date-time, nullable: Marked by a human. There is no calendar integration
    - `created_at` string, date-time
    - `contact` ContactIdentity: The person, as this surface may see them. Email and phone are deliberately absent.
      - `id` string, uuid
      - `full_name` string, nullable
      - `headline` string, nullable
      - `profile_url` string, nullable
      - `platform_uid` string, nullable

## Other responses

- `400`: Error
- `401`: Error
- `402`: Error
- `403`: The key is not outreach-scoped (code outreach_scope_required). Campaign paths need a key minted with the outreach scope at https://www.easeclaw.com/leads/api. The scope cannot be widened on an existing key.
- `404`: Error
- `429`: Rate limited (300/hour per account; drafting also 30/hour + daily AI budget). Retry-After header set when known.
- `500`: Error

---

[API](https://skmtc.dev/easeclaw/apis/easeclaw-api.md) · [All operations](https://skmtc.dev/easeclaw/apis/easeclaw-api/llms.txt) · [OpenAPI document](https://skmtc.dev/easeclaw/apis/easeclaw-api/revisions/79a190b20f61?raw)
