Skip to main content
Sly supports five authentication methods. They all produce the same RequestContext server-side, so once you’re authenticated, every endpoint behaves the same regardless of how you got there.
MethodToken prefixUse whenRevocableScoped
API keypk_test_* / pk_live_*Server-to-server integration from your backendYes, manuallyResource scopes
Agent tokenagent_*Simple agent auth, getting startedYes, rotatePer-agent
Ed25519 sessionsess_*Production agentsYes, per-sessionPer-agent
Portal tokenportal_*Customer-facing usage / billing API accessYes, revokeOperation-scoped
JWT sessioneyJ…The Sly dashboard UIAuto-expires 15 minUser-scoped

How to choose

Backend server integration

Use API keys. One key per environment (test/live), rotate on staff changes, store in a secrets manager.

Agent running on your infra

Start with agent tokens for simplicity; move to Ed25519 sessions before going live. Production agents should never send a long-lived secret over the wire.

Customer-facing dashboard that needs usage data

Use portal tokens. They’re scoped to read-only operations (e.g. usage:read), safe to embed in a customer-facing iframe or browser app.

Your own app UI (humans logging in)

JWT sessions via Supabase Auth. Used by the Sly dashboard itself; rarely what you want for server integrations.

How requests are authenticated

Every authenticated request carries a bearer token:
GET /v1/accounts HTTP/1.1
Host: api.getsly.ai
Authorization: Bearer <token>
The middleware reads the token, determines the method by prefix, and populates a RequestContext that includes:
  • tenantId — your organization (always set)
  • environmenttest or live
  • actorTypeapi_key | user | agent | portal
  • Method-specific fields — apiKeyId, actorId + kyaTier, portalScopes, etc.
All routes are filtered by tenantId automatically. You cannot see another tenant’s data regardless of which method you use.

What’s public (no auth)

A small set of endpoints accept anonymous requests. You never need to authenticate to call these:
  • /health, /ready — liveness / readiness checks
  • /.well-known/ucp, /.well-known/agent.json — protocol discovery
  • /v1/agents/:id/challenge, /v1/agents/:id/authenticate — the Ed25519 handshake
  • /v1/openapi.json, /v1/protocols — spec + capability discovery
  • /webhooks/* — inbound webhooks (signature-verified internally)
  • /a2a, /agents — A2A JSON-RPC + ERC-8004 agent cards
Everything else requires authentication.

Common pitfalls

The header must be Authorization: Bearer <token>. Raw token without Bearer returns 401.
pk_test_* keys only work on sandbox.getsly.ai. pk_live_* keys only work on api.getsly.ai. Mismatched environment → 401.
The server caches verified tokens for 60 seconds for performance. A freshly-revoked token may work for up to 60 seconds after revocation. Don’t treat revocation as instantaneous blocking.
sess_* tokens expire after 1 hour. Catch 401 with { "error": "SESSION_EXPIRED" } and re-run the challenge-response handshake.