Authentication and keys

Two classes of key, what each one may do, how they are stored, and what rotation actually does.

Every request carries a bearer token. There is no other authentication scheme, no session, and no anonymous endpoint: an unauthenticated request to any path in the API returns the documented 401 envelope described in errors.

curl https://api.saifuro.com/v1/decisions \
  -H "Authorization: Bearer sk_live_..."

Two classes of key

Organization keysk_live_ · sk_sandbox_held by your backendmanage agents, mandates,escrows and webhooksread decisions and usageAgent keyak_live_ · ak_sandbox_held by one agent's runtime, nowhere elsecreate authorization requestsread its own decisionsescrow operations for its own deal21 of the 29 operations require an organization key. An agent key on one of them returnsforbidden, not 404 and not silence.

Agent keys exist because of the identity argument in the threat model: credentials are issued per agent, an agent authenticates as itself, and a mandate attaches to that identity rather than to a name in a request body. Give an agent an organization key and every limit in your policies rests on the assumption that nothing in that environment lies about who it is.

What each class can reach

The API exposes 29 operations across 23 paths. 21 of the 29 require an organization key. The eight an agent key may call are the ones an agent needs to do its job and nothing else: create an authorization, read its own decisions, and the escrow operations for a deal it is party to.

An agent key on an organization endpoint does not return 404 and does not silently do nothing. It returns:

{
  "error": {
    "code": "forbidden",
    "message": "This endpoint needs an organization key",
    "request_id": "req_8a21"
  }
}

Format and storage

A key is its prefix, the environment, an underscore, and 32 hexadecimal characters — sk_sandbox_ followed by 32 hex, for example. The environment is part of the key, so a request cannot ask for an environment: the key it arrives with decides, and nothing in the body changes that.

Keys are stored as a SHA-256 hash. The plaintext is shown once, at issue, and cannot be recovered afterwards — not by you and not by us. What we keep alongside the hash is a hint of the form sk_sandbox_...7906, enough to tell two keys apart in a list and not enough to use.

Rotation is a cut, not an overlap

POST /v1/agents/{id}/keys/rotate revokes every active key for that agent and then issues a new one, in that order, in a single transaction. There is no overlap window: the moment the call returns, the old key is dead and the new one is in the response body — the only time it will ever be shown.

Plan for that. A rotation performed while the agent is mid-flight will fail its next request with 401, which is the intended behaviour for a credential you have decided to retire, and the wrong behaviour to discover during an incident. Rotating an agent that must not stop means bringing the new key into its configuration first and cutting over deliberately.

Revoking without replacing is a different operation: POST /v1/agents/{id}/disable.

On this page