Skip to main content

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.

note

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.

MethodPOST
URLhttps://{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"
}
note

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
}
]
}
}
}
note

Aggregations: aggregations in the response update your filter component.

Block settings — Select Widget

mRoute API

Purpose: Load products (and related data) for a merchandising route configured in DiscoveryOS.

MethodPOST
URLhttps://{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.

MethodGET
URLhttps://{shopDomain}/apps/discoveryos/recommendations

Query parameters

ParameterRequiredDescription
currentUrlYesFull URL of the page the shopper is on. Use the encoded page URL (for example encodeURIComponent(window.location.href) in JavaScript).
expandProductDetailsRecommendedWhen true, product documents in the response include richer fields (attributes, variants, etc.).
refIdOn product pagesShopify 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.