Documentation

API keys

Which key does what, where each one belongs, and how the platform decides.

A key identifies your application to the platform. It is not the user's credential — the user is identified by their session token, which travels separately. Most calls need both, and they answer different questions: the key says which project and environment this is, the session says who is asking.

The key travels in the x-platform-key header on every request. An SDK sets it for you when you construct a client; if you are calling the API directly, or writing a client for a language we do not ship yet, that header is the whole contract.

Types

The type is inferred from the prefix, before anything else happens.

pk-publishable

Browsers, mobile apps, anything you ship. Safe to embed.

sk-secret

Server to server only. A capability in itself.

The body after the prefix is 32 URL-safe characters, from 24 random bytes.

One key per environment

Keys belong to an environment, not to a project. A pk- from development cannot reach production data — not a matter of permissions, a different store. See Fundamentals.

Publishable keys

A publishable key identifies the app. It does not authorize the user.

That distinction is what makes shipping it in a bundle safe: holding one grants nothing on its own. Every call that touches user data still needs the user's session, and what that session may do is decided by their grants.

GET /session
x-platform-key: pk-…
Authorization: Bearer <session token>

Secret keys

A secret key reaches the administrative surface — user administration, roles and grants, sending messages. There is no user behind it, so there is nothing to check it against beyond the key itself.

POST /admin/users
x-platform-key: sk-…

Read it from the environment, never from the repository, and never from code that gets bundled for a client.

Shown once

A secret key is stored as a hash. Only publishable keys are kept in a form the platform can decrypt, which means a sk- you did not copy at creation is gone — the console can show you its last four characters and nothing more.

Put it in the environment at creation time, or create another one.

How the platform decides

Every endpoint declares which key types it accepts. The check runs in this order:

  1. The prefix is read. pk- or sk- — the type is inferred from the key itself, not from what you claim.
  2. The type is matched against the endpoint's list. A type that is not on it is rejected immediately, before the key is even validated. A publishable key sent to an admin route fails here.
  3. The key is validated against the environment.

An endpoint that declares nothing accepts nothing, so a new administrative route is closed from the moment it exists rather than open until someone remembers to close it.

A small set of endpoints declare that they need no key at all — the ones that have to work before an application is identified.

Expiry and replacement

A key can carry an expiry, after which it stops validating.

There is no built-in rotation. To replace a key you create the new one, move your traffic, then delete the old — both are valid in between, so there is no cutover where neither works. Order matters: deleting first breaks everything still using it.

Rotate by environment, not globally. Replacing a production secret has nothing to do with the one your CI uses, and doing them together turns one incident into two.

In the JavaScript SDK

The key you pass decides which client you get, and therefore which namespaces exist:

createClient(url, 'pk-…');        // auth only
createServerClient(url, 'sk-…');  // auth + comms + admin

See Clients. Other SDKs draw the same line — the key type is a platform rule, not a JavaScript one.

On this page