- Exchanging a tap for a session token with
POST /v1/taps(a verify page with no backend of its own). - Introspecting or revoking a session token with
GET/DELETE /v1/session-tokens/current. - Reading a unit, or polling claim or transfer status, with a session token.
Allow-list your origins
Manage the list with your API key.PUT replaces it wholesale - send the complete list, not a delta.
Response
Response
GET /v1/settings/cors-origins returns the current list.
Changes take effect within about a minute. The allow-list is cached for 60
seconds, so a newly added origin may be rejected briefly after you save it.
Entry formats
Up to 50 entries, each at most 255 characters, with one wildcard per entry.
An origin is
scheme://host[:port] - no path, query, or fragment. Entries are stored in canonical form and returned as saved, so https://Brand.Example/ comes back as https://brand.example.
A subdomain wildcard needs at least two labels after the *: https://*.brand.example is accepted, https://*.com is not. The wildcard does not match the bare domain - allow-list https://brand.example separately if you serve from the apex.
What the API expects
Send theAuthorization header, with the default credentials mode. Do not set credentials: "include" - the API never returns Access-Control-Allow-Credentials, so the browser will block the response.
OPTIONS requests are handled for you; no configuration is needed.
@endstate-sdk/core sends requests this way already- it never sets
credentials, so a browser client works as long as the origin is allow-listed. The rawfetchabove is what the SDK does for you.
Reading response headers
Browser JS can read these cross-origin:X-Request-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After, Idempotent-Replayed.
Include X-Request-Id in any support request - it identifies the exact call in our logs.
When an origin is rejected
A request from an origin that is not on your list is rejected with403 and auth.forbidden before it reaches the endpoint.
The rejection is still CORS-decorated, which means your JavaScript can read the error envelope and show something useful instead of an opaque network failure. Echoing the origin on a rejection grants nothing - the request was already refused.
Authentication failures are decorated too, so a 401 from a missing or invalid credential is readable in the browser rather than opaque.
One case is not decorated, because there is no valid origin to echo: a malformed Origin, or one that resolves to null (file://, a sandboxed iframe, a data: URL). That surfaces as a generic network error.
If a call fails and you see nothing in the response, check the browser console for the CORS message, then confirm the exact origin - scheme, host, and port - is on the list.
Next steps
Publishable keys
The client-safe credential that identifies your organization.
Host your own verify page
Build the post-tap experience on your domain, with or without a backend.

