Authentication
Every way to authenticate to Kentro in one place: API key headers, bearer tokens, buyer and guest tokens, Pixel keys and OAuth for Kentro MCP.
Every request is authenticated at Kentro's gateway before it reaches an API: the gateway resolves the credential to a tenant and its scopes, and refuses anything else with 401. Which credential to send depends on who is calling: a system, a storefront acting for a buyer, a website or backend sending events, or an AI assistant acting for a user.
Which method to use
| Caller | API | Credential | Sent as |
|---|---|---|---|
| A server-to-server integration | Channel API | API key pair | kentro-key and kentro-secret headers |
| An integration making many calls, or a component that must not hold the secret | Channel API, Pixel management API | Bearer token minted from the key pair | Authorization: Bearer <accessToken> |
| A custom storefront's server | Store API | API key holding storefront:serve, plus the storefront host | X-API-Key and X-Storefront-Host |
| A signed-in buyer on that storefront | Store API | Buyer access token | X-Storefront-Buyer |
| A guest shopper on that storefront | Store API | Guest token | X-Storefront-Guest |
| A website or app sending events | Kentro Pixel collector | Property public key | The SDK's data-key |
| A backend sending events | Kentro Pixel server API | HMAC server key | X-Kentro-Key-Id, X-Kentro-Timestamp, X-Kentro-Signature |
| An AI assistant acting for a Kentro user | Kentro MCP | OAuth 2.1 access token | Authorization: Bearer, managed by the MCP client |
Every credential belongs to one tenant, and nothing in a request selects a tenant: the credential's tenant is the tenant of the call.
API key headers
The Channel API takes the key pair from Users > API keys on every request:
kentro-key: <key>
kentro-secret: <secret>
X-API-Key: <secret> is the single-header form: the secret alone. The gateway compares it against every active key, so prefer the pair, or a bearer token, at high request rates. The Store API takes only this form.
Bearer tokens and refresh
Exchange the key pair once for an access token that lives 15 minutes.
curl -s -X POST https://apis.kentro.live/auth/login/api-key \
-H "Content-Type: application/json" \
-d '{ "key": "'"$KENTRO_KEY"'", "secret": "'"$KENTRO_SECRET"'" }'
const res = await fetch('https://apis.kentro.live/auth/login/api-key', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: process.env.KENTRO_KEY, secret: process.env.KENTRO_SECRET }),
});
if (!res.ok) throw new Error(`login failed: ${res.status} ${await res.text()}`);
const { accessToken, refreshToken, expiresIn } = await res.json();
console.log({ expiresIn, hasRefreshToken: Boolean(refreshToken), tokenPrefix: accessToken.slice(0, 12) });
The answer:
{
"accessToken": "eyJhbGciOi...",
"refreshToken": "4f2c7a...",
"expiresIn": 900,
"user": { "id": "...", "tenantId": "...", "type": "api-key" }
}
Send Authorization: Bearer <accessToken> on Channel API calls. Before expiresIn seconds pass, rotate the pair:
curl -s -X POST https://apis.kentro.live/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "'"$REFRESH_TOKEN"'" }'
- The answer holds a new access token and a new refresh token. The refresh token rotates on every use; a refresh token used twice is refused.
- A key issued as a single token logs in with
{ "apiKeyRaw": "<token>" }instead ofkeyandsecret. POST https://apis.kentro.live/auth/logoutwith{ "refreshToken": "..." }revokes a refresh token.- An expired access token answers
401 TOKEN_EXPIRED: refresh, then retry. A malformed one answers401 TOKEN_INVALID. - On the sandbox the host is
https://apis.kentro.dev.
A bearer token skips the per-request secret check, which matters at many requests per second, and keeps the secret in one place.
Store API: key, host, buyer and guest
A Store API request carries up to three identities.
| Identity | Header | Where it comes from |
|---|---|---|
| The storefront server | X-API-Key (the key's secret) | Users > API keys, with a permission group holding storefront:serve |
| The store | X-Storefront-Host | The published storefront's host, lower case, no scheme, no path |
| The buyer | X-Storefront-Buyer: <accessToken> | POST https://apis.kentro.live/auth/login/customer with { "email", "password", "host" } |
| The guest | X-Storefront-Guest: <guestToken> | POST /session.guest |
- Buyer access tokens live 15 minutes; buyer refresh tokens live 30 days and rotate on every
POST /auth/refresh. Refresh before expiry, or on the first401. - Buyer sign-in, refresh, sign-out and password reset take no API key;
hostin the body names the store. - The Store API does not read
Authorization. The buyer token travels inX-Storefront-Buyer, never as a bearer token. - Mint a guest token once per browser, and only when
store.getanswersguestCheckout: true. Right after sign-in, send both tokens so the guest's cart can be offered to the buyer. - A password change ends every session of the buyer's account.
Details: Store API: Authentication.
Kentro Pixel keys
| Key | Format | Used by |
|---|---|---|
| Public key | pk_live_... for production properties, pk_test_... for staging and development properties | The browser SDK. Visible in page source by design; limited to the property's allowed origins. |
| Server key | An sk_ key id plus a secret shown once | A backend: signs POST https://pixel.kentro.live/v1/server/events with HMAC-SHA256 over timestamp + "." + rawBody, within a 300-second window, and signs identity tokens for signed-in visitors. |
| Kentro authentication | A bearer token or an API key holding pixel:read or pixel:manage | The Pixel management API at https://apis.kentro.live/pixel/v1. |
See Pixel server API, Identity tokens for signed-in visitors and Pixel browser SDK.
OAuth for Kentro MCP
Kentro MCP lets an AI assistant work with a tenant's data as one Kentro user. It uses OAuth 2.1; no API key is involved.
- The MCP client calls the Kentro MCP server and receives
401with aWWW-Authenticateheader that points to the server's OAuth metadata. The metadata names Kentro's authentication service (https://apis.kentro.live/auth) as the authorization server. - The client registers itself (dynamic client registration) and starts an authorization code flow with PKCE. Only the
S256challenge method is accepted. - The user signs in to Kentro and approves the client on the
Connect to Kentro Assistantpage (ApproveorDeny). - The client exchanges the code for an access token (1 hour,
expires_in: 3600, scopecopilot) and a refresh token, and refreshes on its own.
- The connection acts with the approving user's permissions, in that user's tenant.
- The user revokes the connection in Kentro IQ under
Assistant>Assistant Settings, panelConnect your AI tools (MCP). A revoked grant's tokens are refused, and it cannot mint new ones.
Setup per client: Connect Claude and Connect coding agents. Controls: MCP security.
What the gateway answers
Refusals before a request reaches an API use the gateway's shape, { "error", "message" }:
| Status | error | Cause |
|---|---|---|
| 401 | INVALID_REQUEST | No credentials where a key is required, such as a Store API call without X-API-Key. |
| 401 | INVALID_CREDENTIALS | Unknown or disabled key, or a wrong secret. |
| 401 | TOKEN_INVALID | A malformed bearer token. |
| 401 | TOKEN_EXPIRED | A bearer token past its lifetime: refresh. |
| 403 | TENANT_INACTIVE | The tenant is deactivated. |
A Channel API request with no credentials at all reaches the API and answers 401 with code: unauthenticated in the API's own envelope. Branch on error or code, never on message: the INVALID_CREDENTIALS message mentions an email and a password even when the credential was an API key.
Updated about 12 hours ago

