Skip to main content

Auth & scopes

Every call to the Kaleidr platform API carries one credential. There are three kinds, and the API treats each differently:

  • A publishable key identifies your organization in a browser. It cannot call the API by itself; it is exchanged for a session.
  • A session token is what a browser actually calls the API with. It is short-lived and bound to one website origin and one product.
  • A server key is a secret your backend sends directly on each request.

This page covers how each is sent, what the exchange looks like, what scopes unlock, how the vendor scope is granted, and every authentication error with its cause and fix. For what each credential can do if it leaks, see the security model.

Credential types​

CredentialPrefixWhere it livesHow it is usedPlan
Publishable keykld_pk_live_…Page sourceSent once to the session exchange; refused on every other endpointFree, Pro, Enterprise
Session tokenkld_sess_live_…Browser memorySent on every runtime call from the page it was minted forMinted from a publishable key or a published map
Server keykld_sk_live_…Your backend onlySent on every runtime call; refused when the request carries an Origin headerPro, Enterprise
Legacy keykld_live_…Your backendWorks as a direct credential, like a server key. Rotating one produces a server keyExisting keys only

Keys minted through the key management API with environment: "test" carry test in place of live (kld_pk_test_…, kld_sk_test_…). A test key cannot load basemap tiles.

A key is shown in full exactly once, when it is created or rotated. Kaleidr stores only a hash, so a lost key cannot be recovered: rotate it.

Sending a credential​

Send the credential in either header. Both are accepted on every endpoint.

Authorization: Bearer kld_sk_live_…
X-Api-Key: kld_sk_live_…

If a request carries both, Authorization is used when its value starts with a Kaleidr prefix; otherwise X-Api-Key is read. Never put a server key in a URL.

What each credential may do on a runtime endpoint (everything except the session exchange):

CredentialResult on a runtime endpoint
Publishable key401 publishable_requires_session. Exchange it first.
Server key, no Origin headerAccepted, then checked for IP allowlist, scope, allowed products, quota and rate limit.
Server key with an Origin header403 server_key_in_browser. Browsers add Origin to cross-site requests, so this is how the API recognizes a server key in a web page.
Session token from the origin it was minted forAccepted.
Session token with a different Origin403 session_origin_mismatch.
Session token from a published map with no Origin403 session_origin_mismatch.

The JavaScript SDK enforces the same rule earlier: Kaleidr.mount refuses a kld_sk_… key in the browser without making a request.

Session exchange​

A publishable key is traded for a session token at one endpoint. The SDK does this for every keyed mount and keeps the token fresh; you only call it yourself when you build your own browser client.

POST https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions
X-Api-Key: kld_pk_live_…
Content-Type: application/json

{ "product": "chat" }

product is required and is one of chat, editor, viewer or tile. The request must carry an Origin header. A browser adds it for you.

{
"session_token": "kld_sess_live_eyJhbGciOi…",
"expires_in": 900,
"product": "chat",
"basemap_style_id": null
}
FieldMeaning
session_tokenThe credential for runtime calls. Format kld_sess_{env}_{token}.
expires_inLifetime in seconds. A keyed session lasts 900 seconds. Read this field; do not hard-code the number.
productThe product the session is bound to.
basemap_style_idYour organization's default basemap, or null when none is set.

What a session is bound to​

  • One origin. The Origin of the exchange request. A call from any other origin is refused.
  • One product. A tile session cannot call chat endpoints.
  • A narrowed set of scopes. The session carries only the scope its product needs: ai for chat, design for editor, maps for tile, none for viewer. A chat session also keeps vendor when the key holds it and your plan admits it (Enterprise). No other product's session ever carries vendor.

Refreshing​

A client cannot ask for a longer lifetime. Exchange again before expires_in runs out. The SDK refreshes 90 seconds before expiry, when a background tab becomes visible with the session within 90 seconds of expiry or past it, and every 30 seconds after a failed refresh. If the very first exchange fails, the mount fails and is not retried.

