Authentication

JWT-based authentication, securing your requests, and rate limits.

Overview

The Foil Engine API uses JWT Bearer tokens issued by Supabase for authentication. Some endpoints require authentication (creating, saving, deleting personas), while others are publicly accessible (browsing public personas, chatting with published characters).

Note
You can obtain a JWT token by authenticating through Supabase Auth. The token should be included in the Authorization header of every authenticated request.

Authentication Header

Include your JWT token as a Bearer token in the Authorization header:

Authorization: Bearer <your_jwt_token>

Requests to protected endpoints without a valid token will return a 401 Unauthorized response.

Auth Endpoints

GET /api/v1/auth/me

Returns the currently authenticated user. Requires auth.

FieldTypeDescription
idstringUnique user ID (UUID)
emailstringUser's email address
display_namestringUser's display name

Example request:

curl https://api.foilengine.io/api/v1/auth/me \
  -H "Authorization: Bearer <your_jwt_token>"

Example response:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "email": "developer@example.com",
  "display_name": "Dev User"
}

POST /api/v1/auth/migrate-progress

Migrates anonymous play progress to the authenticated user's account. Call this after a user signs in to preserve any chat history or scores accumulated before authentication. Requires auth.

Request Body

FieldTypeRequiredDescription
old_session_idstringYesThe anonymous session ID to migrate progress from

Example request:

curl -X POST https://api.foilengine.io/api/v1/auth/migrate-progress \
  -H "Authorization: Bearer <your_jwt_token>" \
  -H "Content-Type: application/json" \
  -d '{"old_session_id": "anon-session-abc123"}'

Game SDK Authentication

For game integrations, the Game SDK uses API key authentication instead of JWT tokens. Include your key in the X-API-Key header:

X-API-Key: pk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6

API keys are scoped to your account and can only access your own published personas. Create and manage keys from the API Keys dashboard or via the POST /api/v1/sdk/api-keys endpoint (requires JWT auth).

LLM API Key (BYOK)

SDK chat endpoints also require your own LLM provider API key, passed via the X-LLM-API-Key header. This key is used for that request only and is never stored. Any LiteLLM-supported provider works (OpenAI, Anthropic, Groq, etc.).

X-LLM-API-Key: sk-your-openai-or-anthropic-key
X-LLM-Model: gpt-4o  # optional model override

# Optional: use different providers per pipeline step
X-LLM-Eval-API-Key: sk-ant-...        # e.g. Anthropic for evaluation
X-LLM-Response-API-Key: sk-...        # e.g. OpenAI for responses
X-LLM-Summarization-API-Key: sk-...   # e.g. different key for summaries

Which Endpoints Require Auth?

ActionAuth Required
Browse public personasNo
Chat with published personas (web)JWT (sign-in required)
Chat via Game SDKAPI Key + LLM Key
List your own personasJWT
Create / save a personaJWT
Publish a personaJWT
Delete a personaJWT
Manage API keysJWT

Rate Limits

Rate limits are applied per IP address. When a limit is exceeded, the API returns a 429 Too Many Requests response with a Retry-After header indicating seconds until the next request can be made.

CategoryLimitScope
Generation (AI content creation)10 requests / minutePer IP
Chat (sending messages)60 requests / minutePer IP
General (all other endpoints)120 requests / minutePer IP
SDK Chat (sending messages)30 requests / minutePer API key
SDK General (init, history, reset)60 requests / minutePer API key

Example rate-limited response:

HTTP/1.1 429 Too Many Requests
Retry-After: 12

{
  "error": "Rate limit exceeded. Try again in 12 seconds."
}