Skip to main content

CORS & origin validation

Neuroon validates each request's Origin differently depending on the endpoint and the credential type. This page is the single source of truth: if any other doc disagrees, this matrix wins.

Canonical matrix

EndpointAuthAccepts missing Origin (server-to-server)Origin must matchHow to add a domain
POST /api/plugin/shops/{shopId}/products/syncX-Shop-API-Key✅ Yesn/a — only that the API Key belongs to the shop.n/a
GET /api/plugin/shops/{shopId}/productsX-Shop-API-Key✅ Yesn/an/a
POST /api/plugin/shops/{shopId}/track/conversionX-Shop-API-Key✅ Yesn/an/a
POST /api/plugin/shops/{shopId}/verifyX-Shop-API-Key✅ YesBody domain is compared to shop.url.Edit shop.url in the dashboard.
GET /api/plugin/shops/{shopId}/verification-dataX-Shop-API-Key✅ Yesn/an/a
POST /api/shops/{id}/widget-tokenX-Shop-API-Key✅ Yesn/an/a
GET / POST /api/widget/search, /suggestions, /trending, /compare, /cart/cross-sellX-Widget-Token✅ Yes (browsers always send Origin)app.widget.allowed-originsshop.url (when Origin is present, it must match)Ask support to add the domain to allowed-origins.
POST /api/widget/search/audio, /visualX-Widget-Token✅ YesSame as aboveSame as above
POST /api/widget/track/click, /track/conversionX-Widget-Token✅ YesSame as aboveSame as above
POST /api/widget/analytics/event(s)X-Widget-Token✅ YesSame as aboveSame as above
POST /api/webhooks/stripeStripe-Signature✅ Yes (Stripe → us)n/an/a

The WidgetTokenValidator.validateOrigin method accepts a missing or blank Origin (early-return at WidgetTokenValidator.java:60-63). Only when an Origin is present does it check it against app.widget.allowed-origins ∪ shop.url. This makes the widget endpoints curl/server-to-server friendly, even though browsers always send Origin.

POST /api/tokens/refresh is intentionally not in this table — it is not part of the widget/plugin contract. It refreshes user JWTs for the Neuroon dashboard (TokenController.java:36).

Defaults of app.widget.allowed-origins

Default values (application.yml:273-276):

  • localhost and 127.0.0.1 (suffix-match: any subdomain or port).
  • neuroon.ai (suffix-match: includes *.neuroon.ai, e.g. dev.neuroon.ai, cdn.neuroon.ai).
  • The shop.url registered in the dashboard.

Adding a new domain

  1. For your primary domain: edit it from the dashboard → your shop → Settings → Storefront URL. The change applies to the next request served.
  2. For extra domains (staging, branches, marketing domains sharing the widget): open a support ticket with the shopId and the domains. The list lives in backend config (app.widget.allowed-origins).

Self-service for extra domains is on the roadmap. Until then, the dashboard only edits shop.url (a single value).

Common errors

SymptomCauseFix
Browser blocks XHR with CORS error and console shows 403The widget is running on a domain that is neither in allowed-origins nor matches shop.url.Check shop.url or ask to add the domain to allowed-origins.
403 DOMAIN_MISMATCH when calling /verifyThe url in the body does not match shop.url.Edit shop.url in the dashboard and retry.
401 when serving the widget from the browserToken expired, not present in the HTML, or environment mixup (DEV token against api.neuroon.ai).Refresh the token and double-check the base URL.

Further reading