Skip to content
Keptslot
Start free

Keys

There are three kinds of credential, and a fourth route group that takes none at all. The differences are worth ten minutes now, because picking the wrong one produces a 403 whose fix is not obvious from the message.

Every key travels the same way — as a bearer token:

Authorization: Bearer sk_4bT1nQ7xLd9sVzK0pR2eYw8hC6jM3gF5uA1oS7iN0dE

A workspace key belongs to one workspace. It is created in the dashboard under Developer → API keys, or minted through the account API. Everything it can see is that one business: its services, its calendars, its bookings.

An account key belongs to the account, which is the billing entity that owns one or more workspaces. The two scopes are separated at the credential itself: an account key can never satisfy a workspace route, and a workspace key can never satisfy an account route.

The account key exists for one job: creating a workspace by API, and then minting the first key for it.

Prefix Scope Where it runs What it reaches
pk_ Workspace A browser Three endpoints. See below.
sk_ Workspace Your server Everything under /v1, except /v1/account.
ak_ Account Your server /v1/account only.

An account key does not unlock workspace routes. If you hold ak_ and want to read a workspace’s bookings, mint an sk_ for that workspace and use it. That is deliberate: the account key’s surface is four routes and no more.

A publishable key is not a secret, and treating it as one will confuse you. GET /v1/public/workspaces/{slug} hands the workspace’s pk_ to anybody who knows the slug. That is by design — it is how a booking page bootstraps itself with no server of its own.

What makes that safe is not secrecy. It is that a pk_ reaches exactly three endpoints:

  • GET /v1/availability
  • POST /v1/bookings
  • POST /v1/bookings/{id}/verify

Everywhere else it gets a 403 with secret_key_required. It cannot list your bookings, read a customer, or change a price.

What the origin check does and does not do

Section titled “What the origin check does and does not do”

A publishable key carries a list of allowed origins. When a request arrives with an Origin header, that header must be the workspace’s own booking page or an entry on the key’s list. If it is not, the request is refused with origin_not_allowed.

Two things follow, and the second one surprises people:

It is an anti-abuse control, not a security boundary. It stops a third party from lifting your pk_ and embedding it in their site, because a browser stamps their real origin on the request and browsers do not let page JavaScript forge that header.

A request that sends no Origin header at all is not origin-checked. The guarantee is the browser’s, and it ends at the browser. curl sets Origin with one flag, or omits it entirely. So a publishable key does work from a server, in the narrow sense that the three endpoints above will answer it — it is simply not what the key is for, and it buys you nothing over a secret key except a smaller surface and a rate limit.

The controls that do not depend on client honesty are the three-endpoint surface, the rate limits, and revocation.

sk_ is the ordinary server credential. It reaches every workspace route. It is not origin-checked, and it is not rate-limited.

The full value is shown once, on the response that creates it. No later read can return it. A publishable key can be read back later and a secret key cannot — the publishable one is designed to be public, and the secret one is not.

Keep sk_ on a server. A secret key in browser JavaScript is the whole workspace, handed to anybody who opens developer tools.

/v1/public/* takes no Authorization header. The token in the URL is the only credential:

  • GET /v1/public/workspaces/{slug} — the slug is the credential, and the response is deliberately public.
  • GET|POST /v1/public/bookings/{token} and its cancel and reschedule routes — this is the manage link the customer receives by email. The token comes from access_token on the response that created the booking, and that is the only response that ever carries it.

There is no login on this surface, and there never will be. A customer of a Keptslot business is not a Keptslot user.

There is no recovery path for a secret key or a webhook signing secret. Both are shown once and cannot be read back. Revoke and re-create, or — for a webhook — call the rotate endpoint.

This is worth saying plainly because the failure is silent and late: everything keeps working until the day you redeploy from a machine that does not have the value.