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

# Get campaign workspace

> Fetch the assembled CampaignWorkspace projection that backs the campaign drill-in in a single call

`GET /api/v2/buyer/campaigns/:id/workspace`

Returns the `CampaignWorkspace` projection: a presentation-ready view over
[Get campaign](/v2/buyer/campaigns/tasks/get-campaign) that assembles phase,
handling, budget, source, media buys, and per-seller creative approval status
into one response. It's built for a single-call dashboard read — the campaign
drill-in widget uses it — not a substitute for `get_campaign`, which remains
the source of the raw campaign resource.

## Request

```bash theme={null}
curl https://api.apostra.com/api/v2/buyer/campaigns/cmp_987654321/workspace \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
```

## Parameters

| Field        | Type   | Required | Notes                                    |
| ------------ | ------ | -------- | ---------------------------------------- |
| `campaignId` | string | Yes      | Path parameter — the campaign identifier |

## Response

Returns the `CampaignWorkspace` for the campaign — the base campaign fields plus
`mediaBuys[]` and `creatives[]`. See the `getCampaignWorkspace` schema in the API
reference for the authoritative response shape and field types; the key fields
are summarized in [Sections](#sections) below. Conditional fields (for example
`source`, and each media buy's `attentionNote`) appear only when they apply to
the campaign.

`CampaignWorkspace` also declares `spend`, `pacing`, `outcome`, and
`recentActivity` top-level fields, and `dimensions`/`previewUrl`/`placements`
on each creative — but this endpoint does not hydrate any of them today. They
are simply absent from the response, not falsy or zero.

## Review vs. record mode

`mode` tells the campaign drill-in widget which receipt moment it's rendering,
and is chosen by the server from the campaign's `phase` — it is not a request
parameter. A campaign still in `draft` (not yet executed / gone live) returns
`mode: "review"`: a plan glance plus a read-only `readiness.blockers` list of
what still stands between the draft and launch. Every other phase (`active`,
`completed`, `canceled`) returns `mode: "record"`, the ongoing-delivery view.

Only in `review` mode does this endpoint hydrate `readiness`, and only its
`blockers[]` — never `nextAction`, and `attention` is always `[]` here. Each
blocker is `{ code, message }`, derived purely from the campaign's own media
buys and creatives (no extra lookups):

* `CREATIVE_NOT_READY` — one per creative that isn't `ready` on *every* media
  buy it's attached to: `rejected`, `in_review`, `missing`, or not yet
  resolvable on any single occurrence blocks the whole creative (approved on
  one media buy does not clear a still-unresolved or rejected occurrence on
  another; a creative with no seller-review status yet counts as not ready,
  never as clear)
* `NO_MEDIA_BUYS` — the campaign has no media buys yet

`readiness.blockers` is always present as an array in review mode — an empty
array means the campaign is ready to go live, not that readiness wasn't
checked. In `record` mode, `readiness` is absent entirely, as before.

## Sections

| Field       | Notes                                                                                                                                                       |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `phase`     | One of `draft`, `active`, `completed`, `canceled` — the campaign's lifecycle stage                                                                          |
| `mode`      | `review` (draft, pre-launch) or `record` (everything else) — see [Review vs. record mode](#review-vs-record-mode)                                           |
| `handling`  | `tracking` (a directed/mirrored campaign) or `managing` (platform-managed)                                                                                  |
| `budget`    | The campaign-level total, currency, optional `dailyCap`, and `pacing` strategy                                                                              |
| `mediaBuys` | Each entry carries its own `budget` — sum these to see the budget split across media buys, since the total need not be fully allocated                      |
| `creatives` | Per-creative rollup: `readiness` is the worst status across `sellerReviews[]`, and each review names its seller and, when rejected or in review, an `issue` |

`creatives[].readiness` is the worst status across that creative's
`sellerReviews[]` — `rejected` outranks `in_review`/`missing`, which outranks
`ready`. A creative with no seller reviews yet omits `readiness` entirely
rather than defaulting to `ready`. `mediaBuys[]` and `creatives[]` are drawn
directly from the campaign's own media buys, so this is a single-fetch read —
no extra round-trip per media buy or creative.

## Errors

* `404 NOT_FOUND` — no campaign with this ID is visible to the authenticated account.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Get campaign" href="/v2/buyer/campaigns/tasks/get-campaign" icon="magnifying-glass">
    The full campaign resource this projects from
  </Card>

  <Card title="List campaigns" href="/v2/buyer/campaigns/tasks/list-campaigns" icon="list">
    Compact summaries across campaigns
  </Card>

  <Card title="Get media buy status" href="/v2/buyer/campaigns/tasks/get-media-buy-status" icon="signal">
    Poll live ADCP status
  </Card>

  <Card title="Campaign overview" href="/v2/object-guides/campaign" icon="rocket">
    Fields, lifecycle, and concepts
  </Card>
</CardGroup>
