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

# Browse products

> Page through a discovery session's cached results

`GET /api/v2/buyer/discovery/{discoveryId}/discover-products`

Returns products from an existing session without spending another LLM-enriched discovery call. Filters narrow the cached result set in place. Use this to page across groups (`groupOffset`) and products (`productOffset`) after the first [Discover products](/v2/buyer/discovery/tasks/discover-products) call.

## Request

<CodeGroup>
  ```bash curl theme={null}
  curl -X GET "https://api.interchange.io/api/v2/buyer/discovery/disc_01HZX3YQ7K9R6V3M2P1E0F8B2T/discover-products?groupOffset=10&publisherDomain=acme-media.example&pricingModel=cpm" \
    -H "Authorization: Bearer $SCOPE3_API_KEY"
  ```

  ```bash Page within groups theme={null}
  curl -X GET "https://api.interchange.io/api/v2/buyer/discovery/disc_01HZX3YQ7K9R6V3M2P1E0F8B2T/discover-products?productsPerGroup=15&productOffset=5" \
    -H "Authorization: Bearer $SCOPE3_API_KEY"
  ```
</CodeGroup>

## Parameters

| Field              | Type       | Required | Notes                                                                                                                                                                                                                                  |
| ------------------ | ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `discoveryId`      | string     | Yes      | Path param — session to browse                                                                                                                                                                                                         |
| `groupLimit`       | integer    | No       | Max product groups (max 10). Default 10                                                                                                                                                                                                |
| `groupOffset`      | integer    | No       | Groups to skip. Default 0                                                                                                                                                                                                              |
| `productsPerGroup` | integer    | No       | Max products per group (max 15). Default 10                                                                                                                                                                                            |
| `productOffset`    | integer    | No       | Products to skip within each group (max 1000). Default 0                                                                                                                                                                               |
| `publisherDomain`  | string     | No       | Filter by publisher domain (exact component match)                                                                                                                                                                                     |
| `pricingModel`     | enum       | No       | `cpm`, `vcpm`, `cpc`, `cpcv`, `cpv`, `cpp`, or `flat_rate`                                                                                                                                                                             |
| `storefrontIds`    | integer\[] | No       | Filter by storefront ID(s) (max 50)                                                                                                                                                                                                    |
| `storefrontNames`  | string\[]  | No       | Filter by storefront name substring (max 50)                                                                                                                                                                                           |
| `debug`            | boolean    | No       | Include per-agent ADCP debug logs for failed agents                                                                                                                                                                                    |
| `waitMode`         | enum       | No       | `quick` waits up to the interactive default per storefront; `long` waits up to the maximum interactive window. Ask before using `long`                                                                                                 |
| `waitSeconds`      | integer    | No       | Explicit per-storefront wait in seconds, max 210. Overrides `waitMode`; ask before setting above 30                                                                                                                                    |
| `sinceRevision`    | integer    | No       | Progressive polling: return only seller groups that landed after this revision. The response carries the current `revision`, `resultsComplete`, and `pendingAgents`; poll with the returned `revision` until `resultsComplete` is true |

## Response

```json theme={null}
{
  "discoveryId": "disc_01HZX3YQ7K9R6V3M2P1E0F8B2T",
  "productGroups": [
    {
      "groupId": "ctx_disc_01HZX3-group-1",
      "groupName": "Example Media Premium CTV",
      "productCount": 6,
      "totalProducts": 9,
      "hasMoreProducts": true,
      "products": [
        {
          "productId": "prod_example_ctv_premium",
          "name": "Example Media Premium CTV - 30s",
          "channel": "ctv",
          "cpm": 28.0,
          "salesAgentId": "agent_example_media",
          "deliveryType": "guaranteed"
        }
      ]
    }
  ],
  "totalGroups": 18,
  "hasMoreGroups": false,
  "summary": { "totalProducts": 142, "publishersCount": 18, "priceRange": { "min": 4.5, "max": 78.0, "avg": 21.4 } },
  "incompleteAgents": [
    {
      "agentId": "agent_slow_media",
      "agentName": "Slow Media Storefront",
      "reason": "timeout",
      "waitSeconds": 30
    }
  ],
  "retryWithLongerWaitAvailable": true
}
```

Returns the same `DiscoverProductsResponse` shape as discover. Browsing reads from the discovery snapshot cache (TTL 4 hours) — re-run `POST /discover-products` with the same brief to refresh after expiry.

<Note>
  The snapshot's 4-hour TTL can outlive an individual product's FX-quote hold (an [FX-converted](/v2/concepts/cross-currency) product's `expiresAt`, at most until next UTC midnight). Scope3 enforces this server-side: if any product in a cached snapshot has passed its `expiresAt`, the snapshot is treated as stale and this call transparently re-discovers instead of paginating an expired price — you may see a fresh (unpaginated) result in that case rather than the exact page you requested. If you cache the response yourself, apply the same rule: never serve an item past its `expiresAt`.
</Note>

When polling a [progressive discovery](/v2/buyer/discovery/tasks/discover-products#progressive-delivery) with `sinceRevision`, the response additionally carries `revision`, `resultsComplete`, `pendingAgents`, and — while incomplete — a `guidance` string spelling out the exact next call, and `productGroups` contains only seller groups that landed after the revision you passed — with replace semantics (a group may be re-delivered with more products; replace it by `groupId`). Poll with each response's `revision` until `resultsComplete` is true, or stop after roughly your wait budget and treat remaining `pendingAgents` like `incompleteAgents`.

If one or more storefronts timed out or returned partial results for the requested wait window, the response includes `incompleteAgents` without requiring `debug=true`. When `retryWithLongerWaitAvailable` is `true`, you can browse again with `waitMode: "long"` or a larger `waitSeconds` value after confirming the buyer wants to wait longer. If `retryWithLongerWaitAvailable` is `false`, the response is already at the maximum interactive wait window.

## Errors

* `400 VALIDATION_ERROR` — invalid `pricingModel` or out-of-range pagination value.
* `404 NOT_FOUND` — `discoveryId` does not exist or is not visible to the authenticated account.

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

## Related

<CardGroup cols={2}>
  <Card title="Discovery overview" href="/v2/guides/discovery" icon="rocket">
    Sessions, pagination, and caching
  </Card>

  <Card title="Discover products" href="/v2/buyer/discovery/tasks/discover-products" icon="magnifying-glass">
    Run discovery and open a session
  </Card>

  <Card title="Add products" href="/v2/buyer/discovery/tasks/add-products" icon="plus">
    Add a browsed product to the selection
  </Card>

  <Card title="Get products" href="/v2/buyer/discovery/tasks/get-products" icon="list">
    List the current selection
  </Card>
</CardGroup>
