Admin HTTP API

The /api/admin/* surface manages the gateway's backends (upstream model providers) and aliases (model-name → model-id redirection). It is the HTTP counterpart of the RPC management plane (see the JSON-RPC API) and is primarily used by operators and the admin UI.

Authentication

Every /api/admin/* route requires:

text
1
Authorization: Bearer $ARONA_ADMIN_TOKEN

ARONA_ADMIN_TOKEN is read from the environment at process start (GatewayServer::new). If the variable is unset, or the presented token does not match, the request is rejected with 401:

json
1
2
3
4
5
6
7
{
  "error": {
    "message": "Admin access required",
    "type": "auth_error",
    "code": "unauthorized"
  }
}

The bearer prefix is matched case-insensitively (Bearer or bearer).

Unlike the /v1/* surface, admin auth never falls back to API keys or JWTs, and it is enforced with an exact-token comparison — rotate the token by restarting the process with a new value.

Backends

Backends are the routable upstreams behind the gateway. Registration makes a backend routable immediately, persists its config for restart restore, probes it (flips healthy within ~1–2 s) and, for bridge URLs, keeps the tunnel alive. Backend types and URL semantics are detailed in Backends.

POST /api/admin/backends — register a backend

Request body (all fields optional except where noted):

FieldTypeNotes
typestringBackend kind. One of external (any OpenAI-compatible HTTP API), ollama (local or remote ollama server), engine (CEP engine over ws:///wss://), minimax-cloud (cloud video API). MDD engine names (llama_cpp, vllm, ollama, cloud, external_api, candle, native, ...) resolve through the planner. comfyui is rejected (comfyui backend removed); anything else → 400 unknown_type. Defaults to ollama when missing.
urlstringBackend base URL. evernight://<node>/<service> bridge URLs are resolved through the local evernight agent into a local TCP forward (resolution failure → 502 evernight_unreachable). Defaults to http://localhost:11434.
api_keystringOptional upstream API key, sent as Authorization: Bearer on upstream calls.
namestringBackend name. Defaults to the type value when missing. Used as the routing provider hint and for config row identity.
modelsstring[]Static model list. The routing source when probing discovers none. For external backends, discovered models are merged after the static list (static ids keep precedence); engine backends return their discovered model cache first and append static ids after; minimax-cloud performs no model discovery (its probe only health-pings /v1/query/available_models) and serves the static list alone. Ignored by ollama, which discovers models from /api/tags.
workflowobjectOptional. Legacy — historically consumed by the removed ComfyUI backend; no current backend reads it (kept for backend_configs column compatibility).

Example:

bash
1
2
3
4
5
6
7
8
9
10
curl -X POST http://192.0.2.10:8080/api/admin/backends \
  -H "Authorization: Bearer CHANGE_ME" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "external",
    "name": "mock-upstream",
    "url": "http://192.0.2.20:11434",
    "api_key": "sk-xxx",
    "models": ["Qwen/Qwen3-1.7B"]
  }'

Success → 200:

json
1
{ "status": "ok", "message": "backend registered" }

Registration side effects:

GET /api/admin/backends — list backends

json
1
2
3
4
5
6
7
8
9
10
11
12
{
  "backends": {
    "count": 2,
    "health": [
      ["backend_0:ExternalApi", "Healthy"],
      ["backend_1:Ollama", { "Unhealthy": "connection refused" }]
    ]
  },
  "models": [
    { "id": "Qwen/Qwen3-1.7B", "object": "model", "owned_by": "mock-upstream" }
  ]
}

DELETE /api/admin/backends — remove a backend

Identified by its router index in the JSON body — not by name:

bash
1
2
3
4
curl -X DELETE http://192.0.2.10:8080/api/admin/backends \
  -H "Authorization: Bearer CHANGE_ME" \
  -H "Content-Type: application/json" \
  -d '{ "index": 0 }'
FieldTypeRequiredNotes
indexintegeryesRouter registration index, matching the backend_<index> label in the GET /api/admin/backends health report.

Aliases

Aliases map one model name to another (aliastarget) so requests for one model id route to a different backend model. Aliases are resolved before routing, so they apply uniformly to chat, embeddings and video lookups.

Aliases are in-memory router state only — they are not persisted and are lost on restart. Register them after startup or recreate them from your own provisioning state.

POST /api/admin/aliases — add an alias

FieldTypeRequiredNotes
aliasstringyesThe model name clients will request.
targetstringyesThe model id requests are routed to.
bash
1
2
3
4
curl -X POST http://192.0.2.10:8080/api/admin/aliases \
  -H "Authorization: Bearer CHANGE_ME" \
  -H "Content-Type: application/json" \
  -d '{ "alias": "my-model", "target": "Qwen/Qwen3-1.7B" }'

GET /api/admin/aliases — list aliases

json
1
2
3
4
5
{
  "aliases": [
    { "alias": "my-model", "target": "Qwen/Qwen3-1.7B" }
  ]
}

Pairs are returned sorted by alias.

DELETE /api/admin/aliases — remove an alias

FieldTypeRequiredNotes
aliasstringyesThe alias to remove.
bash
1
2
3
4
curl -X DELETE http://192.0.2.10:8080/api/admin/aliases \
  -H "Authorization: Bearer CHANGE_ME" \
  -H "Content-Type: application/json" \
  -d '{ "alias": "my-model" }'

Persistence summary

ResourcePersisted?Restore on restart
BackendsYes — backend_configs table (name key, upsert on register, delete on removal).Yes: restored at startup; external backends start fail-closed and flip healthy after the first probe round. evernight:// URLs are re-resolved through the bridge at startup.
AliasesNo — in-memory Router.aliases only.No.