Each exchange for product: "tile" uses one map load from your organization's allowance; other products cost nothing to exchange. The exchange has its own rate limit per key, separate from runtime calls. See Quota and rate limits.

Order of checks​

The exchange stops at the first check that fails:

OrderCheckFailure
1The key is valid401 Invalid or missing API key
2The key's exchange rate limit429 rate_limited
3The key is a publishable key403 publishable_key_required
4The request has an Origin header403 origin_required
5The origin is in the key's allowed origins, if the key has any403 origin_not_allowed
6The key is not restricted away from this product403 product_not_allowed
7Your plan includes the product403 tier_capability_not_allowed
8The key holds the scope the product needs403 insufficient_scope, or tier_capability_not_allowed if the key holds it but your plan no longer includes it
9For tile: a map load is available429 map_load_quota_exceeded

Trying it from a terminal​

curl -s https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions \
-H "X-Api-Key: kld_pk_live_…" \
-H "Origin: https://www.example.com" \
-H "Content-Type: application/json" \
-d '{"product":"chat"}'

This works because Origin is an ordinary header that any non-browser client can set. That is the reason the allowed-origins list is described as a browser control and not as a secret: see CORS and allowed origins.

Sessions for a published map​

A map published from Studio whose Kaleidr AI tile turns on Control Tower or Popup Window can provide chat to its visitors with no key in the page. The page exchanges the map's public id, and the feature it opens, instead:

POST https://api.kaleidr.com/inference-api/b2b/v1/sdk/share-sessions
Content-Type: application/json

{ "share_id": "your-map-id", "feature": "control_tower" }
{ "session_token": "kld_sess_live_eyJhbGciOi…", "expires_in": 300, "product": "chat" }

This session is chat only, carries the ai scope, lasts 300 seconds, and is charged to the map owner's organization. It never carries vendor. It must be used from the page that requested it: a call with no Origin, or a different one, is refused. The refusals are:

StatusCodeCause
403origin_requiredThe request has no Origin header.
404not_foundNo published map or share link has this id, or the share link's map is unpublished.
403chat_disabledThe map's Kaleidr AI does not turn on the feature asked for.
403origin_not_allowedThe page is not in the map's allowed domains.
403owner_has_no_organizationThe map's owner has no organization to charge.
403tier_capability_not_allowedThe owner's plan does not include chat.
429rate_limitedToo many exchanges for this map or from this address.

Setting it up is covered in Kaleidr AI on a published map.

Scopes​

A key carries scopes. Each endpoint family needs one.

