Sellvik / developers
Concepts

CORS

Why the browser blocks your call, and the exact allowlist that fixes it.

The Sellvik API treats CORS as an auth boundary, not a cosmetic convenience. The rules below exist because letting them slip is a tenant-data leak risk; we will not loosen them.

Quick rules

  • Admin routes (/v1/admin/*) never set CORS headers. There is no browser-safe way to call them. If you need browser CRUD, build a thin proxy on your server.
  • Store routes (/v1/store/*) set CORS only when the request Origin exactly matches an entry in the shop's allowedOrigins list. No wildcards, no protocol coercion, no port stripping.

Configuring allowed origins

Panel → Settings → API keys → Allowed Origins.

Each entry is the literal scheme://host[:port] value the browser sends:

https://shop.example.com
https://www.shop.example.com
https://staging.shop.example.com
http://localhost:3000

Things that don't work:

  • shop.example.com — missing scheme.
  • https://*.example.com — no wildcards.
  • https://shop.example.com/ — trailing slash.
  • https://shop.example.com:443 — explicit port for the default port.

Preflight (OPTIONS)

For any non-simple request (anything sending JSON, custom headers, or using PATCH/DELETE), the browser sends a preflight OPTIONS first.

  • If the Origin is in your shop's allowlist: 204 No Content with the full CORS headers.
  • If not: 403 origin_not_allowed with a body explaining where to add the origin.

The 403 is intentional. A silent CORS drop is hard to debug; the explicit error surfaces a readable network response.

What headers are allowed

Allowed request headers on /v1/store/*:

  • Authorization (customer JWT)
  • Content-Type
  • X-Sellvik-Key
  • X-Sellvik-Cart

Allowed methods: GET, POST, PATCH, PUT, DELETE, OPTIONS.

Access-Control-Allow-Credentials: true is always set when the origin matches — so fetch(url, { credentials: "include" }) works for sites that need cookies.

Common failure modes

SymptomCause
CORS error: No 'Access-Control-Allow-Origin'Your origin isn't in the allowlist, or has a typo.
CORS error: credentials mode but origin is *Should be impossible — we never echo *. File a bug.
Request works in curl, fails in browserThis is CORS. Add the origin.
Adding origin doesn't take effectCached preflight (Access-Control-Max-Age: 600). Hard-reload or wait.
403 origin_not_allowed on preflightOrigin missing from allowlist; copy the exact string the browser shows.

Why no wildcards

Wildcards turn the allowlist from an auth control into a sanity check. A single CDN-hosted XSS on *.example.com would compromise every Sellvik shop that trusts that wildcard. Exact-match keeps the blast radius scoped to the explicit origins the merchant approved.

If you operate many subdomains and need to add them, list each one. If you have a lot, mail us; bulk-add tooling exists for the panel.

On this page