Skip to main content

Public endpoints

What public endpoints are for

The 9 public storefront endpoints power the Sumeru Systems storefront widgets (Theme App Extension) and any custom storefront integration. They're:

  • CORS-allowed for your shop's allow-listed domains
  • No authentication required for default storefront use
  • API-key authenticated for headless / custom storefronts
  • Rate-limited per shop to prevent abuse
  • Cached aggressively at edge for low-latency reads

Endpoint catalog

EndpointPurposeMethod
/api/public/reviewsRead reviews; submit new reviewGET, POST
/api/public/referralGenerate / validate referral codesGET, POST
/api/public/bundlesFetch bundle definitionsGET
/api/public/upsellGet cart upsell suggestionsGET
/api/public/quizSubmit quiz answers; get resultsPOST
/api/public/ab-experimentGet variant assignmentGET
/api/public/product-feedFetch product catalog (filtered)GET
/api/public/cart-nudgeGet personalized cart-page contentGET
/api/public/pixelPixel event ingestionPOST

Full OpenAPI spec at /developers/api/public-api/.

Auth model

Default: CORS allow-list

Each shop has a configured allow-list of domains (yourshop.com, www.yourshop.com). Requests from those origins succeed without explicit auth:

// From yourshop.com
fetch('https://api.sumeru.systems/api/public/reviews?product_id=prd_123', {
headers: { 'X-Shop-Domain': 'yourshop.com' }
})
.then(r => r.json())

API key (for headless / custom)

For storefronts not on standard Shopify domains:

X-Public-Key: pk_live_xY7aB3cKz9...

Public keys are scoped to public endpoints only — cannot access the admin API.

Caching

Read endpoints are cached at edge:

EndpointCache TTL
/reviews60s
/bundles5 min
/upsell60s
/product-feed5 min
/cart-nudge60s (per cart)
/ab-experimentper session, immutable

Cache busts on relevant admin updates. Headers include Cache-Control and X-Cache: HIT|MISS.

CORS configuration

Default allow:

  • Origin: any allow-listed domain
  • Methods: GET, POST, OPTIONS
  • Headers: Content-Type, X-Shop-Domain, X-Public-Key
  • Credentials: false (default; configurable)

Pre-flight (OPTIONS) responses cached at browser for 1h.

Rate limits

Public endpoints have higher limits than admin (storefront traffic patterns):

Endpoint patternPer shopPer IP
Read endpoints10K/min100/min
/pixel (event ingest)100K/min1K/min
/quiz, /referral1K/min20/min

When limited, 429 with Retry-After.

Abuse prevention

  • IP-level rate limits (above)
  • Bot detection on submit endpoints (review, quiz)
  • HMAC challenge for high-volume endpoints (/pixel)
  • Per-shop daily quotas (resets midnight UTC)

Common patterns

Embed reviews on PDP

<div id="reviews"></div>
<script>
fetch('/api/public/reviews?product_id={{product.id}}')
.then(r => r.json())
.then(data => {
document.getElementById('reviews').innerHTML =
data.data.map(r => `<div>${r.rating}${r.body}</div>`).join('');
});
</script>

Show cart upsell

async function loadUpsell(cartItems) {
const response = await fetch('/api/public/upsell', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ items: cartItems }),
});
const { data } = await response.json();
return data.suggestions;
}

Submit quiz

async function submitQuiz(answers, email) {
return fetch('/api/public/quiz', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ answers, email }),
}).then(r => r.json());
}

See also