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

# Get media buy packages

> Read a media buy's packages and resolve a description to a packageId

`GET /api/v2/buyer/media-buys/:mediaBuyId/packages`

Lists a media buy's packages with the attributes that identify each one: `productId`, `productName`, the package's own `startTime`/`endTime`, and its `pacingPeriod` (index plus the campaign's label, e.g. `"Week 6"`). Use this to turn a description of a package ("the display package ending 2026-08-11") into the `packageId` to send to [Update campaign](/v2/buyer/campaigns/tasks/update-campaign). Prefer it over `GET /campaigns/:id` whenever the goal is to pick a package: this response carries no targeting, creative, or format detail, so it stays small enough for an agent to read in full.

Update campaign is addressed by campaign, not by media buy, so you need the parent `campaignId` as well as the `packageId` to act on what you find here. This response does not carry it: keep it from whichever read gave you the media buy ID, or recover it from [List campaigns](/v2/buyer/campaigns/tasks/list-campaigns) by matching `mediaBuys[].mediaBuyId`.

<Warning>
  The trailing number on a `packageId` (e.g. the `3` in `sf_pkg_sf_mb_1783618937177_43ycbp7b_3`) is a dispatch-order position, not the pacing period. Never parse it. Read `pacingPeriod.index` and `pacingPeriod.label` to identify a period. See [Package identity and the id numbering scheme](/v2/buyer/campaigns/packages#package-identity-and-the-id-numbering-scheme).
</Warning>

## Request

```bash theme={null}
curl https://api.interchange.io/api/v2/buyer/media-buys/mb_ETBn4gJ9Wu/packages \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
```

No request body.

## Parameters

| Field        | Type   | Required | Notes                          |
| ------------ | ------ | -------- | ------------------------------ |
| `mediaBuyId` | string | Yes      | Media buy ID (path parameter). |

## Response

```json theme={null}
{
  "mediaBuyId": "mb_ETBn4gJ9Wu",
  "isPaced": true,
  "packageCount": 2,
  "packages": [
    {
      "packageId": "sf_pkg_sf_mb_1783618937177_43ycbp7b_1",
      "productId": "prod_display_300x250",
      "productName": "Display Run of Site",
      "status": "active",
      "pacingPeriod": { "index": 1, "label": "Week 1" },
      "startTime": "2026-08-01T00:00:00Z",
      "endTime": "2026-08-07T23:59:59Z",
      "budget": 5000,
      "budgetCurrency": "USD",
      "pacing": "even",
      "delivery": { "impressions": 210000, "spend": 4980, "clicks": 84 }
    },
    {
      "packageId": "sf_pkg_sf_mb_1783618937177_43ycbp7b_2",
      "productId": "prod_display_300x250",
      "productName": "Display Run of Site",
      "status": "active",
      "pacingPeriod": { "index": 2, "label": "Week 2" },
      "startTime": "2026-08-08T00:00:00Z",
      "endTime": "2026-08-11T23:59:59Z",
      "budget": 5000,
      "budgetCurrency": "USD",
      "pacing": "even"
    }
  ]
}
```

<Note>
  That is the shape of a paced buy executed after this read shipped. Packages created before it carry no `pacingPeriod` at all, and most carry no `startTime`/`endTime` either, so on media buys that are already live today the response below is the one to expect. Neither gap can be backfilled.
</Note>

```json theme={null}
{
  "mediaBuyId": "mb_ETBn4gJ9Wu",
  "isPaced": true,
  "packageCount": 2,
  "packages": [
    {
      "packageId": "sf_pkg_sf_mb_1781130562070_h0npv6ag_1",
      "productId": "contextual-generative-display-cpc",
      "productName": "Contextual Generative Display (CPC)",
      "status": "active",
      "budget": 634.5,
      "budgetCurrency": "USD",
      "pacing": "even"
    },
    {
      "packageId": "sf_pkg_sf_mb_1781130562070_h0npv6ag_2",
      "productId": "contextual-generative-display-cpc",
      "productName": "Contextual Generative Display (CPC)",
      "status": "active",
      "budget": 634.5,
      "budgetCurrency": "USD",
      "pacing": "even"
    }
  ]
}
```

Both entries are the same product with the same budget and no window, so neither can be resolved to a period through this API. See [Packages without a recorded flight window](/v2/buyer/campaigns/packages#packages-without-a-recorded-flight-window) for what to do instead.

* `mediaBuyId`: the media buy these packages belong to.
* `isPaced`: whether this buy was split across pacing periods. When `true`, expect one package per product per period, and use `pacingPeriod` to tell them apart where it is present. On buys executed before this read shipped, `isPaced` is `true` while every package lacks `pacingPeriod`, and the period cannot be recovered.
* `packageCount`: how many packages this media buy has.
* `packages[]`: grouped by product, then ordered by `pacingPeriod.index` where it is present. Packages with no recorded period sort by `packageId` as text, which is not dispatch order (`..._10` sorts before `..._2`). Never read a period out of a package's position in this array. See the [numbering scheme](/v2/buyer/campaigns/packages#package-identity-and-the-id-numbering-scheme):
  * `packageId`: the identifier to quote when updating or pausing this package. Opaque, do not parse it.
  * `productId`: the seller product this package buys. `null` when the product is not locally resolvable.
  * `productName`: the product's name as published by the seller, when known locally.
  * `status`: `active`, `paused`, or `canceled`. Independent of the media buy's own status: a live buy can carry a paused package.
  * `pacingPeriod`: `{ index, label }`. `index` is a one-based ordinal counting from the campaign's first period; `label` is how the campaign named it ("Week 6"). Absent when the buy is not paced, and absent on every package created before period identity was recorded.
  * `startTime` / `endTime`: ISO 8601. Present on paced packages executed after this read shipped. Absent on an unpaced buy, where the package runs the media buy's own window and has no separate one, and absent on packages created before the platform retained the window it requested. Match on `pacingPeriod.label` where you have it, since that is the buyer's own wording ("Week 6"); `endTime` is the fallback when you already know a literal date. Where neither is present, `productName` plus `budget` sometimes narrows it to one, but a schedule that gave those periods equal budgets gives their packages identical budgets, and those cannot be told apart through this API.
  * `budget`: this package's budget, gross of buyer fees, in `budgetCurrency`.
  * `budgetCurrency`: ISO-4217 currency of `budget`.
  * `pacing`: how the package spends its budget (`even`, `asap`, or `front_loaded`).
  * `delivery`: `{ impressions, spend, clicks }`. Absent when the package has not delivered yet or the source has not reported.

A buy that has not been dispatched yet returns `200` with `packageCount: 0` and an empty `packages[]`. Packages exist only after execute, so a DRAFT buy, a `PENDING_APPROVAL` buy that has not executed, and a rejected buy all read as empty rather than as an error. See [Execute campaign](/v2/buyer/campaigns/tasks/execute-campaign).

## Errors

| Code        | When                                                       |
| ----------- | ---------------------------------------------------------- |
| `NOT_FOUND` | Media buy ID does not exist for the authenticated account. |

See [Errors](/v2/reference/errors) for the full error shape and recovery semantics.

## Related

<CardGroup cols={2}>
  <Card title="Packages" href="/v2/buyer/campaigns/packages" icon="box">
    Package identity, the id numbering scheme, and pacing period behavior
  </Card>

  <Card title="Get campaign products" href="/v2/buyer/campaigns/tasks/get-campaign-products" icon="boxes-stacked">
    The campaign-scoped lean package-ID read for every product on a buy
  </Card>

  <Card title="Update campaign" href="/v2/buyer/campaigns/tasks/update-campaign" icon="pen">
    Pass packageId to update or cancel a single package
  </Card>

  <Card title="Media buy status" href="/v2/buyer/campaigns/tasks/get-media-buy-status" icon="signal-stream">
    Poll live ADCP status after execute
  </Card>
</CardGroup>
