Authentication

API keys, scopes, and what to do when a key leaks.

The authenticated API lives under /api/v1 and is reached with an API key.

https://app.superposition.ai/api/v1

Creating a key

Go to Settings → API access and choose New key. It asks for two things:

  1. Details — a name you will recognise later, and when the key should expire.
  2. Permissions — what the key may reach. See Scopes.

The secret is shown once, immediately after creation. There is no screen, endpoint, or support request that can bring it back. Store it in your platform's secrets vault, not in source control.

Afterwards the key list shows only its opening characters — the sp_live_ or sp_test_ prefix plus the first few of the secret — which is enough to match a key against one already deployed in CI.

Making a request

Send the key as a bearer token. These examples read it from SUPERPOSITION_API_KEY rather than inlining it, so the key stays out of your shell history and out of anything you paste into an issue:

export SUPERPOSITION_API_KEY="sp_live_..."

curl https://app.superposition.ai/api/v1/jobs \
  -H "Authorization: Bearer $SUPERPOSITION_API_KEY"

Keys are prefixed sp_live_ in production and sp_test_ elsewhere, so it is obvious at a glance which environment a key belongs to.

Send one credential per request. A request carrying both a bearer token and a session cookie is rejected rather than resolved by precedence — guessing which one you meant is how the wrong principal ends up in an audit log.

Everything you do is recorded

Every authenticated request writes a row to your organization's audit log, readable in Settings and through GET /audit. The row names the credential that acted, the endpoint, and whether it succeeded — including requests that were refused for a missing scope, which is usually the first thing you want when something stops working.

Requests that never authenticate at all (no credential, or one that matches nothing) are not recorded, because there is no organization to attribute them to.

The two ids on a key, and the one secret

A key has an identity you can share and a secret you cannot recover. They are different values and only one of them is dangerous.

What it looks likeSafe to share?
Secretsp_live_ / sp_test_ + 40 charactersNo. This IS the credential.
Key ID32 characters, no prefixYes. Names the key without granting anything.
Prefixe.g. sp_test_a1b2Yes. Shown in Settings so you can tell keys apart.

The secret is shown exactly once, when you create the key, and is hashed at rest. There is no screen, endpoint, or support request that can bring it back — if you lose it, create a new key and revoke the old one.

The key ID is what identifies the key everywhere else: on the API access page, in the audit log (as Credential ID), and in GET /me as principal.credentialId. It is a database identifier, not derived from the secret, and it cannot be used to authenticate — sending it as a bearer token returns 401. Quote it in a support request when you need to say which key.

If a value starts with sp_live_ or sp_test_, treat it as the secret and rotate it if it has leaked. Anything else on these screens is an identifier.

What a key can do

A key is bound to exactly one organization, and it can never do more than its owner can.

Two limits apply on every request, and both have to pass:

  1. Scopes — what you selected when you created the key.
  2. Your role — read live, on every request. If your role in the organization is reduced, the key narrows immediately. If you are removed from the organization, it stops working.

So a key holding billing:read still reads nothing if its owner is not an organization admin. This is deliberate: a key is a way to act as yourself from a script, not a way to gain access you do not already have.

A key belongs to you

Every key you create acts as you and follows your role, so a change to your role changes what the key can do on its very next request — there is nothing to re-issue or clean up.

That also means a key cannot outlive your access. If you leave the organization the key is not deleted, but it stops being accepted, because there is no longer a role behind it. If you are added back, it works again.

If you need a key for something that has to keep running when people come and go — a CI pipeline, a scheduled export — create it from an account that will stay in the organization, and treat it like any other shared credential. Organization-owned service accounts were removed: they added a second ownership model, and a second way for a key's permissions to be wrong, for a case that a normal key covers.

Choosing an organization

If you belong to more than one organization, each key is still bound to one. You may send the binding back as a cross-check:

Superposition-Organization: <organization id>

If it disagrees with the key's binding the request is rejected. It is never used to switch organizations — a key cannot reach data outside the organization it was made in.

When a key leaks

Revoke it. Settings → API access → Revoke, or ask the assistant to revoke it by name.

Revocation takes effect on the key's very next request. There is no grace period on purpose: a leaked key has to die immediately, and a grace window is the opposite of that.

There is no rotation. Replacing a key is: create the replacement, deploy it, revoke the old one. That way you choose the overlap window rather than inheriting a fixed one.

Checking what a key holds

curl https://app.superposition.ai/api/v1/me -H "Authorization: Bearer $SUPERPOSITION_API_KEY"

/me returns the principal, the organization, the role backing the key, and the expanded scopes — wildcards resolved into the concrete list. It needs no scope of its own, because it tells you only what you already hold.

Last updated on

On this page