# Storefront API Access

# Introduction

Nimstrata's Storefront API allows merchants with composable commerce solutions to send events, retrieve search results and recommendations, and request autocomplete suggestions.

If you're using Hydrogen, Oxygen, or another custom headless storefront solution, you can call Nimstrata and Shopify's APIs directly.

📖 Nimstrata's Storefront API Documentation
https://storefront.retailconnect.app/docs
📖 Shopify's Storefront API Documentation
https://shopify.dev/docs/api/storefront


# Rate Limits

Shopify and Nimstrata's Storefront APIs handle businesses ranging from tens to millions of SKUs, so there are no explicit rate limits on the number of requests that can be sent. However, various malicious user prevention systems are in place and you may receive 430 Shopify Security Rejection or 429 (Too Many Requests) error codes.

To avoid being rate limited, ensure your solution uses the correct Buyer IP Header when calling Shopify’s Storefront API, Nimstrata’s Storefront API uses the End User’s IP Address.


# Endpoints

# Retail API - Vertex AI Search for Commerce

# User Events

https://storefront.retailconnect.app/v1/event

If you'd like to send User Events to our Storefront API in addition to (or instead of) our Shopify App Pixel and App Embed, there are some special requirements for search events. This is a common use case to facilitate faster AI model training or to leverage the Experiments tab in the Google Cloud Console for additional AB test data.

Because Vertex AI Search for Commerce uses a single API to serve search and browse events, "Browse" events are technically "Search" events without a search query. However, you must send at least one Page Cateogry and Filter for them to be processed correctly. Please see the examples below.

System Attributes and Custom Attributes used for filtering results should be sent to improve Dynamic Facet training.

# User Event Examples

{
  "projectName": "your-gcp-project-name",
  "userEvent": {
    "eventType": "search",
    "visitorId": "00000000-0000-0000-0000-000000000000", // rcc-visitor-id cookie value
    "searchQuery": "search term",
    "offset": 0, // Used for pagination
    "filter": [
      {
        "field": "attributes.custom_filter",
        "value": ["Filter Value"],
        "type": "string"
      }
    ],
    "productDetails": [ // Send all products, example shortened for brevity
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } }
    ],
    "userInfo": {
      "userAgent": "User Agent",
      "userId": "00000" // Shopify Customer ID if Logged In
    },
    "experimentIds": ["CONTROL"]
  }
}
{
  "projectName": "your-gcp-project-name",
  "userEvent": {
    "eventType": "search",
    "visitorId": "00000000-0000-0000-0000-000000000000", // rcc-visitor-id cookie value
    "searchQuery": "",
    "offset": 0, // Used for pagination
    "filter": [
      { "field": "attributes.rcc_collection_id", "value": ["123456789012"] }, // attributes.rcc_collection_id or Shopify Collection ID
      {
        "field": "attributes.custom_filter",
        "value": ["Filter Value"],
        "type": "string"
      }
    ],
    "pageCategories": ["123456789012"], // attributes.rcc_collection_id or Shopify Collection ID
    "productDetails": [ // Send all products, example shortened for brevity
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } }
    ],
    "userInfo": {
      "userAgent": "User Agent",
      "userId": "00000" // Shopify Customer ID if Logged In
    },
    "experimentIds": ["CONTROL"]
  }
}
function createUUID() {
  const s = [];
  const hexDigits = '0123456789abcdef';
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  s[14] = '4';
  s[19] = hexDigits.substr((s[19].charCodeAt(0) & 0x3) | 0x8, 1);
  s[8] = s[13] = s[18] = s[23] = '-';
  return s.join('');
}

async function getVisitorId(browser) {
  let ID = await browser.cookie.get('rcc-visitor-id');

  if (ID) return ID;

  ID = createUUID();
  browser.cookie.set('rcc-visitor-id', ID);

  return ID;
}