Skip to content
Elara One docs

Stores and API keys

How the API knows which store you mean, the public store key and server secret, registered websites, and how to rotate credentials safely.

Every request to the Elara One API is made on behalf of one store. This page covers how a store is identified, which credentials to send from a browser and from a server, and how to change them without taking your shop offline.

A store

A store is one shop or business on Elara One, such as Hearth & Oak. Each store has its own database: its catalogue, customers, orders, CRM records and settings live there and are never shared with another store. Search indexes, cache entries and media paths are kept apart per store too.

WhatWhere
API base URLhttps://api.elaraone.app/api/v1
Store admin{slug}.admin.elaraone.app
Keys, secret and websitesStore admin, Settings → Storefront API

The public store key

X-Tenant-Key identifies the store, and it is the only thing that does. Send it on every call.

  • Live store keys start with pk_live_. A staging store, where your plan includes one, has its own key starting with pk_test_.
  • The key is public in the same way a Stripe publishable key is: it can appear in browser code. On its own it only works from your registered websites (browser calls) or together with the server secret (server calls).
  • Find it under Store key in Settings → Storefront API.

A missing key returns 400 TENANT_KEY_MISSING. An unknown key, a suspended store and a rotated key whose overlap has ended all return the same 404 TENANT_NOT_FOUND. The API never echoes the key back.

The server secret

X-Tenant-Secret proves a call comes from your server. Send it on every server-to-server call, together with the store key.

Never put the secret in browser code

Anyone who visits the site can read browser code and call the API as your server. Keep the secret in a server-only environment variable, never under a prefix your framework copies into the browser bundle: NEXT_PUBLIC_* (Next.js), NUXT_PUBLIC_* and VITE_* (Nuxt and Vite), PUBLIC_* (Astro, SvelteKit), REACT_APP_* (Create React App).

The secret is shown in Settings → Storefront API. Revealing or rotating it asks for your admin password and authenticator code.

Browser calls and server calls

The API tells the two kinds of caller apart by the Origin header, which browsers add to cross-site requests.

Browser callServer call
How the API tellsThe request has an Origin headerThe request has no Origin header
Who makes itJavaScript on a web pageYour storefront server, a script, a job, an integration
Must carryX-Tenant-Key, from a registered websiteX-Tenant-Key and X-Tenant-Secret
GetsThe public tier onlyEverything the route allows, including per-shopper rate limits through X-Client-IP

The Origin check is not authentication. It stops other websites' JavaScript from using your key, but a program that is not a browser can send any Origin it likes. That is why a browser call only gets the public tier: X-Client-IP is ignored, and routes that need the secret (such as consent) refuse it whatever Origin it claims.

We recommend a backend-for-frontend: your storefront's own server calls the API, and the browser only talks to your server. All the starter storefronts work this way.

curl https://api.elaraone.app/api/v1/products \
  -H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
  -H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
  -H "X-Client-IP: 203.0.113.7"

Server-side fetch in Node.js does not add an Origin header, so your server's calls are server calls. Do not copy the incoming browser request's headers onto the API call wholesale: the browser's Origin would turn a server call into a browser call.

Register your websites

Browser calls are accepted only from the websites you register in Settings → Storefront API → Your websites. Each entry is an origin: scheme, host and, when it is not the default, port. No path.

You enterStored as
https://Shop.Example.com/https://shop.example.com
https://shop.example.com:443https://shop.example.com
https://shop.example.com:8443https://shop.example.com:8443
https://shop.example.com/productsRefused: no path, query string or fragment
http://shop.example.comRefused: https:// only
https://*.example.comA wildcard, on plans with wildcard website domains
  • A wildcard matches one or more labels below its base, never the bare domain itself. Register https://example.com separately if the shop runs there too.
  • How many websites you can register depends on your plan. The admin shows how many you have used.
  • Origin: null (a sandboxed iframe, a page opened from a file) counts as an unregistered website. So does a page served from localhost on a live store: develop against the API from your own server instead. Staging stores, where your plan includes them, accept http://localhost and http://127.0.0.1 on any port.
  • Registering a website never identifies a store; the key does. Two stores can register the same website.

CORS

  • Preflight (OPTIONS) requests are answered for any origin, because the store cannot be identified before the real request. They are cached for 600 seconds and never allow credentials (cookies). A successful preflight does not mean the call will be accepted.
  • The real response carries Access-Control-Allow-Origin set to your origin, never *, and every response carries Vary: Origin.
  • Your page's JavaScript can read these response headers: Idempotent-Replayed, Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id, X-Search-Id, X-Search-Total and X-Tenant-Key-Deprecated.

If your storefront calls the API only from its server, switch Browser calls off in Settings → Storefront API. Every call without the secret is then refused, with or without an Origin.

Report-only, then enforcing

A new store starts in report-only mode. Nothing is refused, but every call the lock would refuse is counted and shown in Settings → Storefront API → API lock, per website, with the first example of each kind (path, method, time and browser family). No header values or IP addresses are kept.

After 14 days the lock turns on by itself. The admin shows the date and counts down. You can choose Turn on the lock now earlier, and until the original date you can go Back to report-only.

Once the lock is on, the API answers:

Statuserror.codeWhenFix
403ORIGIN_NOT_ALLOWEDA browser call from a website you have not registeredRegister the website, or call from your server
403BROWSER_CALLS_DISABLEDA browser call while browser calls are switched offCall from your server with the secret, or switch browser calls back on
403TENANT_SECRET_REQUIREDA server call without X-Tenant-SecretSend the secret on every server call
403TENANT_SECRET_INVALIDA server call with the wrong secret, or a secret-only route called without itCopy the current secret from Settings → Storefront API

None of these is worth retrying: the same call gets the same answer until your integration or the store's settings change.

Before the lock date, check that:

  1. Every website the shop runs on is registered, including www. and any separate checkout or landing-page host.
  2. Every server that calls the API sends X-Tenant-Secret: the storefront server and any integration, scheduled job or feed generator.
  3. The report shows no calls without the secret and none from unregistered sites for the last few days.
  4. If the report shows no browser calls at all, switch Browser calls off.

Rotate the public key

Rotate the store key when it has been copied onto a site you do not control, or when an agency hands over. Go to Settings → Storefront API → Danger zone → Rotate store key. Rotating asks for your admin password and authenticator code.

  • The new key keeps the old one's prefix (pk_live_ or pk_test_) and is shown straight after the rotation.
  • The old key keeps working for 7 days. Responses to calls made with it carry X-Tenant-Key-Deprecated: true. Log this header in your integration so a forgotten deployment shows up.
  • End overlap now stops the old key at once, for a key that has leaked.
  • After the overlap, calls with the old key get 404 TENANT_NOT_FOUND.
  • Only one rotation runs at a time. Deploy the new key everywhere during the overlap.

Rotate the server secret

Rotate the secret when it may have leaked: it was seen in a browser, committed to a repository, or someone who knew it has left.

The change is immediate, with no overlap. Once the store is enforcing, calls with the old secret get 403 TENANT_SECRET_INVALID. To keep a locked shop working, rotate just before you deploy the new value to every server.

If a call ever carries both an Origin header and the secret, the secret has leaked to every visitor of that website. The API still serves the call, but the admin shows an urgent notice. Rotate the secret and move those calls to your server.