DevPlace Admin API
Administrator endpoints for users, roles, media, audit log, analytics and statistics, AI quota rules and resets, news curation, settings, bot fleet inspection, Devii tasks, backups and schedules, and Code Farm era control.
Site administration endpoints for users, news curation, and settings. Every call requires an admin account. Background service management lives on the Background Services page.
Every endpoint follows the shared Conventions & Errors (auth, content negotiation, pagination, status codes); see Authentication for the four ways to sign requests.
GET /admin/users - List users
Paginated user management page. Returns HTML.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | int | no | Page number. |
Sample response
{
"users": [
{
"uid": "UID",
"username": "username",
"avatar_seed": "string",
"bio": "text",
"location": "string",
"git_link": "string",
"website": "string",
"level": 0,
"xp": 0,
"xp_progress_pct": 0,
"xp_next_level": 0,
"stars": 0,
"created_at": "2026-01-01T00:00:00+00:00",
"last_seen": "string",
"role": "string",
"email": "user@example.com",
"is_active": false,
"posts_count": 0
}
],
"pagination": null,
"admin_section": "string"
}
GET /admin/media - Media trash
Moderation view of deleted media. When a member or admin deletes an attachment it is soft-deleted: hidden from the gallery and from its parent object, but the row and file are kept and the relation to the parent is preserved. This page lists every soft-deleted attachment, newest first, with its uploader, so an admin can restore or permanently purge it. Returns HTML.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | int | no | Page number. |
POST /media/{uid}/restore - Restore media
Restore a soft-deleted attachment. Because the parent relation is never cleared, it reappears in the owner's Media tab and on its original post, project, or gist immediately.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Soft-deleted attachment uid. |
Sample response
{
"ok": true,
"redirect": "/admin/media"
}
POST /admin/awards/{uid}/revoke - Revoke award
Soft-delete a published award and its linked attachments, then recompute receiver stats. Restorable from admin trash.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Award uid to revoke. |
Sample response
{
"ok": true,
"redirect": "/profile/receiver?tab=awards"
}
POST /admin/media/{uid}/purge - Purge media
Permanently delete a soft-deleted attachment: removes the database row and deletes the file from disk. This cannot be undone and is the only way media is hard-deleted from the UI.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Attachment uid to purge. |
Sample response
{
"ok": true,
"redirect": "/admin/media"
}
GET /admin/audit-log - Audit log
Paginated, filterable audit event list (newest first, 25 per page). Negotiates HTML or JSON. Every state-changing action on the platform is recorded here with actor, origin, target, change, and result.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | int | no | Page number. |
event_key | query | string | no | Filter by exact event key. |
category | query | string | no | Filter by category (auth, content, admin, container, ...). |
actor_role | query | string | no | Filter by actor role at action time. |
actor_uid | query | string | no | Filter by acting user uid. |
origin | query | string | no | Filter by origin (web, api, devii, cli, service, scheduler). |
result | query | string | no | Filter by result (success, failure, denied). |
q | query | string | no | Free-text search over summary, event key, and target. |
date_from | query | string | no | ISO date lower bound (inclusive). |
date_to | query | string | no | ISO date upper bound (inclusive). |
Sample response
{
"entries": [
{
"uid": "AUDIT_UID",
"created_at": "2026-06-11T20:00:00+00:00",
"event_key": "admin.setting.update",
"category": "admin",
"actor_username": "ADMIN",
"actor_role": "admin",
"origin": "web",
"via_agent": 0,
"target_type": "setting",
"old_value": "0",
"new_value": "1",
"result": "success"
}
],
"pagination": {
"page": 1,
"total": 1,
"total_pages": 1
},
"filters": {},
"options": {
"category": [
"admin",
"auth",
"content"
]
}
}
GET /admin/audit-log/{uid} - Audit event
A single audit event with its full row and every related-object link.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Audit event uid. |
Sample response
{
"event": {
"uid": "AUDIT_UID",
"event_key": "container.instance.start",
"result": "success"
},
"links": [
{
"relation": "actor",
"object_type": "user",
"object_uid": "USER_UID"
},
{
"relation": "instance",
"object_type": "instance",
"object_uid": "INSTANCE_UID"
}
]
}
GET /admin/analytics - Site analytics
One-call aggregate analytics, returned as JSON: total members, active users in the last 24h/7d/30d, signedinnow, new signups (24h/7d/30d), content totals (posts, comments, gists, projects, news), and top authors. Use this instead of paging the user list to count or measure activity.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
top_n | query | int | no | How many top authors to include (1-50). |
signedinnowcounts members holding an unexpired session (logged in within the session lifetime, default 7-30 days), not a real-time online/presence count; the response carries asignedindefinitionexplaining this.active*means created content in the window (activedefinition).
This is the endpoint the Devii assistant calls as
site_analytics; see Devii internals.
GET /admin/statistics/data - Platform statistics
Tabbed platform statistics with KPI cards, period-over-period deltas, time-series data for charts, and breakdown tables. Covers visitors, members, content, engagement, social, AI, Devii, services, containers, game, awards, moderation, tools, and storage.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tab | query | string | no | Tab key (overview, visitors, members, content, ...). |
hours | query | int | no | Lookback window in hours (24, 168, 720, 2160, or 0 for all time). |
compare | query | int | no | Include previous-period comparison (1 or 0). |
top_n | query | int | no | Rows in breakdown tables (1-50). |
The HTML dashboard lives at
/admin/statistics. Visitor metrics require the statistics tracking middleware (hourly aggregation, 90-day retention).
GET /admin/statistics - Statistics dashboard
Admin HTML dashboard for platform statistics with charts and tabs.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tab | query | string | no | Initial tab to render. |
hours | query | int | no | Initial time window in hours. |
GET /admin/ai-usage/data - AI gateway usage analytics
One-call AI gateway metrics, returned as JSON for a bounded time window: request volume and throughput, token usage with averages and percentiles (p50/p90/p95/p99), latency (upstream, gateway overhead, queue wait, connection establishment), error rates by category, cost in USD (per model, per caller, input vs output, projected monthly burn, caching savings), caller behavior, and an hourly breakdown. Cost is taken from the upstream native cost when present (OpenRouter) and computed from the configured per-million pricing otherwise (DeepSeek).
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
hours | query | int | no | Lookback window in hours (1-168). |
top_n | query | int | no | How many rows in each top-N breakdown. |
TTFT and inter-token latency are not reported: the gateway forwards non-streaming to the upstream.
GET /admin/users/{uid}/ai-usage - Per-user AI usage
One user's AI gateway usage over the last 24 hours, returned as JSON: request volume, success and error rates, token totals, cost (window, per hour, per request, and a 30-day projection from the full 24h spend), average latency and throughput, a per-model breakdown, and an hourly cost series. Because Devii operates a signed-in user's account with that user's own API key, this is the user's complete gateway spend, whether driven through Devii or direct API calls. Shown admin-only on the user's profile page.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Target user UID. |
hours | query | int | no | Lookback window in hours (1-168). |
Sample response
{
"owner_id": "USER_UID",
"window_hours": 24,
"requests": 42,
"success": 41,
"failed": 1,
"success_pct": 97.6,
"error_pct": 2.4,
"tokens": {
"prompt": 120000,
"completion": 38000,
"total": 158000
},
"cost": {
"window_usd": 0.214,
"per_hour_usd": 0.0089,
"per_request_usd": 0.0051,
"projected_30d_usd": 6.42
},
"latency": {
"avg_ms": 1830.0,
"avg_tps": 41.2
},
"by_model": [
{
"key": "molodetz",
"requests": 42,
"total_tokens": 158000,
"cost_usd": 0.214
}
],
"hourly": [
{
"hour": "2026-06-08T16",
"requests": 6,
"cost_usd": 0.031,
"total_tokens": 22000
}
]
}
POST /admin/users/{uid}/role - Set a user role
Promote or demote a user. You cannot change your own role.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Target user UID. |
role | form | enum | yes | New role. Allowed: member, admin. |
Sample response
{
"ok": true,
"redirect": "/admin/users",
"data": null
}
POST /admin/users/{uid}/password - Reset a user password
Set a new password for a user.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Target user UID. |
password | form | string | yes | New password, 6+ characters. |
Sample response
{
"ok": true,
"redirect": "/admin/users",
"data": null
}
POST /admin/users/{uid}/toggle - Enable or disable a user
Toggle a user's active state. You cannot disable yourself.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Target user UID. |
Sample response
{
"ok": true,
"redirect": "/admin/users",
"data": null
}
GET /admin/news - List news articles
Paginated news management page. Returns HTML.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | int | no | Page number. |
Sample response
{
"articles": [
{
"article": {
"uid": "UID",
"slug": "slug",
"title": "Title",
"description": "text",
"content": "text",
"url": "/path",
"source_name": "string",
"author": "string",
"grade": 0,
"ai_grade": 0,
"status": "published",
"image_url": "/path",
"featured": 0,
"has_unique_image": 0,
"article_published": "string",
"created_at": "2026-01-01T00:00:00+00:00",
"synced_at": "2026-01-01T00:00:00+00:00"
},
"time_ago": "2 hours ago",
"synced_at": "2026-01-01T00:00:00+00:00",
"grade": 0,
"has_image": false
}
],
"pagination": null,
"admin_section": "string"
}
POST /admin/news/{uid}/toggle - Toggle featured
Toggle an article's featured flag and lock it from the news service's auto-rotation.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Article UID. |
Sample response
{
"ok": true,
"redirect": "/admin/news",
"data": null
}
POST /admin/news/{uid}/publish - Toggle published
Switch an article between draft and published.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Article UID. |
Sample response
{
"ok": true,
"redirect": "/admin/news",
"data": null
}
POST /admin/news/{uid}/landing - Toggle landing
Toggle whether an article shows on the landing page and lock it from the news service's auto-rotation.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Article UID. |
Sample response
{
"ok": true,
"redirect": "/admin/news",
"data": null
}
POST /admin/news/{uid}/delete - Delete a news article
Delete an article and its images.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Article UID. |
Sample response
{
"ok": true,
"redirect": "/admin/news",
"data": null
}
GET /admin/settings - Read site settings
Return the current site and operational settings. Negotiates HTML or JSON.
Minimal role: Admin
Sample response
{
"settings": {},
"admin_section": "string"
}
POST /admin/settings - Save site settings
Update operational and site settings. Empty fields are skipped.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
site_name | form | string | no | Site name. |
ratelimitper_minute | form | string | no | Requests per window. |
registration_open | form | enum | no | Allow signups. Allowed: 1, 0. |
maintenance_mode | form | enum | no | Maintenance gate. Allowed: 1, 0. |
Accepts every field on the admin settings form; only non-empty values are written.
Sample response
{
"ok": true,
"redirect": "/admin/settings",
"data": null
}
POST /admin/notifications - Set a notification default
Set the platform-wide default for one notification type on one channel. Applies to users who have not customized that notification; explicit user choices are unaffected.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
notification_type | form | string | yes | One of: comment, reply, mention, vote, follow, message, badge, level, issue, reminder, harvest_stolen. |
channel | form | string | yes | One of in_app, push or telegram (telegram is off by default and requires a paired Telegram account). |
value | form | boolean | no | 1 to enable this notification by default, 0 to disable. |
Sample response
{
"ok": true,
"redirect": "/admin/notifications",
"data": {
"notification_type": "vote",
"channel": "push",
"value": false
}
}
POST /admin/users/{uid}/reset-ai-quota - Reset user AI quota
Delete a specific user's AI gateway ledger rows, resetting their quota.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Target user UID. |
POST /admin/ai-quota/reset-guests - Reset guest AI quotas
Reset AI quota for all anonymous guest users.
Minimal role: Admin
POST /admin/ai-quota/reset-all - Reset all AI quotas
Reset AI quota for every user (members and guests).
Minimal role: Admin
GET /admin/gateway/quota-rules - List AI gateway quota rules
List every rolling-24h USD quota rule on /openai/v1/*, each scoped by any combination of role, specific user uid, and app_reference label, plus the global per-role default caps that apply when no rule matches.
Minimal role: Admin
POST /admin/gateway/quota-rules - Create or update an AI gateway quota rule
Caps rolling-24h USD spend on /openai/v1/*. At least one of ownerkind, ownerid, app_reference must be set; leaving a dimension blank makes it a wildcard, and the most specific active match wins over other rules and over the global default. Pass uid to update an existing rule.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | json | string | no | Existing rule uid to update; omit to create a new rule. |
owner_kind | json | string | no | internal, key, user, admin, or anonymous. Blank = any role. |
owner_id | json | string | no | Specific user uid. Blank = any caller of the matched role. |
app_reference | json | string | no | App label (the X-App-Reference header). Blank = any app. |
limit_usd | json | number | yes | Rolling 24h USD cap. 0 = unlimited. |
is_active | json | boolean | no | Whether the rule is enforced. |
label | json | string | no | Optional admin-facing note. |
POST /admin/gateway/quota-resets - Reset the AI gateway 24h spend
Clear the counted rolling-24h spend for a scope so a capped caller can call again, without deleting any usage history (the cost analytics stay intact). Scope it exactly like a quota rule; leaving all three dimensions blank resets every caller. Only spend recorded before the reset is cleared - new calls count again immediately against the same limit.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
owner_kind | json | string | no | internal, key, user, admin, or anonymous. Blank = every role. |
owner_id | json | string | no | Specific user uid. Blank = every caller. |
app_reference | json | string | no | App label (the X-App-Reference header). Blank = every app. |
DELETE /admin/gateway/quota-rules/{uid} - Delete an AI gateway quota rule
Delete a quota rule; callers it covered fall back to the next most specific rule or the global default.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Quota rule uid. |
GET /admin/bots - Bot monitor page
Live low-quality screenshot grid of every running bot persona, one frame per bot.
Minimal role: Admin
Sample response
{
"frames": [
{
"slot": 0,
"username": "username",
"persona": "string",
"action": "string",
"status": "published",
"url": "/path",
"label": "string",
"captured_at": 0,
"age_seconds": 0,
"has_image": false,
"active": false,
"frame_url": "/path"
}
],
"enabled": false,
"service_status": "published",
"admin_section": "string",
"user": null
}
GET /admin/bots/data - Bot monitor data
JSON of every running bot slot with its label, persona, current action/status, and latest frame URL for polling.
Minimal role: Admin
Sample response
{
"enabled": true,
"service_status": "running",
"frames": [
{
"slot": 0,
"username": "bytewren",
"persona": "grumpy_senior",
"action": "POST: rant [3]",
"status": "page load",
"url": "https://example.com/feed",
"label": "bytewren",
"captured_at": 1718366400,
"age_seconds": 2,
"has_image": true,
"active": true,
"frame_url": "/admin/bots/0/frame.jpg?t=1718366400"
}
]
}
GET /admin/bots/{slot}/frame.jpg - Bot frame image
The latest low-quality JPEG screenshot for one bot slot (no-store).
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
slot | path | integer | yes | Bot fleet slot index. |
GET /admin/devii-tasks - Scheduled Devii tasks
Every scheduled Devii task across all owners with its schedule, run count, expiry, failure streak, and whether its owner may still schedule, plus the configured automation bounds. Returns HTML (or JSON with Accept: application/json).
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
state | query | string | no | One of active, inactive, all. |
POST /admin/devii-tasks/{uid}/disable - Disable a scheduled task
Stop one scheduled task. The row is kept and stays auditable.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Uid of the task. |
POST /admin/devii-tasks/{uid}/delete - Delete a scheduled task
Soft-delete one scheduled task; it moves to the admin trash.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Uid of the task. |
GET /admin/backups - Backups dashboard
Storage usage, every backup archive, and every backup schedule. Returns HTML (or JSON with Accept: application/json).
Minimal role: Admin
GET /admin/backups/data - Backups data
JSON dashboard payload: per-path storage usage, total data and backup size, disk usage, the backup list, and the schedule list.
Minimal role: Admin
POST /admin/backups/run - Create backup
Enqueue an async backup job for a target (database, uploads, keys, full). Returns the job uid and a status_url.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
target | form | string | yes | One of database, uploads, keys, full. |
Sample response
{
"ok": true,
"uid": "JOB_UID",
"backup_uid": "BACKUP_UID",
"status_url": "/admin/backups/jobs/JOB_UID"
}
GET /admin/backups/jobs/{uid} - Backup job status
Status of one backup job (pending, running, done, failed) with archive stats.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Backup job uid. |
Sample response
{
"uid": "JOB_UID",
"kind": "backup",
"status": "done",
"target": "full",
"backup_uid": "BACKUP_UID",
"download_url": "/admin/backups/BACKUP_UID/download",
"bytes_out": 10485760,
"file_count": 1240,
"sha256": "\u2026"
}
GET /admin/backups/{uid}/download - Download backup
Stream a completed backup archive as a tar.gz file. Restricted to the primary administrator (the first user created with the Admin role); every other administrator receives 403 Forbidden.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Backup uid. |
POST /admin/backups/{uid}/delete - Delete backup
Permanently delete a backup archive and reclaim its disk space.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Backup uid. |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
POST /admin/backups/schedules/create - Create backup schedule
Create a recurring backup. kind=interval uses everyseconds; kind=cron uses a 5-field cron expression. keeplast rotates older backups of the schedule.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | form | string | yes | Schedule name. |
target | form | string | yes | Backup target. |
kind | form | string | yes | interval or cron. |
every_seconds | form | int | no | Seconds between runs (kind=interval). |
cron | form | string | no | Cron expression (kind=cron). |
keep_last | form | int | no | Keep only the newest N (0 = all). |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
POST /admin/backups/schedules/{uid}/edit - Edit backup schedule
Update a backup schedule's target, trigger, and retention.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Schedule uid. |
name | form | string | yes | Schedule name. |
target | form | string | yes | Backup target. |
kind | form | string | yes | interval or cron. |
every_seconds | form | int | no | Seconds between runs (kind=interval). |
cron | form | string | no | Cron expression (kind=cron). |
keep_last | form | int | no | Keep only the newest N (0 = all). |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
POST /admin/backups/schedules/{uid}/toggle - Toggle backup schedule
Enable or disable a backup schedule.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Schedule uid. |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
POST /admin/backups/schedules/{uid}/run - Run backup schedule now
Immediately enqueue a backup for a schedule without waiting for its next run.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Schedule uid. |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
POST /admin/backups/schedules/{uid}/delete - Delete backup schedule
Delete a backup schedule. Existing archives are kept.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Schedule uid. |
Sample response
{
"ok": true,
"redirect": "/admin/backups"
}
GET /admin/game - Code Farm Era management
View the current Code Farm Era status.
Minimal role: Admin
Sample response
{
"era_active": false,
"era_name": ""
}
POST /admin/game/era/start - Start an Era
Start a new Code Farm Era: resets every farm's visible Era coins/harvests counters to zero. Real coins, prestige, stars, Legacy, and Mastery are never touched.
Minimal role: Admin
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | form | string | yes | Era name. |
duration_days | form | int | no | Planned Era length in days. |
Sample response
{
"ok": true,
"redirect": "/admin/game"
}
POST /admin/game/era/end - End the running Era
End the current Era: ranks every participating farm by Era score, awards Stars to the top 10 (and an Era-exclusive cosmetic when available), and permanently records the results.
Minimal role: Admin
Sample response
{
"ok": true,
"redirect": "/admin/game"
}