> ## 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.

# Campaign suggestion sets

> How optimizer suggestions that move budget between media buys are approved

When Apostra's optimizer works across a whole **campaign** rather than one media buy at
a time, its recommendations stop being independent. Taking budget out of one
media buy is what funds putting budget into another, so the two halves are one
decision. A **campaign suggestion set** is that decision: every media buy the
optimizer moved money between, grouped under the single run that computed them.

<Note>
  If you are not receiving sets yet, nothing is missing — see
  [Availability](#availability).
</Note>

## Why a set is approved as a whole

Each member of a set carries a `netAllocationDelta` — the amount that media buy
gains or gives up. Those are transfers, not standalone recommendations, and they
sum to exactly zero across the set.

That is why there is no way to approve one media buy's share on its own.
Approving a `+4000` minor units without its offsetting `-4000` would create
budget that the campaign never freed; approving the `-4000` alone would strand it. And rescaling a
subset so it balances by itself produces an allocation the optimizer never
evaluated against your goals or your sellers' capacity. So the set is the unit:
you approve all of it, or none of it.

The per-media-buy breakdown is there so you can see what the transfer does —
[read a single set](/v2/buyer/campaigns/tasks/get-campaign-suggestion-set) to get it.
It is not there so that parts of it can be actioned separately.

## The lifecycle of a set

<Steps>
  <Step title="Awaiting messages">
    The optimizer publishes one message per media buy it evaluated, and they
    arrive independently. Until all of them have, the set is incomplete and
    Apostra will not act on it — applying half a transfer would leave your
    campaign's budget unbalanced. A set can sit here legitimately while the rest of
    the run arrives.
  </Step>

  <Step title="Awaiting approval">
    The set is complete and balanced, and it is yours to decide. You are notified
    when a set reaches this state.
  </Step>

  <Step title="Approved or rejected">
    Your decision applies to the whole set.
    [Approve](/v2/buyer/campaigns/tasks/approve-campaign-suggestion-set) it, or
    [reject](/v2/buyer/campaigns/tasks/reject-campaign-suggestion-set) it — rejection
    optionally carries a reason; approval takes no body.
  </Step>

  <Step title="Applied">
    Apostra sends the changes to your sellers and waits for each one to take
    effect. This is not instant — see [What happens after you
    approve](#what-happens-after-you-approve).
  </Step>
</Steps>

If optimizations are set to apply automatically, a complete set goes straight to
approved without waiting for you. That setting is read from the campaign, falling
back to the advertiser's default when the campaign does not set one — so a set
can auto-approve on a campaign that appears to specify nothing. It is fixed when
the run is first seen, so changing it mid-run affects the next run, not one
already in flight.

## What happens after you approve

Approving does not move the money. It clears Apostra to move it, and the
move takes time, because each media buy lives at a different seller and a seller
takes a change when it takes it.

Two things about that are worth understanding, because they are what you will
see while polling.

**Budget is freed before it is spent.** Every media buy giving budget up is
changed first, and Apostra waits until each seller has actually enacted its
decrease before sending a single increase. It never commits budget the campaign has
not yet freed. That waiting is the reason a set stays in `APPLYING` for a while,
and it happens twice — once for the decreases and again for the increases. How
long that takes is up to your sellers: often minutes, longer when one queues the
change for review. Apostra keeps checking rather than assuming, and if a
seller goes quiet it stops and raises the set for a person rather than waiting
indefinitely.

**If a change cannot be made, the whole transfer is put back.** A set is one
decision, so it is applied as one. If a media buy's change fails after another
buy's change has already landed at its seller, Apostra restores every media
buy it had already moved to the budget it held before the set was applied.

The one exception is a reversal that cannot itself complete — a seller refuses
the undo, or never enacts it. Apostra then stops rather than guessing, moves
the set to `NEEDS_RECONCILIATION`, and a person puts the budgets right. Until
they do, your live budgets can sit part-way between the suggestion and their
pre-approval values; see the statuses below.

<Note>
  A media buy whose **flight has ended** while the set was applying is left out —
  of the transfer, and of the reversal too. A finished buy cannot spend what a
  budget change would give it, and failing the set over one would undo the other
  buys' correct changes over a calendar date. The set still completes and names
  the media buys it left out, on `statusReason`.

  The exception is a media buy that was **giving budget up**. If its flight ends
  before its seller has enacted the decrease, that budget was never freed — the
  buy may already have spent it — so Apostra does not send the increases it
  would have funded. The whole transfer is put back instead, and a later run
  re-plans the campaign without the finished buy.

  When a finished buy is left out, your budgets will not match either the
  suggestion or their pre-approval values exactly. A buy left out of a reversal
  may still be sitting at the applied budget, and because its flight has ended,
  nothing further will change it.
</Note>

### Statuses you may see

| Status                 | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AWAITING_MESSAGES`    | Not every media buy in the run has reported yet. Nothing to decide.                                                                                                                                                                                                                                                                                                                                                                                               |
| `AWAITING_APPROVAL`    | Complete and balanced. Waiting on your decision.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `APPROVED`             | Accepted — by you, or automatically if the campaign applies optimizations without review.                                                                                                                                                                                                                                                                                                                                                                         |
| `APPLYING`             | In progress: changes are being sent to your sellers and confirmed. How long it lasts is up to your sellers — the decreases are confirmed before any increase is sent.                                                                                                                                                                                                                                                                                             |
| `APPLIED`              | Done. Every media buy took its change, except any whose flight had ended — those are named on the set.                                                                                                                                                                                                                                                                                                                                                            |
| `COMPENSATING`         | Something could not be applied — or a media buy giving budget up finished its flight before its decrease landed — so the media buys that had already moved are being restored to their pre-approval budgets.                                                                                                                                                                                                                                                      |
| `COMPENSATED`          | The transfer was reversed. Every media buy it could reach is back at its pre-approval budget; any it could not are named on the set.                                                                                                                                                                                                                                                                                                                              |
| `APPLY_FAILED`         | Refused before any change reached a seller. Nothing moved, and there was nothing to put back.                                                                                                                                                                                                                                                                                                                                                                     |
| `NEEDS_RECONCILIATION` | A seller accepted a change but never enacted it within the hour, or the reversal itself could not complete. Apostra stops rather than guessing. Apostra is alerted and a person is resolving it.                                                                                                                                                                                                                                                                  |
| `REJECTED`             | Declined. Nothing moves.                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `SUPERSEDED`           | A newer, complete run for the same campaign replaced this one. Decide the newer set instead.                                                                                                                                                                                                                                                                                                                                                                      |
| `EXPIRED`              | The recommendation no longer describes your campaign — a media buy in it changed after the optimizer read it, or one reached a terminal state, or the campaign is gone. A later run will produce a fresh set.                                                                                                                                                                                                                                                     |
| `PARKED`               | Held back because the run did not satisfy its own consistency rules. Apostra is alerted; you do not need to act.                                                                                                                                                                                                                                                                                                                                                  |
| `DRY_RUN_RECORDED`     | Applying campaign-scoped optimizations is not switched on for your account, so nothing was sent to your sellers. What would have moved is recorded. Which set lands here is decided by the campaign: one you review terminates here instead of being offered to you, and one that applies optimizations without review terminates here instead of applying. Either way it is final rather than queued — nothing retries it, and a later run produces a fresh set. |

Only `AWAITING_APPROVAL` is actionable by you. Everything else is either in
progress or terminal.

`NEEDS_RECONCILIATION` is the one status where your live budgets may not match
either the suggestion or their pre-approval values. Apostra is alerted
automatically and resolves it; you do not need to open a ticket. Do not
hand-edit the affected media buys' budgets while a set is in this state —
doing so changes what Apostra is working from to put them right.

The `status` filter accepts the full enum. Treat an unrecognised status as "not
actionable by me" rather than assuming this list is closed.

## Finding sets that need you

[List campaign suggestion sets](/v2/buyer/campaigns/tasks/list-campaign-suggestion-sets)
and filter on `status=AWAITING_APPROVAL` to see just the decisions outstanding.
You can also filter by `campaignId`.

The list gives you each set's `campaignMediaBuyCount` but not its per-media-buy
breakdown — a single campaign can span many media buys, and a list is for finding the
set you care about. Fetch that one set to see where the money goes.

`campaignMediaBuyCount` is the number of media buys the optimizer **declared** for
the run, not the number reported so far. A set still in `AWAITING_MESSAGES` can
declare four and return an empty `mediaBuys` array, because membership is fixed
only once the set is complete.

## How a set relates to a suggestion

A campaign suggestion set is made of ordinary optimization suggestions — one per
member media buy — and each still appears through
`GET /api/v2/buyer/optimization-suggestions` as usual. What changes is where the
decision lives: a suggestion that belongs to a set cannot be approved or rejected
on its own, and attempting it returns `409` naming the set to decide instead.

## Availability

Campaign-scoped optimization is being rolled out. No campaign-scoped runs are
published yet, so these endpoints return nothing for anyone — they filter
nothing by account, and an empty list today is not a statement about your
rollout. Once runs are published, an account that is not yet enabled will have
its sets recorded rather than acted on, whether or not the campaign applies
optimizations without review, and no approval notification arrives for the ones
you would otherwise have reviewed. Nothing about your existing per-media-buy
optimization suggestions changes in the meantime.
