aov-bundle-upsell
🔌 Store API
Overview

Store API

A read-only REST API over this store's bundle data, for your own scripts, dashboards and integrations. Every endpoint a merchant token can reach is a GET, and each token belongs to one store.

If what you want is an AI assistant that answers questions about the store, you want MCP instead. This surface is for code you write.

Base URLhttps://avada-bundle-upsell.firebaseapp.com/public-api/shop/YOUR-STORE.myshopify.com
MethodsGET only
CredentialA token beginning aovmcp_
Sent asAuthorization: Bearer aovmcp_…
Rate limit60 requests per minute, per token

Copy the Public API base URL from the app rather than assembling the one above. It is shown in Settings → Integrations, on the Connect to AI and the API card, with your store's domain already filled in.

The same token as MCP

This is the one place this API differs from what you may expect: there is no separate API key. The token you create for an AI client is the same token you use here, and it grants exactly the same thing on both surfaces.

SurfaceFor
/mcpAI clients
/public-apiYour own scripts

Create one in Settings → Integrations — see Authentication. Revoking a connection stops both at once.

A connection created by signing in through an AI client works here too. There is nothing wrong with that, but you will not have the token — the client fetched it and kept it. For a script, create a token by hand.

Your first request

curl "https://avada-bundle-upsell.firebaseapp.com/public-api/shop/YOUR-STORE.myshopify.com/status" \
  -H "Authorization: Bearer aovmcp_YOUR_TOKEN"
const base =
  'https://avada-bundle-upsell.firebaseapp.com/public-api/shop/YOUR-STORE.myshopify.com';
 
const res = await fetch(`${base}/offers?status=active&limit=50`, {
  headers: {Authorization: 'Bearer aovmcp_YOUR_TOKEN'}
});
const {success, data, message} = await res.json();

The response shape

{"success": true, "data": { }}

On failure, success is false and message carries a human-readable reason:

{"success": false, "message": "This token is read-only"}
⚠️

Branch on success and the HTTP status, not on message. There are no stable machine-readable error codes on this surface — the message is written for a person reading a log and may be reworded. success === false plus the status is the contract; the wording is not.

This differs from the Store API in AOV.ai's other apps, which return an error.code. Do not port code that switches on one.

⚠️

success: true does not always mean the resource exists. GET /offer/:id for an unknown id answers 200 with success: true and data: undefined rather than a 404. Check that data is present before using it.

Read-only, enforced by method

The rule is the HTTP method itself: a merchant token is refused on anything that is not a GET, with 403 This token is read-only. There is no scope, no permission, and nothing you can be granted that lifts it — so a token in a script cannot create, change or delete an offer even by accident.

Never call this from a browser

The API sends permissive CORS headers, so a request from browser JavaScript will succeed. That is there for server-side tools and local development, not for your storefront.

⚠️

A token in browser code is a token you have published. Anything running in a shopper's browser is readable by that shopper; bundling or minifying changes nothing. Call this API from your server, and let the browser talk to your server.

If a token has ever shipped to a browser, revoke it in Settings → Integrations and create a new one. Removing the code does not un-publish what was already served.

Limits

Requests60 per minute, per token
Rate-limit headersX-RateLimit-Limit, X-RateLimit-Remaining on every response
Over the limit429, with Retry-After in seconds

Requests are counted before the token is resolved, so a flood of bad tokens is throttled too. The budget is per token, so one integration cannot spend another's — give each script its own.

Read X-RateLimit-Remaining rather than counting requests yourself. It is on every response, including successful ones.

What is never returned

  • No customer data. No names, emails, addresses, or individual orders. Analytics are aggregates over a date range.
  • No credentials. The Shopify access token and its hash are stripped from every response.
  • No support-session or contact fields. GET /status returns a fixed allowlist of fields, so a field added to the store record later does not start appearing here on its own.
  • No theme source. Reading theme files is not available to a merchant token.
  • No write access. Every non-GET request is refused.

Where next

  • Endpoints — everything a token can call
  • Errors — every refusal, and what to do about it
  • MCP tool guide — what the fields mean, in more depth
Product
Install AppWebsiteAvada Apps
Resources
DocumentationFAQPrivacy Policy
Company
Avada GroupContact
© 2026 Avada Group. All rights reserved.