aov-cart-drawer-help-center
🔌 Store API
Overview

Store API

A REST API over this store's cart drawer data, for your own scripts, dashboards and integrations. Every response has the same shape, and each key belongs to one store.

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

Base URLhttps://aov-cart-drawer.firebaseapp.com/store-api/v1
MethodsGET, and POST / PUT / PATCH / DELETE with a write key
CredentialA key beginning aov_sk_
Sent asAuthorization: Bearer aov_sk_…
Rate limit60 requests per minute, per key — plus 20 writes per minute
RequiresA paid plan, re-checked on every request

Create a key

  1. In AOV.ai Cart Drawer, go to Settings, then the Store API tab.
  2. Copy the Base URL.
  3. Choose its access level. Read only is the default.
  4. Give the key a name — the integration it is for. 1–40 characters, and it has to be distinct from your other active keys.
  5. Click Create key.

The key is shown once, with a ready-to-run curl and Node example underneath.

⚠️

The key appears only at this moment. The server stores a fingerprint, not the key, so it cannot be shown again — not by you and not by support. Copy it into your secret store before closing the banner. If you lose it, revoke that key and create another.

Access levels

A key carries one of two levels, and it is enforced on every request.

LevelCan call
Read onlyThe 13 GET endpoints
Read and writeAlso the 34 endpoints that change the cart drawer's settings

A read-only key that calls a write endpoint is refused with READ_ONLY_CONNECTION (409) — a clear refusal rather than a 404 or 403, so an integration failing this way tells you which of the two problems it has.

⚠️

A write key changes the live cart drawer. A supported change is saved and then published to the storefront straight away, so shoppers see it. Give an integration the lowest level that does its job: a dashboard that only reads has no business holding a key that can edit the drawer.

Your first request

curl "https://aov-cart-drawer.firebaseapp.com/store-api/v1/setup-health" \
  -H "Authorization: Bearer aov_sk_YOUR_KEY"
const res = await fetch(
  'https://aov-cart-drawer.firebaseapp.com/store-api/v1/analytics?start=2026-08-01&end=2026-08-31',
  {headers: {Authorization: 'Bearer aov_sk_YOUR_KEY'}}
);
const {success, data, error} = await res.json();

Every response has the same shape

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

On failure, success is false and error carries a stable code and a message meant to be read by a person. data is null — except when a change was refused after being checked, in which case it carries the details:

{"success": false, "data": null, "error": {"code": "INVALID_INPUT", "message": "…"}}

Branch on error.code, not on the message. Codes are stable; wording is not. The HTTP status carries the same meaning, so a client that only checks the status is also correct. Both are listed in Errors.

This envelope holds even for failures that happen outside the router — a bad path, an unexpected server error. You will never get an HTML error page back, so your parser does not need a special case for one.

The API describes itself

GET /store-api/v1 returns the endpoint list, with each method, path, summary, and the query parameters it accepts. It is generated from the same table that builds the routes, so it cannot fall out of date with what actually exists.

It requires a key like everything else under the prefix, and it lists only the endpoints this key can use on this store — a read-only key does not see the write endpoints, and a store on the other cart drawer generation does not see the endpoints that belong to the other one (see Two cart drawer generations).

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 key in browser code is a key you have published. Anything running in a shopper's browser is readable by that shopper — bundling, minifying, or obfuscating changes nothing. Call this API from your server, and let the browser talk to your server.

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

Keys are per surface

Cart Drawer issues two kinds of key and they are not interchangeable:

PrefixSurfaceFor
aov_sk_/store-api/v1This API
aov_mcp_/mcpAI clients — see MCP

Present an aov_mcp_ key here and the response says so by name — WRONG_SURFACE — rather than reporting it invalid, because the fix is to mint the right kind of key, not to hunt for a typo. Revoking one surface never affects the other.

Losing the plan revokes your keys

Every other refusal on this API is temporary: fix the cause and the same key resumes working. Loss of the paid plan is not.

⚠️

When a request arrives from a store that is no longer on a paid plan, the response is NO_PLAN and that store's Store API keys are revoked. Upgrading does not bring them back — you create new keys and update your integration with them.

This is deliberate. Billing changes do not all pass through this app, so the first refused request is the reliable moment to act on one; and keys left dormant would otherwise all wake up together on the day a store is reinstated, with nobody having decided that they should.

Uninstalling the app also retires the store's keys.

MCP connections behave differently. When the plan lapses, an AI connection is refused with NO_PLAN but not revoked, and it works again after you upgrade.

Changing settings safely

Write endpoints take a JSON body and change what shoppers see, so three habits are worth having.

  • Read first. GET /drawer-settings returns the saved configuration together with its revision. Decide your change from that, not from memory.
  • Send expectedRevision. Pass the revision you read, so a change saved in the meantime is refused instead of overwriting someone else's work. What to do then is under A stale revision.
  • Send a requestId you can repeat. It identifies one intended change, so a retry does not apply it twice. The rules are under requestId reuse.

Both fields, and what a committed write returns, are on Endpoints.

Limits

Requests60 per minute, per key
Write requests20 per minute, per key — counted on top of the 60
Concurrent writesOne at a time per store; a second write that arrives mid-save is refused
Page sizepageSize 1–50 on every paged read
Analytics window/analytics covers at most 400 days, in the store's own timezone

A rate limit is counted per key, so one integration cannot exhaust another's budget. Requests are counted before the key is even resolved, which means a flood of bad keys is throttled too.

What is never returned

  • No customer data and no credentials. The same guarantees as MCP: see What it never returns.
  • No internal ids. The store's internal record id and the key's own fingerprint are stripped before anything leaves the server.
  • No plan changes. Nothing on this surface alters billing, and no endpoint quotes a price.

Where next

  • Endpoints — all forty-seven, with their parameters and access levels
  • Errors — every code, what causes it, what to do
  • MCP tool guide — the meaning of the fields each endpoint returns
Product
Install AppWebsiteAvada Apps
Resources
DocumentationFAQPrivacy Policy
Company
Avada GroupContact
© 2026 Avada Group. All rights reserved.