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

# 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.apostra.com/api/v2/buyer/discovery/disc_01HZX3YQ7K9R6V3M2P1E0F8B2T/discover-products?groupOffset=10&publisherDomain=acme-media&pricingModel=cpm" \
    -H "Authorization: Bearer $SCOPE3_API_KEY"
  ```

  ```bash Page within groups theme={null}
  curl -X GET "https://api.apostra.com/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`, `cpa`, `flat_rate`, or `time`                                                                                                                                                              |
| `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). Apostra 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`.

Inside Murph, the runtime owns continuation once discovery starts. It retains the same discovery identity and reads cumulative groups with `sinceRevision: 0`, so products from earlier responses remain available when the final result reaches the assistant. It makes at most eight dispatches within 30 seconds. An unfinished or ambiguous result, or accumulated result pages that exceed its response-size limit, is reported as incomplete; it does not mean that no matching products exist. Murph keeps the original request and does not automatically start a replacement or attach products after that limit. A completed discovery with zero products has no products to attach. Selected products still pass the campaign, account and current discovery-publication checks before attachment. If an initial request is rejected before discovery executes, you can correct it and retry in the same conversation. An error while an existing discovery is running, or one whose execution outcome is uncertain, keeps the original request protected from replacement.

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.

Murph follows completed `get_products` result pages using their returned cursor and retains earlier pages before attaching products. An exact repeat of a confirmed attachment is acknowledged without sending it again; different selections can still be attached. When its active continuation history reaches 100 confirmed attachments, Murph stops further distinct attachments and preserves earlier confirmations. Legacy synchronous discovery continues to use its existing attachment checks.

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