API Reference
The Amurg Hub exposes a RESTful HTTP API for authentication, session management, message retrieval, file transfer, and administration. All endpoints return JSON. Real-time streaming is handled over WebSocket (see the WebSocket Protocol docs).
Base URL
All API paths are relative to the hub's configured address, e.g. https://hub.example.com.
Authentication
Authenticated endpoints require a Bearer token in the Authorization header. Tokens are obtained via the login endpoint (builtin auth) or from an external provider (Clerk).
Authorization: Bearer <jwt-token>
Admin endpoints additionally require the authenticated user to have the admin role.
Health & Readiness
Liveness probe. Returns uptime.
{ "status": "ok", "uptime": "4h32m10s" } Readiness probe. Pings the database and returns ready status.
// 200 OK
{ "status": "ready" }
// 503 Service Unavailable
{ "status": "not_ready", "error": "db ping failed" } Auth Endpoints
Returns the configured auth provider. No authentication required.
{ "provider": "builtin" } Authenticate with username and password. Only available when provider is 'builtin'. Rate limited to 5 req/s per IP.
Request body:
{ "username": "admin", "password": "admin" } Response:
{ "token": "eyJhbGciOiJIUzI1NiIs..." } Returns the authenticated user's identity.
{ "id": "user-uuid", "username": "admin", "role": "admin" } Endpoints
List agent endpoints visible to the current user. When default_endpoint_access is 'none', non-admin users only see explicitly permitted endpoints.
[
{
"id": "ep-uuid",
"runtime_id": "rt-uuid",
"org_id": "default",
"profile": "claude-code",
"name": "Claude Code (prod)",
"tags": "{}",
"caps": "{"native_session_ids":false,"turn_completion":true,"resume_attach":false,"exec_model":"interactive"}",
"security": "{"permission_mode":"strict","allowed_tools":["Bash","Read"]}",
"online": true
}
] Sessions
Create a new session on an endpoint. Checks endpoint permissions and max session limits.
Request body:
{ "endpoint_id": "ep-uuid" } Response (201 Created):
{
"id": "session-uuid",
"endpoint_id": "ep-uuid",
"user_id": "user-uuid",
"state": "active",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
} List all sessions owned by the current user.
[
{
"id": "session-uuid",
"endpoint_id": "ep-uuid",
"user_id": "user-uuid",
"state": "active",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:32:00Z"
}
] Fetch message history for a session. Supports pagination via query params. Verifies session ownership (owner or admin).
Query parameters:
| Param | Default | Description |
|---|---|---|
limit | 100 | Max messages to return (capped at 500) |
after_seq | 0 | Return messages with sequence number greater than this |
[
{
"id": "msg-uuid",
"session_id": "session-uuid",
"seq": 1,
"direction": "user",
"channel": "stdin",
"content": "Hello, agent!",
"ts": "2024-01-15T10:30:05Z"
},
{
"id": "msg-uuid-2",
"session_id": "session-uuid",
"seq": 2,
"direction": "agent",
"channel": "stdout",
"content": "Hello! How can I help you?",
"ts": "2024-01-15T10:30:06Z"
}
] Close a session. Only the session owner can close it. Broadcasts session.closed to WebSocket subscribers.
{ "status": "closed" } File Transfer
Upload a file to a session. Multipart form data with a 'file' field. Max 10MB by default. The hub stores the file and forwards it to the runtime as a base64-encoded WebSocket message.
Response (201 Created):
{
"file_id": "file-uuid",
"name": "input.csv",
"mime_type": "text/csv",
"size": 1024
} Download a file by its ID. Returns the file with appropriate Content-Type and Content-Disposition headers.
Returns the binary file content with headers:
Content-Type: text/csv
Content-Disposition: attachment; filename="output.csv" WebSocket Endpoints
Runtime WebSocket connection. Authentication is handled inside the connection via the runtime.hello message. See the WebSocket Protocol docs.
The runtime sends a runtime.hello message immediately after connecting, which includes the runtime token and endpoint registrations.
Client WebSocket connection. The JWT token is sent as a query parameter or in the first message. See the WebSocket Protocol docs.
Used for real-time message streaming, session subscriptions, permission prompts, and session state updates.
Admin Endpoints
Admin Required
All endpoints in this section require the admin role.
Runtimes & Users
List all registered runtimes with their online/offline status.
[
{
"id": "rt-uuid",
"org_id": "default",
"name": "prod-runtime",
"online": true,
"last_seen": "2024-01-15T10:30:00Z"
}
] List all users in the organization. Password hashes are stripped from the response.
[
{
"id": "user-uuid",
"org_id": "default",
"username": "admin",
"role": "admin",
"created_at": "2024-01-15T10:00:00Z"
}
] Create a new user. Only available with builtin auth provider. Username: 3-64 chars, password: 8-128 chars.
Request body:
{ "username": "alice", "password": "secure-password", "role": "user" } Permissions
Grant a user access to an endpoint. Only relevant when default_endpoint_access is 'none'.
{ "user_id": "user-uuid", "endpoint_id": "ep-uuid" } Revoke a user's access to an endpoint.
{ "user_id": "user-uuid", "endpoint_id": "ep-uuid" } List endpoint IDs a user has been granted access to.
{ "user_id": "user-uuid", "endpoint_ids": ["ep-uuid-1", "ep-uuid-2"] } Session Administration
List all sessions across all users in the organization.
Returns the same format as /api/sessions but includes sessions from all users.
Force-close any session. Logs a session.admin_close audit event.
{ "status": "closed" } Endpoint Configuration
List all endpoints with runtime info, security config, and any hub-side config overrides.
[
{
"id": "ep-uuid",
"org_id": "default",
"runtime_id": "rt-uuid",
"runtime_name": "prod-runtime",
"runtime_online": true,
"profile": "claude-code",
"name": "Claude Code (prod)",
"tags": {},
"caps": { "turn_completion": true, "exec_model": "interactive" },
"security": { "permission_mode": "strict" },
"config_override": null
}
] Get the hub-side config override for an endpoint.
{
"endpoint_id": "ep-uuid",
"org_id": "default",
"security": "{}",
"limits": "{}",
"updated_by": "user-uuid",
"updated_at": "2024-01-15T12:00:00Z"
} Set or update a hub-side config override for an endpoint. The override is pushed to the connected runtime in real-time.
Request body:
{
"security": {
"permission_mode": "strict",
"allowed_tools": ["Bash", "Read", "Write"],
"allowed_paths": ["/home/user/project"],
"denied_paths": ["/etc", "/root"]
},
"limits": {
"max_sessions": 5,
"session_timeout": "1h",
"idle_timeout": "10m"
}
} Response:
{ "status": "saved", "pushed_to_runtime": true } Audit Log
Query audit events with optional filtering. Supports pagination and prefix-match on action.
Query parameters:
| Param | Default | Description |
|---|---|---|
limit | 50 | Max events to return (capped at 500) |
offset | 0 | Number of events to skip for pagination |
action | - | Filter by action prefix (e.g. permission. matches all permission events) |
session_id | - | Filter by exact session ID |
endpoint_id | - | Filter by exact endpoint ID |
Response:
[
{
"id": "audit-uuid",
"org_id": "default",
"action": "permission.granted",
"user_id": "user-uuid",
"session_id": "session-uuid",
"endpoint_id": "ep-uuid",
"detail": { "request_id": "req-uuid", "tool": "Bash" },
"created_at": "2024-01-15T10:31:05Z"
}
] Event types:
| Action | Description |
|---|---|
login.success | Successful user authentication |
login.failed | Failed authentication attempt |
message.sent | User sent a message to a session |
session.create | New session created |
session.stop | Session stopped |
session.idle_close | Session closed due to idle timeout |
runtime.connect | Runtime connected to the hub |
runtime.disconnect | Runtime disconnected from the hub |
turn.completed | Agent turn completed (detail includes duration_ms, optional exit_code) |
permission.requested | Agent requested tool permission |
permission.granted | User approved tool permission |
permission.denied | User denied tool permission |
permission.timeout | Permission request timed out (auto-denied after 60s) |
Structured Detail
The detail field is a json.RawMessage (structured JSON object, not a string). The endpoint_id and org_id fields are available as top-level properties on every audit event.
Examples
Login and create a session
# Login
TOKEN=$(curl -s -X POST http://localhost:8090/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r .token)
# List endpoints
curl -s http://localhost:8090/api/endpoints \
-H "Authorization: Bearer $TOKEN" | jq .
# Create session
SESSION=$(curl -s -X POST http://localhost:8090/api/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"endpoint_id":"my-endpoint-id"}' | jq -r .id)
# Get messages
curl -s "http://localhost:8090/api/sessions/$SESSION/messages?limit=50" \
-H "Authorization: Bearer $TOKEN" | jq . Upload a file
curl -X POST "http://localhost:8090/api/sessions/$SESSION/files" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@/path/to/input.csv" Query audit log for permission events
curl -s "http://localhost:8090/api/admin/audit?action=permission.&limit=20" \
-H "Authorization: Bearer $TOKEN" | jq . Error Responses
All errors return a JSON body with a single error field:
{ "error": "invalid credentials" } | Status | Meaning |
|---|---|
| 400 | Bad request (invalid body, validation failure) |
| 401 | Missing or invalid authentication token |
| 403 | Forbidden (insufficient role or no endpoint access) |
| 404 | Resource not found |
| 409 | Conflict (e.g. duplicate username) |
| 429 | Rate limited |
| 500 | Internal server error |