AI Setu Docs
Concepts

Ephemeral tokens

Short-lived, scoped tokens for handing inference access to a browser, agent run, or end-user session.

Your workspace API key can call anything, forever, until you revoke it. That's the wrong shape to hand to a browser tab, a sandboxed agent run, or a per-customer session — any of those could leak the key, and a leaked long-lived key is a standing liability. An ephemeral token is minted on demand from your backend, expires on its own within hours, and can be restricted to exactly the routes and models that one session needs. It cannot outlive or exceed the purpose it was minted for.

Minting a token

Minting happens on your backend, authenticated with your workspace's personal access token (PAT) — never inside the untrusted client:

curl https://api.aisetu.ai/graphql \
  -H "Authorization: Bearer $AI_SETU_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation Mint($input: MintEphemeralTokenInput!) { mintEphemeralToken(input: $input) { token jti expiresAt scopes } }",
    "variables": {
      "input": {
        "parentKeyId": "'"$PARENT_KEY_ID"'",
        "scopes": ["chat", "model:openai/gpt-4o-mini"],
        "ttlSeconds": 900,
        "budgetMicros": 500000
      }
    }
  }'

Hand the returned token (prefixed tt_ev_) to the client; it's used exactly like a workspace key:

import { AiSetu } from '@ai-setu/client';

const client = new AiSetu({ apiKey: ephemeralToken });

const res = await client.chat.completions.create({
  model: 'openai/gpt-4o-mini',
  messages: [{ role: 'user', content: 'Hello' }],
});

See the Agent Quickstart for the full walkthrough of wiring this into a runtime agent, including how to layer a budgetMicros cap on top.

What a scope can restrict

InputRestricts
chatPOST /v1/chat/completions
embeddingsPOST /v1/embeddings
messagesPOST /v1/messages (Anthropic-native)
model:<id>Narrows the token to specific models. With no model: scope, any model is allowed on the granted route(s); with one or more present, the request's model must match one of them.

A token with no scopes at all is rejected outright — there is no "grants everything" ephemeral token. A scope can never exceed what the parent key (parentKeyId) itself is authorized for: requesting chat or messages requires the parent to hold chat:write, and embeddings requires embed. A model:<id> scope is always allowed to request (it can only narrow, never widen). Minting fails validation if any requested scope exceeds the parent's grant.

Lifetime

ttlSeconds is required and capped at 24 hours — the mint call rejects anything longer. The cap is also enforced a second time on the verifying side (the gateway), independent of what a token's own claims say, so a future minting bug can't produce a token that outlives the platform-wide ceiling.

The gateway verifies a token statelessly: an HMAC-SHA256 signature check plus an expiry check, no database or cache round trip on the request path. That's what makes ephemeral tokens cheap enough to mint per session or even per request.

Revocation

Verification alone can't kill a token before it expires, so revocation is layered on top via a shared denylist your backend writes to directly:

mutation RevokeOne {
  revokeEphemeralToken(jti: "...")
}

mutation RevokeAllFromKey {
  revokeEphemeralTokensForKey(parentKeyId: "...")
}
  • Revoke one — denies that single jti immediately.
  • Revoke all for a parent key — stamps a cutoff so every token minted from that key with an earlier issue time is denied; anything minted after the call is unaffected.

A revoked token is rejected on the next request with 401 / wesence.revoked_key. Regardless of whether you ever call revoke, every ephemeral token is bounded by its own ttlSeconds — the denylist only matters for killing a token before it would have expired on its own.

Revoking or rotating the parent key

Revoking an API key (revokeApiKey) or rotating it (rotateApiKey, which revokes the old key) immediately invalidates every ephemeral token minted from it. You do not need a separate revokeEphemeralTokensForKey call. The gateway reads the denylist on every ephemeral request, so a widget holding one of those tokens gets 401 / wesence.revoked_key on its very next call. Minting from a revoked key is refused with NOT_FOUND. The same applies to the keys revoked by a GDPR erasure request.

If you rotate a key, widgets holding tokens minted from the old key stop working: mint fresh tokens from the new key.

The revocation is best-effort: if the denylist write fails, the key is still revoked and those tokens stop at their own expiry (at most 24 hours later). The api_key.revoked / api_key.rotated audit event flags a failed write (ephemeralRevokeFailed). Calling revokeApiKey again on the already-revoked key re-writes the denylist entry, so you can retry safely.

Deleting a workspace

Deleting a workspace (deleteWorkspace) revokes every ephemeral token minted from any of its API keys, as if you had called revokeEphemeralTokensForKey on each key. The gateway reads the denylist on every ephemeral request, so a widget holding one of those tokens gets 401 / wesence.revoked_key on its very next call; there is no cache delay. Minting from a key of a deleted workspace is refused with NOT_FOUND, the same answer a revoked key gets.

The revocation is best-effort: if the denylist write fails, the delete still succeeds and those tokens stop at their own expiry (at most 24 hours later). The workspace.deleted audit event records how many parent keys were revoked (ephemeralParentKeysRevoked) and flags a failed write (ephemeralRevokeFailed).

Optional per-token limits

Beyond scope and TTL, a mint call can attach:

  • budgetMicros — a spend cap in USD micros for just this token. Once hit, further calls return 402 / wesence.credential_cap_exceeded; nothing else in your workspace is affected.
  • rateLimits — request/token frequency limits scoped to this token alone.

Error codes on a scoped call

CodeHTTP statusMeaning
wesence.invalid_key401Token missing, malformed, expired, or ephemeral tokens aren't enabled on this deployment
wesence.revoked_key401The token (or its parent key, via a revoke-all) was revoked
wesence.scope_denied403The token is valid, but its scope doesn't permit this route or model
wesence.credential_cap_exceeded402The token's own budgetMicros cap is exhausted

Full reference: Errors.

Deployment note

Ephemeral tokens require a signing key configured on both the API (which mints) and the gateway (which verifies) — if your deployment hasn't set one up, tt_ev_ tokens are rejected as an unknown credential (401 / wesence.invalid_key). Ask your platform operator if minting fails unexpectedly.

On this page