# API keys and sessions

Two different things call this service. A program sends an API key; a person
signs in to the dashboard and gets a session. They are not two spellings of
one mechanism, and the boundary between them is deliberate.

Within the first of the two there are three kinds of key, and the differences
between those are what most of this page is about.

## Why keys and sessions are separate

An API key identifies a **program**. It is a long-lived bearer credential,
configured once into a deployment. It may recognize documents and read that
account's own results.

A session identifies a **person at a browser**. It is short-lived and bound to
a sign-in. The dashboard uses it to manage the account: issuing and revoking
keys, choosing a retention window, taking a top-up quote.

The two sets of powers do not overlap, and that is the point. A key that could
issue keys would turn one leaked credential into an account nobody can take
back. The attacker mints a second key before the first is revoked. Keeping key
management behind a sign-in means that recovering from a leaked key is always
possible, using something the leak did not contain.

It works in the other direction too. A browser session is exposed to a class
of risk a server-side key is not. It is therefore not the credential that
spends money on recognition at scale.

The account-management routes are therefore outside the versioned API surface
and are not part of the published contract. They are the dashboard's, and the
dashboard is their client.

## What a key is made of

A key looks like `sk_live_9c41ba2e…`: a kind marker, then a body of random
characters carrying 128 bits of entropy.

The kind is **in the prefix** rather than looked up anywhere. A credential
beginning `sk_sandbox_` is never charged, and that is decided by reading those
characters. It cannot drift from a row in a table, because there is no row in
a table saying otherwise.

Only a hash of the key is stored. The service can tell whether a presented key
is one it issued, and it cannot produce the key itself. A key is therefore
shown in full exactly once, at creation. Afterwards it is known by its prefix:
the marker plus the first 8 characters of the body. That is enough to
recognize a key in a list and not enough to use it.

A key can be given an end of validity, and a key past it is refused like an
unknown one. A revoked key is refused the same way. A caller cannot tell an
unknown key from a withdrawn one, which is the answer that reveals least.

## The public sandbox key

`sk_sandbox_public` is printed in this documentation, on the home page and in
every runnable example. Publishing a credential sounds like a mistake, and
here it is the design.

It belongs to **no account**. It has no balance to spend, no history to read
and no settings to change. `GET /v1/usage` answers it with a null balance and
zero counters rather than somebody's figures, and it reads no stored scan.

What it can do is recognize. A document sent on the public key reaches the
real engine and comes back really read. The alternative is a fixed answer for
every image, which makes a product look broken to the person trying it on
their own passport.

Three walls bound that, and all three are keyed to the client rather than to
the key. Everybody shares the credential, so counting per key would count the
world as one caller. The rate bucket is per address. The lifetime free
allowance is per client. And the same image resubmitted past a small threshold
is refused, so one picture cannot be replayed to consume the demo.

Those walls fail **closed**. When the store holding the counters cannot be
reached, the anonymous path answers a retryable 503 rather than letting
unmetered free recognition through. A registered key is unaffected; it is
metered by its own balance.

Because the key is published, the recognitions it produces are never stored.
No account exists for them to belong to.

## An account's own sandbox key

The second kind is a sandbox key an account issues for itself, and it does
something different from the public one.

It is answered from a **fixed synthetic specimen** and never reaches the
Engine at all. Every call returns the same invented holder, the same document,
the same zone. Nothing about the image that was sent affects the answer beyond
being validated and counted.

That is what makes it the integration credential. A client built against it
can assert on exact values in a test, because the values do not move. It
spends no recognition capacity and is never charged. No real identity document
is read on the credential an account is most likely to hand around.

It reads no stored scan either. `GET /v1/scans/{id}` answers 404 for every
sandbox key, including the account's own results. An account's history is a
store of identity data, and this is the low-trust key.

Its usage figures, on the other hand, are the account's real ones. Usage is an
account-level question, and the answer does not change with the key that asked
it.

## The live key

The third kind is the one that does the work. It reaches the engine and draws
credits. Its results are stored under the account's retention window, and it
is the only kind that can read them back.

Everything a live key can do is a reason to treat it as a secret. It spends
money, and it opens a history of identity documents. An account may hold
several, which is what makes it possible to replace one without a gap. [Rotate
API keys](/guides/rotate-api-keys) is that procedure.

## Why the three exist rather than one

A single key with a test-mode flag is the obvious alternative. It fails at the
first question a developer asks: how do I try this before I sign up.

The three kinds answer three different moments. The public key is for the
minute before an account exists, where the only thing that matters is that a
real document reads correctly. The account's sandbox key is for the weeks of
building against a stable answer. The live key is for production.

Each of them is bounded by what its moment justifies. The public key
recognizes for real and is walled by client. The sandbox key is free and reads
nothing. The live key does everything and is the one worth protecting. A
caller who knows which of the three is in a deployment can predict the whole
of its behavior. That is what a credential ought to make possible.
