Skip to content

Keys and CORS

Public and secret storefront keys, registered origins and CORS behaviour.

You get two keys per storefront, both requested from Unipage. Together they are one storefront, with a name, its registered origins and optionally an order webhook. The public key’s origins are where your shoppers may browse from and return to after paying. The restaurant is resolved from the key: there is no restaurant id in the URL.

Public key Secret key
Looks like upg_sf_pk_... upg_sf_sk_...
Where it lives in your browser bundle, safe to expose only on your server, never in a browser
Sent as X-Unipage-Key: <key> header Authorization: Bearer <key> header
Grants the read and quote routes every route, including orders
Bound to the origins you registered (https://shop.example.com) nothing: server-to-server only
const res = await fetch("https://api.unipage.eu/storefront/v1/menu?orderType=TAKEOUT", {
  headers: { "X-Unipage-Key": import.meta.env.VITE_UNIPAGE_PUBLIC_KEY },
});
curl https://api.unipage.eu/storefront/v1/orders/q4m8z \
  -H "Authorization: Bearer $UNIPAGE_SECRET_KEY"

A Core API key (upg_capi_..., the restaurant’s own back-office key) is also accepted where the secret key is, but give a storefront its own keys.

Requesting keys

When you request keys, give every origin your shop is served from (scheme://host[:port], no path, no trailing slash).

Local development needs no registration: every public key also accepts localhost, 127.0.0.1 and [::1] on any port, over http or https. A storefront on your machine that uses production keys places real orders, so test against a test restaurant.

Origins can be changed later without a new key: the public key stays the same, so your storefront needs no new build.

Rotating a key

If a key leaks, ask Unipage to rotate it. Each key is rotated on its own: the old one stops working at once and the new one is shown to you once.

  • Secret key: only your server needs the new key.
  • Public key: it keeps its origins and webhook, but it is in your browser bundle, so rebuild and deploy your storefront with the new one.

Authentication errors

  • A missing, unknown or revoked key answers 401 UNAUTHENTICATED.
  • A public key on a secret route, or used from an origin that is not registered for it (and is not local), answers 403 FORBIDDEN.
  • A request without an Origin header (curl, a server) is accepted with a public key: the origin list restricts browsers, the key identifies you.

CORS

A browser preflight (OPTIONS) is answered 204 for a registered or local origin, with:

Access-Control-Allow-Headers: X-Unipage-Key, Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Max-Age: 600

Every response (errors and 429 included) carries Vary: Origin and, for a registered or local origin:

Access-Control-Allow-Origin: <origin>
Access-Control-Expose-Headers: Retry-After

The secret routes send no CORS headers for a browser: call them from your server.

Type to search…

↑↓ navigate↵ selectEsc close