ScopeUnlocksNeeded by
ai/chat/* and /retrieval/* endpointsChat, and any backend that calls the chat or lookup endpoints
design/design/* endpointsEditor sessions, and any backend that calls the design endpoints
mapsBasemap sessionsTile
vendorNothing by itself. It lets chat answers draw on your organization's own published data.Chat, when you have uploaded data

A new key gets ai, maps and design unless you ask for something else. On the Free plan a key always carries the whole Free surface: exactly those three scopes, and all four products (chat, editor, viewer, tile), whichever of them the request names. vendor is never a default, and only an Enterprise organization can create a key that carries it.

A request to create a key that names a scope or a product your plan does not admit is refused with 403 tier_capability_not_allowed. Nothing is dropped from a request without an error. In practice that is a request for vendor on Free or Pro.

Scopes are fixed when the key is created. No endpoint and no setting edits them afterward, and a rotated key inherits them, minus any scope your current plan no longer admits. To change a key's scopes, create a new key and revoke the old one.

Rotation on Free follows the Free rule. On the Free plan the replacement of a rotated publishable key carries the whole Free surface (ai, maps, design, and all four products), whatever the old key held. A server key or a legacy key cannot be rotated on Free: the request is refused with 403 free_plan_publishable_only.

What a key can do is the smaller of the key and the plan​

Every request checks the key's stored scopes and products against what your organization's plan includes today. Changing plan never edits a key, but it does change what the key can do:

  • insufficient_scope: the key was never given the scope. Fix: use a key that has it.
  • tier_capability_not_allowed: the key has it, but your current plan does not include it. Fix: change plan.

vendor is the exception to the second line, because it opens no endpoint. A key that stores vendor on a plan below Enterprise is not refused: its requests succeed, and its answers are built without your data.

A key with an empty product list is allowed every product your plan includes. A key with no scopes is refused everywhere.

A product limit applies to every key​

allowed_products limits a key to some of chat, editor, viewer and tile. The limit is enforced for every key type, at the point where that key is used:

KeyWhere the limit is checkedRefusal
Publishable keyAt the session exchange, against the product requested403 product_not_allowed
Server key or legacy keyOn every runtime request, against the product the endpoint belongs to403 product_not_allowed

Each endpoint family belongs to the product whose scope it needs:

EndpointsScopeProduct a limited key must allow
/chat/*, /retrieval/*aichat
/design/*designeditor

So a server key created with "allowed_products": ["tile"] is refused on /chat/control/stream with 403 product_not_allowed, even though it carries the ai scope. A server key limited to viewer alone can call no runtime endpoint, because a published map needs no key. Leave the list empty when a key should reach every endpoint its scopes allow.

A session token is not checked again here: it was bound to its one product when it was exchanged.

FreeProEnterprise
Publishable keysYesYesYes
Server keysNoYesYes
ai, maps, designYesYesYes
vendorNoNoYes

Pro adds server keys and a higher limit on active keys to what Free admits. The full plan table lives in Get an API key.

The vendor scope​

vendor does not open an endpoint. It decides whether a chat answer made with this key may draw on your organization's own published data, alongside Kaleidr's general knowledge. The whole path, from upload to answer, is in Your data: overview.

Who can use it:

  • Free and Pro cannot hold vendor. A request to create a key with it is refused with 403 tier_capability_not_allowed, whether or not vendor_acknowledged is sent. No key is created.
  • Enterprise can create vendor keys.

The scope is about reading the data through a key. Uploading the data is a separate permission, held by an owner or admin of the organization and not by any key, and it is Enterprise only as well: Free and Pro cannot upload business data. The files a signed-in user adds to a map in Kaleidr Studio are a different feature, available on every plan, and no scope reads them: see Datasets on a map.

The API Keys page cannot grant vendor. Create the key through the key management API:

curl -s https://api.kaleidr.com/shared-api/api-keys \
-H "Authorization: Bearer $KALEIDR_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "store-locator-chat",
"key_type": "publishable",
"scopes": ["ai", "vendor"],
"vendor_acknowledged": true,
"allowed_origins": ["https://www.example.com"]
}'

vendor_acknowledged: true is required for a publishable key that carries vendor. Without it the request fails with 422 vendor_scope_requires_acknowledgement. The field exists because a publishable key sits in public page source, so data that key can read is readable by anyone who visits the page. A server key needs no acknowledgement.

Before you put vendor on a publishable key:

  • Use one key per website. Only the site that must answer from your data gets vendor.
  • Treat everything in your published data as public on that site. Do not publish cost prices, unreleased rates or anything you would not print on the page.
  • Remember that sessions already in flight do not gain the scope. A key created with vendor gives it to sessions exchanged from then on.

To withdraw vendor, revoke the key and create a replacement without it. Revoking takes effect on the next request, including for sessions already issued.

When an organization leaves Enterprise​

A move from Enterprise to Pro or Free does not edit your keys, and it does not make them fail:

WhatAfter the move
A key that carries vendorKeeps working for everything else. Its answers no longer draw on your data. No error, status or field says so.
Browser sessions issued before the moveEnded. Their next request returns 401, and the SDK obtains a new session, which does not carry vendor.
Rotating a key that carries vendorOn Pro: succeeds with 201. The replacement has the same scopes without vendor; its product list is unchanged. On Free: a publishable key's replacement carries ai, maps, design and all four products, whatever the old key held, and rotating a server or legacy key is refused with 403 free_plan_publishable_only.
Creating a key with vendorRefused with 403 tier_capability_not_allowed.
Your releasesOwners and admins can still list them, and can unpublish and delete them, on any plan, with the upload API. On Free and Pro, uploading and publishing are refused with 403 vendor_data_not_on_plan.

On a return to Enterprise, a key that still stores vendor reaches the data again. A replacement rotated on the lower plan does not regain the scope: create a new key.

Restricting a key​

RestrictionApplies toSet on the API Keys pageSet through the key management APIRefusal
Allowed originsPublishable keysYesYes (allowed_origins)403 origin_not_allowed at the exchange
Allowed productsAny keyNoYes (allowed_products)403 product_not_allowed: at the exchange for a publishable key, on each runtime request for a server or legacy key. See product limits.
IP allowlistServer and legacy keysNoYes (allowed_ips)403 ip_not_allowed
Monthly capAny keyNoYes (monthly_cap_tokens)429 quota_exceeded
ExpiryAny keyNoYes (expires_at)401 after the date
ScopesAny keyNoAt creation only (scopes)403 insufficient_scope

Allowed origins. Up to 100 entries, each scheme://host[:port] with no path. An empty list on a publishable key means any origin. Details and failure modes are in CORS and allowed origins.

IP allowlist. Up to 100 IP addresses or CIDR blocks. A block that matches every address (/0) is refused: leave the list empty to mean "any address". When a key has a list and the caller's address cannot be established, the request is refused.

Monthly cap. A ceiling on what this one key may spend from your organization's AI credits in a billing period. See Quota and rate limits.

What reaches a session that is already issued​

A session re-reads its parent key on every request, so removing access is fast. Adding access needs a new exchange.

Change to the key or accountEffect on a session already issued
Key revoked, or rotated with no grace period401 on its next request.
The session's origin removed from the key's allowed origins401 on its next request.
The session's product removed from the key's allowed products401 on its next request.
Plan downgradedSessions issued before the downgrade get 401. Sessions exchanged afterward get 403 tier_capability_not_allowed for what the plan no longer includes.
Monthly cap added or loweredApplies on the next request.
Monthly cap removedApplies from the next exchange.
Plan upgradedApplies from the next exchange.

Because a session lasts minutes, "from the next exchange" is a short wait. The SDK's refresh picks it up with no code change.

Key management API​

The API Keys page at kaleidr.com/api-keys sets a key's name, its type and its allowed origins. Everything else on this page is set through the same API that page uses.

  • Base URL: https://api.kaleidr.com/shared-api/api-keys
  • Authentication: Authorization: Bearer with the access token of a signed-in Kaleidr account that is an owner or admin of the organization. A platform key is not accepted here. There is no separate long-lived credential for key management today.
  • Organization: without an organization named, your primary organization is used. To name another, send org_id in the JSON body when you create a key, and as the ?org_id= query parameter on every other route. A query org_id on the create route is ignored.
Method and pathPurposeSuccess
POST /Create a key201, the key object plus plaintext_key
GET /List active keys, newest first200
GET /{id}/events?limit=1..200A key's audit events200
PATCH /{id}Change restrictions200, the key object
POST /{id}/rotateReplace the key201, the new key plus plaintext_key
POST /{id}/revokeRevoke the key200, the key object

There is no delete route: revoke a key to retire it.

Fields accepted when creating a key:

FieldTypeDefaultNotes
namestring, 1 to 200 charactersrequired
org_idUUIDyour primary organizationThe organization the key is created in. Sent in the body: a query parameter is ignored on this route.
key_type"publishable" or "server""publishable""server" is refused on Free with 403 free_plan_publishable_only.
environment"live" or "test""live"
scopesstring array["ai", "maps", "design"]From ai, maps, design, vendor. Anything else is 422 unknown_scope. A scope your plan does not admit (vendor below Enterprise) is 403 tier_capability_not_allowed.
allowed_originsstring array, up to 100[]Empty means any origin, for a publishable key.
allowed_productsstring array[]From chat, editor, viewer, tile. Empty means all. Anything else is 422 unknown_product. Enforced for publishable, server and legacy keys: see product limits.
allowed_ipsstring array, up to 100[]IP addresses or CIDR blocks.
monthly_cap_tokensinteger, 0 or morenone1 or more caps the key. 0 or null means no cap.
expires_atdate and time in the futurenone
vendor_acknowledgedbooleanfalseRequired for a publishable key with vendor (Enterprise).

PATCH accepts name, allowed_origins, allowed_products, allowed_ips, monthly_cap_tokens and expires_at. Send only the fields you want to change; an explicit null clears a value. It does not accept scopes.

rotate accepts { "grace_hours": 0 }, from 0 to 8760. The replacement inherits the old key's scopes, except a scope your current plan no longer admits, which is left off. On Free the replacement always carries the whole Free surface, and a server or legacy key cannot be rotated (403 free_plan_publishable_only). With 0, the old key and its sessions stop working at once. With a grace period, the old key keeps working until the period ends, still counts toward your plan's limit on active keys, and cannot be rotated again. The API Keys page rotates with a 24-hour grace period.

Errors from these routes are listed in Errors: key management.

Authentication errors​

A 401 means the API does not accept the credential at all. A 403 means it knows who you are and the answer is no. Every one has the shape {"detail": "<code>"}.

In a browser, a request refused for its credential or origin carries no CORS header, so the page sees a CORS error instead of the body. A request refused later, for scope or plan, is readable, and the SDK reports kaleidr session exchange failed (403). In both cases, open the request in the browser's Network tab to read the code. See CORS and allowed origins.

StatusCodeCauseFix
401Invalid or missing API keyNo credential; an unknown, revoked or expired key; an expired session; a session whose key was revoked, lost this origin or product, or was issued before a plan downgrade; an organization that is suspended or has no plan.Check the key value and its status on the API Keys page. For a session, exchange again.
401publishable_requires_sessionA publishable key was sent to a runtime endpoint.Exchange it for a session, or call from a backend with a server key.
403publishable_key_requiredThe session exchange was called with a server or legacy key.Use a kld_pk_… key at the exchange.
403origin_requiredA session exchange with no Origin header.Call it from a browser page.
403origin_not_allowedThe page's origin is not in the key's allowed origins, or not in the published map's allowed domains.Add the exact origin to the key, or the domain to the map.
403product_not_allowedThe key's allowed products exclude this product: the product requested at the session exchange, or, for a server or legacy key, the product the called endpoint belongs to.Change allowed_products, or use another key.
403insufficient_scopeThe key was created without the scope this endpoint or product needs.Use a key that has the scope. Scopes cannot be edited.
403tier_capability_not_allowedThe key has the scope or product, but your current plan does not include it.Change plan at kaleidr.com/billing.
403server_key_in_browserA server key was sent with an Origin header.Move the call to your backend. If the key was in page source, rotate it.
403session_origin_mismatchA session token was used from an origin other than the one it was minted for, or a published-map session was used with no Origin.Exchange a session on the page that uses it.
403ip_not_allowedA server or legacy key with an IP allowlist was used from an address outside it.Call from an allowed address, or change allowed_ips.
403chat_disabledPublished-map exchange: the map's Kaleidr AI does not turn on the feature asked for.Turn on Control Tower or Popup Window in the map's Kaleidr AI tile in Studio.
403owner_has_no_organizationPublished-map exchange: the map's owner has no organization.The owner must create or join an organization.
404not_foundPublished-map exchange: no published map or share link with that id.Check the id and that the map is published.

The complete catalog, including 429 and 5xx responses, is in Errors.