Demosyne

Authentication

Bearer keys, scopes, world and character bindings, and how revocation lands.

Keys

Customer requests send a bearer key in the Authorization header. Keys use the trr_ prefix. The secret is shown exactly once at mint time in the console; the server stores a SHA-256 of the secret and cannot re-display it.

Authorization: Bearer trr_…

Keys are org-bound. The organization is fixed on the credential; a key never acts for another org. Mint and revoke from the console under the org you mean to use.

Scopes

A key carries one or more scopes. The five scopes and what each grants:

ScopeGrants
defineCreate and register scenario definitions
seatTake over or add characters; configure brain, memory, and prompts
observeRead worlds, characters, perceptions, and summaries
measureRead usage and spend; without it, usage fields read as absent
controlAdvance and pause worlds; mint and revoke keys

The console ships two presets: full access (all five) and read only (observe + measure). Usage fields on a world are None when the key lacks measure; that means missing scope, not zero spend.

Bindings

A key may be narrowed to specific worlds and characters via world_ids and character_ids at mint time. A binding restricts what the key can reach; it never widens a scope the key does not hold. An unbound key can reach every world and character its org owns, within its scopes.

Secret and publishable keys

A key is secret by default: it belongs on a server and never in a browser. A publishable key, minted with kind="publishable" and the prefix trr_pk_, holds exactly the observe scope and reads only worlds that have been published. It is safe to embed in client-side code; everything else still takes a secret key.

Revocation

Revoking a key in the console takes effect immediately for new requests. Allow up to 30 seconds for running services to notice and drop a cached credential. There is no undo; mint a new key if you need the same scopes again.

Using the key

The client resolves the key as argument, then environment, then config file: Client(api_key="trr_..."), then TERRARIUM_API_KEY, then the file written by terrarium configure. Every request sends it as Authorization: Bearer trr_....

Getting 401 or 403

A 401 means the key itself: missing, mistyped, or revoked. A 403 means the key works but may not do this: a scope it was not granted, a world or character it is not bound to, or an org mismatch. Check what a key actually holds with client.me() or terrarium me; it reports the org, scopes, and bindings the server sees.

Base URL

Production API base: https://api.demosyne.com/v1. The SDK resolves the base as argument, then TERRARIUM_BASE_URL, then the config file written by terrarium configure, then that default.