opbox

The token.* family (6 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.

Consumetoken.consume

PropertyValue
Capabilitytoken.consume
Risk classSensitive - autonomy L2
Min. permissionMember
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

A THIN wrapper over the shared consume_token validation core (ADR-0040 step 4): the verb and the TokenIdentityProvider resolver call the SAME path, so the token’s three revocation axes are enforced in exactly ONE place (steering #1 - one validation path, never a second hand-rolled one). The verb adds only the JSON-shaping the front doors expect; all seven fail-closed checks + the atomic single-use spend live in consume_token.

Input { secret, scopeRef?, presentedEmail?, via?, fromBrowser? } (fields ending in ? are optional)

Call POST /v/token.consume with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.consume.

Gettoken.get

PropertyValue
Capabilitytoken.read
Risk classRead - autonomy L0
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

One token’s metadata (kind+scope+status+expiry+consume-history + lastAccessAt). NEVER the hash or the plaintext (C12). IDOR-scoped to the caller workspace.

Input { tokenId } (fields ending in ? are optional)

Call POST /v/token.get with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.get.

Listtoken.list

PropertyValue
Capabilitytoken.read
Risk classRead - autonomy L0
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

Returns outstanding tokens filtered by scope/status. The response carries ONLY kind+scope+status+expiry+consume-history metadata - never the hash or the plaintext (C12). IDOR-scoped: a token row from workspace B is never enumerable (the verb filters on workspace_id).

Input { scopeRef?, status? } (fields ending in ? are optional)

Call POST /v/token.list with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.list.

Minttoken.mint

PropertyValue
Capabilitytoken.write
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Returns { tokenId, secret, ... } - the secret is the ONLY time the plaintext is ever returned. The DB stores only its sha256 hash + an explicit scheme (C12).

Input { kind, scopeRef, purpose?, expiresInSecs?, allowedClickerEmails?, boundActorId?, requireBrowser? } (fields ending in ? are optional)

Call POST /v/token.mint with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.mint.

Revoketoken.revoke

PropertyValue
Capabilitytoken.write
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Atomic guard: a non-terminal token → REVOKED; a re-revoke of a terminal token is a no-op-conflict (idempotent terminal). A later consume of a REVOKED token is refused (410-equivalent).

Input { tokenId } (fields ending in ? are optional)

Call POST /v/token.revoke with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.revoke.

Revoke scopetoken.revoke-scope

PropertyValue
Capabilitytoken.write
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Bumps the scope-version counter so EVERY outstanding token in the scope fan is invalidated at next consume (one call kills the whole fan, any flavour). This is the generalised accessVersion axis - the SAME mechanism EPIC-PORTAL’s bump-access-version rides (consolidation).

Input { scopeRef } (fields ending in ? are optional)

Call POST /v/token.revoke-scope with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool token.revoke-scope.