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

# List campaign suggestion sets

> Find optimizer runs that move budget between media buys and need a decision

`GET /api/v2/buyer/campaign-suggestion-sets`

Lists the campaign suggestion sets for your account, newest activity first. Filter on
`status=AWAITING_APPROVAL` to see only the decisions outstanding. See
[campaign suggestion sets](/v2/buyer/campaigns/campaign-suggestion-sets) for what a set is
and why it is decided as a whole.

<Note>
  The list reports each set's `campaignMediaBuyCount` — the number of media buys the
  optimizer declared for the run — but not its per-media-buy breakdown. That count
  is a declaration, not a membership count: a set still awaiting messages can
  declare four and have none yet.
  [Read a single set](/v2/buyer/campaigns/tasks/get-campaign-suggestion-set) when you
  need to see where the money goes.
</Note>

## Request

```bash theme={null}
curl "https://api.apostra.com/api/v2/buyer/campaign-suggestion-sets?status=AWAITING_APPROVAL&limit=20" \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
```

## Parameters

| Field        | Type    | Required | Notes                                                                                                                                                             |
| ------------ | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`     | string  | No       | One of the set statuses. `AWAITING_APPROVAL` is the only actionable one.                                                                                          |
| `campaignId` | string  | No       | Restrict to one campaign. The campaign's business identifier, the same value `GET /campaigns` takes and this response returns — not its row id. 1–200 characters. |
| `limit`      | integer | No       | 1–100. Defaults to 20. Counts sets, which is all this response carries.                                                                                           |
| `offset`     | integer | No       | Defaults to 0.                                                                                                                                                    |

## Response

```json theme={null}
{
  "campaignSuggestionSets": [
    {
      "campaignSuggestionSetId": "77",
      "optimizerRunId": "8f14e45f-ceea-4c11-8e94-1c1a3c1e2f21",
      "campaignId": "cmp_987654321",
      "campaignDbId": "1042",
      "campaignName": "Nike Q1 Brand Awareness",
      "campaignRunSequence": "42",
      "campaignMediaBuyCount": 2,
      "budgetCurrency": "USD",
      "applyMode": "MANUAL",
      "status": "AWAITING_APPROVAL",
      "statusReason": null,
      "netAllocationDelta": "0",
      "notifiedAt": "2026-08-19T06:00:12.400Z",
      "decidedAt": null,
      "appliedAt": null,
      "applyAttemptCount": 0,
      "compensationAttemptCount": 0,
      "firstMessageAt": "2026-08-19T06:00:09.100Z",
      "lastMessageAt": "2026-08-19T06:00:11.800Z"
    }
  ],
  "hasMore": false
}
```

`netAllocationDelta` is in minor units of `budgetCurrency` — cents for USD, whole
yen for JPY — and is `"0"` for any set eligible to apply, because the transfers
inside it cancel out. It is `null` on a set that is not complete, since there is
nothing balanced to report yet.

Every allocation figure travels as a **string**, and that is not because the
values are too large for a JSON number — most are comfortably inside the exact
integer range. They are stored as int64, and the driver surfaces int64 as a
decimal string so no value can ever be silently rounded on the way out. Keep them
as strings or parse to a big-integer type; do not route them through a float.
