REST API Reference
The Spanlens REST API backs the dashboard and is stable for direct use. Dashboard endpoints accept a Supabase JWT in Authorization: Bearer …; the read endpoints (requests, stats, traces, anomalies, recommendations, users, evals) also accept a Spanlens API key, which is how the MCP server and BI integrations query your data. Proxy and ingest endpoints use a Spanlens API key.
Authentication
Two security schemes are used:
| Scheme | Header | Used for |
|---|---|---|
| BearerJWT | Authorization: Bearer <jwt> | All /api/v1/* dashboard endpoints |
| ApiKey | Authorization: Bearer sl_live_… | Proxy endpoints (/proxy/*) and SDK ingest (/ingest/*) |
| Either | Authorization: Bearer <jwt | sl_live_… | sl_live_pub_…> | Dual-auth read endpoints, marked "JWT or API key" below. Public-scope keys (sl_live_pub_…) work here and are read-only everywhere else. |
JWTs are obtained from Supabase Auth (supabase.auth.getSession()) and expire after 1 hour. Spanlens API keys (sl_live_…) are created at /projects by clicking + New Spanlens key on the project card; they never expire (revoke explicitly via the toggle when rotating). For the cryptographic details + the per-SDK auth-header mapping, see Keys & encryption and Direct proxy.
Base URLs
| Environment | Base URL |
|---|---|
| Production (hosted) | https://api.spanlens.io |
| Local dev | http://localhost:3001 |
| Self-hosted | https://your-spanlens.example.com |
Endpoint groups
| Group | Prefix | Auth |
|---|---|---|
| Health | GET /health | None |
| Organizations | /api/v1/organizations | JWT |
| Projects | /api/v1/projects | JWT |
| API keys | /api/v1/api-keys | JWT |
| Provider keys | /api/v1/provider-keys | JWT |
| Key introspection | /api/v1/me/key-info | API key |
| Requests | /api/v1/requests | JWT or API key |
| Stats | /api/v1/stats | JWT or API key |
| Traces | /api/v1/traces | JWT or API key |
| Users (end-user analytics) | /api/v1/users | JWT or API key |
| Sessions | /api/v1/sessions | JWT |
| Prompts | /api/v1/prompts | JWT |
| Anomalies | /api/v1/anomalies | JWT or API key |
| Security | /api/v1/security | JWT |
| Alerts | /api/v1/alerts | JWT |
| Recommendations | /api/v1/recommendations | JWT or API key |
| Evals | /api/v1/evaluators, /api/v1/eval-runs | JWT or API key (writes need a full key or admin/editor) |
| Datasets | /api/v1/datasets | JWT |
| Experiments | /api/v1/experiments | JWT |
| Prompt experiments (A/B) | /api/v1/prompt-experiments | JWT |
| Prompt playground | /api/v1/prompts/playground/run | JWT |
| Human evals | /api/v1/human-evals | JWT |
| Annotation queue | /api/v1/annotation/queue | JWT |
| Score configs | /api/v1/score-configs | JWT (admin/editor for writes) |
| Webhooks | /api/v1/webhooks | JWT (admin/editor for writes) |
| Audit logs | /api/v1/audit-logs | JWT |
| Saved filters | /api/v1/saved-filters | JWT |
| Exports | /api/v1/exports/* | JWT |
| Rate limits | /api/v1/rate-limits | JWT |
| Billing | /api/v1/billing | JWT |
| Shares | /api/v1/shares | JWT |
| Members | /api/v1/organizations/:orgId/members | JWT (admin for writes) |
| Invitations | /api/v1/organizations/:orgId/invitations | JWT (admin) |
| Proxy, OpenAI | /proxy/openai/v1/* | API key (full) |
| Proxy, Anthropic | /proxy/anthropic/v1/* | API key (full) |
| Proxy, Gemini | /proxy/gemini/v1/* | API key (full) |
| Proxy, Azure OpenAI | /proxy/azure/* | API key (full) |
| Proxy, Mistral | /proxy/mistral/* | API key (full) |
| Proxy, OpenRouter | /proxy/openrouter/* | API key (full) |
| Proxy, Groq | /proxy/groq/* | API key (full) |
| Proxy, DeepSeek | /proxy/deepseek/* | API key (full) |
| Proxy, xAI | /proxy/xai/* | API key (full) |
| Proxy, Cohere | /proxy/cohere/* | API key (full) |
| SDK Ingest | /ingest/* | API key (full) |
| OTLP traces | POST /v1/traces | API key (full) |
For the full interactive spec, request/response schemas, try-it-out, example curl commands, open the Swagger UI.
Plan-gated responses to know about
A few endpoints respond with HTTP 402 Payment Required when a plan limit is hit, so your client can distinguish "you ran out of headroom" from a generic 400/403:
POST /api/v1/organizationsreturns 402 with{ "code": "workspace_limit_reached", "error": "…", "owned": N, "limit": M, "effectivePlan": "…" }when the caller already owns the maximum workspaces their effective plan allows (Free 1, Pro 2, Team 5, Enterprise unlimited). Upgrade any owned workspace and retry. See Billing & quotas for the full per-plan table.