/api/admin expose admin operations for users, models, providers, keys, comparisons, votes, threads and messages, plus dashboard metrics. Each one carries [Authorize(Policy = "AdminOnly")]. model_leaderboard, system_settings and telegram_sessions have no admin routes; change them in Supabase.
Access
401: no token, or the token failed validation.403: valid token, butpublic.users.roleisn’tadmin.GET /api/admin/dashboard/healthis the cheap way to check both. The admin panel calls it right after sign-in.
Resources
Dashboard
Metrics, provider health, recent activity
Users
Users and roles
AI models
Catalog and status
Providers
Provider registry
API keys
Key pool, toggles, cooldowns
Comparisons
Battles
Votes
Votes and statistics
Threads
Threads and visibility
Messages
Thread messages
Lists and paging
Paginated routes (/users, /models, /keys, /comparisons, /votes, /threads and /messages) take page (from 1) and pageSize (1 to 500, default 50) and return the matching row count as total. /providers and /models/active are unpaged and return total only; active models are sorted by model_name.
search and the filters (role, status, provider, visibility, userId, modelId, comparisonId, threadId, isRevealed) combine with AND.
Behaviours to know
PUT writes every field
PUT writes every field
PUT /users/{id}, /models/{id}, /providers/{name} and /threads/{id} serialize the whole request DTO, so any field you leave out is stored as null. Read the record, change what you need, send it all back. Use the PATCH routes to change a single field (role, status, visibility, key state). PUT /keys/{keyId} is the exception: it only writes the fields you send.IDs, not names
IDs, not names
Comparisons and votes return
model1_id, model2_id, winner_model_id and user_id. Resolve names with GET /models and GET /users.Database errors pass through
Database errors pass through
When PostgREST rejects a write (a foreign key, a duplicate) the route returns
400 with the PostgREST JSON as a string in error. Parse it if you want the message field.Provider and key changes apply immediately
Provider and key changes apply immediately
Every write to
/providers and /keys refreshes the API’s in-memory provider cache. Model changes don’t touch the model cache, which refreshes within five minutes.Users: rows, not accounts
Users: rows, not accounts
POST /users and DELETE /users/{id} work on public.users only. Supabase Auth accounts are created by signing up and removed in Supabase.Raw inserts for votes, threads and messages
Raw inserts for votes, threads and messages
POST /votes, /threads and /messages insert rows directly, without the arena’s checks. Use them for repairs and test data in non-production environments; the admin panel doesn’t expose them.Ignore health.redis
Ignore health.redis
The dashboard’s
health.redis is always offline; there is no Redis.Outside this API
The admin panel’s Email page calls the Supabase Edge Functionsend-admin-email ({ emails, subject, title, html } → { sent, failed }), not this API. Feature flags can be read with GET /api/settings/feature-flag/{key} but are changed in the system_settings table.