# Publishable Keys & CORS

BasketBooster uses two kinds of credentials. Knowing which goes where keeps
your store secure with zero friction for shoppers.

## Publishable key (`pk_...`)

- **Public by design** — it ships in your storefront HTML, exactly like a
  Stripe publishable key. It can only *read* widget content and *send* shopper
  events for your account; it cannot touch your catalog, settings, or billing.
- Every account has one, auto-created at registration. Find it on the
  dashboard's *Recommender → Widget snippet* page.
- Sent as the `?key=` query parameter (what the widgets do) or the `X-Pub-Key`
  header.

```
GET /v1/recommendations?key=pk_...&item_id=123
```

## Secret API key

- **Server-side only.** Full write access to your catalog and integration
  settings (`POST /v1/items`, `/integration/*`, `/orders/upload`) via the
  `X-API-Key` header.
- Create it on the dashboard's *API Keys* page. It is **shown once** at
  creation — store it in your server's environment/secrets manager.
- Never put it in a browser, mobile app, or public repository. If it leaks,
  revoke it on the *API Keys* page and create a new one.

## CORS and the origin allowlist

The widget API is designed to be called straight from shoppers' browsers on
your domain, so it is CORS-open and **preflight-free** (parameters travel in
the query string; event posts use a CORS-safelisted content type — no extra
round-trips, no latency).

Which origins may use your publishable key is controlled by the key's
**allowed origins** list:

- **Empty list (default)**: any origin works. Fine for getting started — the
  key can only read your public product recommendations anyway.
- **With entries**: browsers on listed origins get proper CORS responses;
  requests from other origins are refused by the browser. Recommended once
  you're live, to stop others from embedding your widget (and spending your
  request quota) on their sites.

Rules of thumb when filling the allowlist:

- Enter full origins: `https://your-store.com`.
- `https://www.your-store.com` and `https://your-store.com` are **different
  origins** — list both if both serve your store.
- Add your staging domain if you test there.
- Scheme matters: an `https://` entry does not cover `http://`.

## HTTPS

An HTTPS store must call the HTTPS API base (`https://api.basketbooster.eu`) —
browsers block plain-`http` requests from `https` pages ("mixed content").

## Shopper privacy

Anonymous shoppers are identified by a random session id stored in
`localStorage` — no cookies, no cross-site tracking. If you pass
`data-user-id`/`data-customer-id`, use your own internal customer id, not an
email address.
