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.

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