| title | Management API |
|---|---|
| sidebar_position | 3 |
The management API is used by the dashboard and CLI. All endpoints require a JWT session token.
Base URL: http://localhost:3000/api
Authentication: Authorization: Bearer <jwt>
Obtain a JWT via POST /api/auth/login.
POST /api/auth/login
{ "email": "admin@example.com", "password": "your-password" }Response:
{
"token": "eyJ...",
"refreshToken": "a3f8c2...",
"user": { "id": "uuid", "email": "admin@example.com", "role": "admin", "permissions": [] }
}token— short-lived JWT (1 hour). Use asAuthorization: Bearer <token>on all other endpoints.refreshToken— opaque token used to obtain new access tokens without re-entering credentials. Store securely; see POST /api/auth/refresh. Rotates on every use.
POST /api/auth/refresh
This endpoint is public (no Authorization header required).
{ "refreshToken": "a3f8c2..." }Response:
{
"token": "eyJ...",
"refreshToken": "b9d4e1...",
"user": { "id": "uuid", "email": "admin@example.com", "role": "admin", "permissions": [] }
}Issues a new 1-hour access token and a new refresh token (rotation). The previous refresh token is immediately invalidated — replace it with the value returned in the response. Returns 401 if the token is invalid or has already been used/revoked.
:::note
The CLI and dashboard perform this refresh automatically — the CLI tries silently when the token expires or is within 5 minutes of expiry; the dashboard retries on any 401 response. Both clients persist the new refresh token automatically.
:::
GET /api/setup/status
Returns { "configured": false } if no admin account exists yet; { "configured": true } otherwise.
POST /api/setup/first-admin
Only available when configured: false.
{ "email": "admin@example.com", "password": "secure-password" }GET /api/me
PUT /api/me
{ "email": "new@example.com", "currentPassword": "old", "newPassword": "new" }GET /api/models
POST /api/models
{
"id": "gpt-5-mini",
"provider": "openai",
"apiKey": "sk-...",
"inputPrice": 0.25,
"outputPrice": 2.0,
"contextWindow": 128000,
"capabilities": ["functionCalling", "json"]
}GET /api/models/:id
PUT /api/models/:id
DELETE /api/models/:id
POST /api/models/:id/apikey
{ "apiKey": "sk-NEW_KEY" }GET /api/projects
POST /api/projects
{
"name": "My App",
"slug": "my-app",
"defaultTimeoutMs": 30000,
"models": ["gpt-5-mini"]
}GET /api/projects/:slug
PUT /api/projects/:slug
DELETE /api/projects/:slug
GET /api/projects/:slug/tokens
POST /api/projects/:slug/tokens
{
"name": "production",
"limits": [
{
"metric": "cost",
"limit": 10.00,
"window": "monthly",
"mode": "extend"
}
]
}Response includes the token value in plain text — returned once only.
PUT /api/projects/:slug/tokens/:tokenId
DELETE /api/projects/:slug/tokens/:tokenId
GET /api/projects/:slug/members
POST /api/projects/:slug/members
{ "userId": "user-uuid", "role": "viewer" }PUT /api/projects/:slug/members/:userId
{ "role": "editor" }DELETE /api/projects/:slug/members/:userId
GET /api/users
POST /api/users
{ "email": "user@example.com", "password": "password", "role": "operator" }GET /api/users/:id
PUT /api/users/:id
DELETE /api/users/:id
GET /api/roles
POST /api/roles
{
"name": "billing_reviewer",
"permissions": ["project:read", "report:read"]
}PUT /api/roles/:name
DELETE /api/roles/:name
GET /api/usage
Query parameters:
| Parameter | Type | Description |
|---|---|---|
from |
ISO date | Start of range |
to |
ISO date | End of range |
project |
string | Filter by project slug |
model |
string | Filter by model ID |
outcome |
string | success, error, budget_exceeded |
limit |
number | Max records to return (default: 100) |
offset |
number | Pagination offset |
GET /api/usage/:id
Returns the full record including the routing trace.
GET /api/settings
PUT /api/settings
{
"port": 3000,
"logLevel": "info",
"defaultTimeoutMs": 30000,
"publicUrl": "https://routerly.example.com"
}POST /api/notifications/test
{ "channelName": "my-smtp" }Returns 200 OK on success or an error with details.
GET /api/system/info
Response:
{
"version": "1.2.3",
"uptime": 3600,
"node": "v22.0.0",
"platform": "darwin/arm64"
}