Skip to main content
One API key belongs to your organization and covers your whole fleet. It authorizes the call. It never decides identity: that comes from each agent’s own signing key, which Sanning never receives. This page is about the key.

Create a key

Access to console.sanning.io starts with a conversation with the Sanning team, not a sign-up form. Once your organization exists on the roster, open Settings, API keys and select Create key. Only an owner or admin can create one. Name the key, and leave Verify unchecked unless this key will also ask Sanning for a verdict. Store it as SANNING_API_KEY in whatever your service already uses for secrets. The key is a credential for your organization, not the key that signs your evidence.

What a key can do

A key can anchor, or anchor and verify. Those are the two choices, and the console’s Create key dialog is exactly that: a name, and whether the key may verify. The console shows the two words. The scope names behind them travel on the API and appear inside a refusal, so they are worth recognizing: Those are the only two sets a key you create can carry. Scopes are not selected one at a time, and POST /api/v1/user/keys accepts nothing else: it answers “A key can anchor, or anchor and verify. Send scopes with exactly the three anchor scopes, or those three and the two verify scopes.” The same route takes only a name and the scope set. Sanning sets every other property of the key. The three anchor scopes travel together because each one is useless without the others. A key that can write but cannot enroll anchors nothing, because the plane refuses an envelope signed by a key it has no agent for. A key that can write but cannot read anchors for months and then fails on the day someone asks for a pack, because building one reads your own records back. The Verify choice always appears in the dialog. Where your organization does not have verify access, it appears disabled, with a sentence naming the address to ask.

Enrollment happens on the first anchor

You write no enrollment step. On the first anchor call the SDK proves possession of the signing key to the control plane, and the agent appears on the console’s Agents page attributed to that key. One organization key covers every agent: no per-agent credential, no enrollment script. See How an agent enrolls for the full lifecycle, including revoking and re-keying an identity from the console. Enrollment is the plane’s door policy, and it is not the trust path. Every signed record verifies offline against the open kernel whether or not the roster knows the key. Two properties are load-bearing:
  • The challenge is checked before it is signed. Enrollment is the one moment your identity key signs bytes the server chose, and that key also seals your evidence. The SDK refuses anything that is not a nonce rather than trusting Sanning not to send an envelope pre-image. Sanning is never in the trust path, including here.
  • Re-enrolling the same key is a no-op. That is what makes it safe to run on every boot.

One signing key per agent

An agent’s identity is its key, so a different key under a name your organization has already enrolled is a rotation, and a rotation must be authorized by the key being retired rather than by the API key. Generating a key at process start therefore works on the first boot and fails on the second with RotationUnauthorizedError. Load the same 32-byte seed on every boot. When you do mean to rotate, pass the retiring key so it can counter-sign the challenge:
A rotation is never inferred from a refusal. That is what stops a leaked organization key taking over an identity that is already producing evidence. If the retiring key is genuinely lost, an owner or admin pins a new key for the agent from Settings, Signing keys in the console, and the agent completes the re-key on its next boot. See Re-key a revoked name.

Enroll at deploy time instead

Where you would rather enroll out of band, turn the automatic call off and drive it yourself. A fleet that cold-starts together shares one rate limit, because enrollment is limited per API key, so this is the answer to EnrollmentThrottledError as well.
Then build the anchorer with autoEnroll: false in TypeScript, or auto_enroll=False in Python.

Two names travel, and they are not the same name

subject.agent_id is sealed inside every signed record. It is history, it never changes, and it cannot contain spaces. A display name lives on the console roster, accepts any text, and a rename shows up straight away. They default to agreeing. Pass displayName to createAnchorer in TypeScript, or display_name on the anchorer in Python, when you want a human-readable label. Renaming an agent then never reaches back and rewrites what a past record was signed saying.

Anchor from your agent

Where the key and the signing seed are used.

How an agent enrolls

The full lifecycle: enroll, revoke, re-key.

Keep what you anchored

The store the pack reads, and the scope that reads the index.