API
Reference for the Discovery OS Shopify app proxy: search, merchandising routes (mRoute), and recommendations. Call these endpoints from the storefront when you integrate your own UI.
Replace {shopDomain} with the store’s Shopify hostname (for example your-store.myshopify.com). Requests are made from the buyer’s browser on the storefront origin so the app proxy can authenticate the session.
Prerequisites: Enable the app embed, validate the session.
Session validation
The app embed exposes **window.paDiscoveryOsApp.validateSession()**. Your client must await this before calling search, mRoute, or recommendations so the session stays valid and lines up with the stored config.
// Example implementation
export async function paRequest(paRequest) {
if (typeof request !== 'function') {
throw new Error('paRequest expects a function as argument');
}
try {
if (window.paDiscoveryOsApp?.validateSession) {
await window.paDiscoveryOsApp.validateSession();
}
return await paRequest();
} catch (error) {
console.error('paRequest failed:', error);
throw error;
}
}
Search API
Purpose: Run a catalog search and get product hits plus aggregations.
| Method | POST |
| URL | https://{shopDomain}/apps/discoveryos/search |
Sample payload
{
"q": "bike", // search term or query
"start": 0,
"size": 5,
"scope": {"brand": ["Bryton"]}, // selected filters,
"sort_fields": [{"price": { "order": "desc", "type": "number"}}], // selected sort
"selected_fields": [ // list of field names that you want to be returned with product response
"title",
"brand",
"link",
"type",
"image_link",
"collections",
"variants.id",
"variants.title",
"variants.price",
"variants.delivery_status",
"variants.badge_handle",
"variants.search_information",
"variants.availableForSale",
"variants.delivery"
],
"aggregations": ["filter_cat", "brand"],
"referralUrl": "your-store.myshopify.com", // current url: window.location.href
"context": "searchPreview",
"customerId": "a7068b20-630c-4dc5-b6a7-2f16d3b68a74",
"sessionId": "4e742af1-691f-480b-9cf1-3becc2aac3a8"
}
Use customerId and sessionId from localStorage data.
"aggregations": list of facet field names from localStorage data
"context": searchPreview for search-as-you-type, serp for the search results page, collection for collection search
Sample response
{
"payload": {
"total_results": 124,
"results": [
{
"refId": "gid://shopify/Product/123",
"name": "Runner Pro",
"url": "/products/runner-pro"
}
],
"aggregations": {
"price_stats": {
"count": 10,
"min": 719,
"max": 1999,
"avg": 1050.5,
"sum": 10505
},
"brand": [
{
"key": "wahoo",
"doc_count": 7
},
{
"key": "elite",
"doc_count": 1
},
{
"key": "garmin",
"doc_count": 1
},
{
"key": "jetblack",
"doc_count": 1
}
]
}
}
}
Aggregations: aggregations in the response update your filter component.

mRoute API
Purpose: Load products (and related data) for a merchandising route configured in DiscoveryOS.
| Method | POST |
| URL | https://{shopDomain}/apps/discoveryos/mroute |
Sample payload
{
"route": "/collections/collection-handle",
"start": 0,
"size": 20,
"shop": "your-store.myshopify.com",
"scope": {}, // Similar as search API
"sort_fields": [], // Similar as search API
"selected_fields": [ // // Similar as search API
"refId",
"name",
"url",
"images",
"brand",
"prices"
]
}
Sample response
{
"payload": {
"total_results": 24,
"results": [
{
"refId": "gid://shopify/Product/456",
"name": "Trail Runner",
"url": "/products/trail-runner"
}
]
}
}
Recommendations API
Purpose: Load the recommendation route and widgets (slots, products, banners metadata) for the current page context.
| Method | GET |
| URL | https://{shopDomain}/apps/discoveryos/recommendations |
Query parameters
| Parameter | Required | Description |
|---|---|---|
currentUrl | Yes | Full URL of the page the shopper is on. Use the encoded page URL (for example encodeURIComponent(window.location.href) in JavaScript). |
expandProductDetails | Recommended | When true, product documents in the response include richer fields (attributes, variants, etc.). |
refId | On product pages | Shopify product numeric ID for the product being viewed (for example from Liquid product.id).Include this on product detail pages so recommendations can anchor on the current product. |
Example URL (product page)
Build currentUrl from the shopper’s real page URL (must be URL-encoded). Example pattern:
https://{shopDomain}/apps/discoveryos/recommendations?currentUrl=<encoded-full-page-url>&expandProductDetails=true&refId=<product-id>
On non-product pages, omit refId and still pass currentUrl so routing matches PLP, home, collection, etc.
Sample response (shape only)
The live payload is large. At a high level you receive a recommendations object whose route describes the matched route, the currentProduct (when applicable), and widgets — each widget has slots, and each slot lists products and banners (and campaign metadata used for tracking).
{
"recommendations": {
"route": {
"id": "7f960983-3740-f011-abf3-02bf4bf6447c",
"name": "PDP",
"currentProduct": {
"refId": "8728216993948",
"name": "Example product",
"url": "https://{shopDomain}/products/example-product",
"isInStock": true,
"brand": { "id": "6170085a-5e4a-433d-a273-dc7924d4a5da", "name": "Example Brand" },
"images": ["https://cdn.shopify.com/..."],
"prices": [{ "price": 17, "code": "AUD" }],
"attributes": []
},
"widgets": [
{
"id": "7b43001c-3740-f011-abf3-02bf4bf6447c",
"name": "PDP",
"widgetTitle": "Recommended to you",
"slots": [
{
"label": "Slot 1",
"tacticId": "46872308-1428-f111-abf3-02bf4bf6447c",
"campaignId": "9d054dab-1328-f111-abf3-02bf4bf6447c",
"products": [
{
"refId": "15109897027606",
"name": "Pink Bear",
"url": "https://{shopDomain}/products/pink-bear",
"isInStock": true,
"images": ["https://cdn.shopify.com/..."],
"prices": [{ "price": 100, "code": "EUR" }],
"attributes": []
}
],
"banners": []
}
]
}
]
}
}
}
Slots may also include fields such as recommenderId, adSetId, placementId, hmac, timeStamp, and similar values used for retail media / attribution; preserve them if you fire impression or click events as required by your PA integration.