Authentication
Authenticate with Ctrl AI using session auth or API keys.
Ctrl AI supports two authentication methods: session-based auth (for the web UI) and API keys (for programmatic access).
Session Auth
When you sign in through the web interface, Ctrl AI creates a server-side session stored in the database. Sessions expire when the browser closes.
Supported sign-in providers:
- Email magic links (via Resend)
- GitHub OAuth
- Google OAuth
- LinkedIn OAuth
- Enterprise SSO via OIDC (Okta, Azure AD, Google Workspace)
See SSO Configuration for enterprise single sign-on setup.
API Keys
For programmatic access (scripts, CI/CD, SDK integrations), use API keys.
Creating an API Key
- Go to Settings > API Keys
- Click Create API Key
- Give it a name (e.g., "CI Pipeline", "Production Backend")
- Copy the key immediately — it's only shown once
API keys have the format ctrlai_pk_<32-hex-chars>.
Using an API Key
Include the key in the Authorization header:
curl -X POST https://your-instance.ctrlai.com/api/v1/inference \
-H "Authorization: Bearer ctrlai_pk_abc123..." \
-H "Content-Type: application/json" \
-d '{"query": "What is the credit risk for this applicant?"}'Key Properties
| Property | Details |
|---|---|
| Format | ctrlai_pk_<32-hex-chars> |
| Storage | SHA-256 hashed (never stored in plaintext) |
| Default role | author (can read, create, and edit units) |
| Permissions | Configurable (default: ["inference"]) |
| Expiry | Optional expiration date |
| Revocation | Immediate via Settings or API |
Managing Keys via API
# List keys (admin only)
GET /api/v1/orgs/{slug}/api-keys
# Create key (admin only)
POST /api/v1/orgs/{slug}/api-keys
{ "name": "Production Backend" }
# Revoke key (admin only)
DELETE /api/v1/orgs/{slug}/api-keys/{id}Rate Limiting
All API requests are rate-limited per user or API key:
| Tier | Limit | Applied To |
|---|---|---|
| Read | 60 requests / 60s | GET endpoints |
| Write | 30 requests / 60s | POST, PATCH, DELETE endpoints |
| Strict | 5 requests / 60s | Auth endpoints |
When rate-limited, the API returns 429 Too Many Requests with:
X-RateLimit-Limit— maximum requests allowedX-RateLimit-Remaining— requests remaining in windowRetry-After— seconds until the window resets
Response Format
All API responses follow a consistent envelope:
// Success
{
"data": { ... },
"meta": { "total": 42, "limit": 20, "offset": 0 }
}
// Error
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key",
"details": { ... }
}
}