Skip to main content

Management API

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.


Authentication

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 as Authorization: Bearer <token> on all other endpoints.
  • refreshToken — permanent opaque token. Store securely; use it with POST /api/auth/refresh to obtain new access tokens without re-entering credentials.

Refresh

POST /api/auth/refresh

This endpoint is public (no Authorization header required).

{ "refreshToken": "a3f8c2..." }

Response:

{
"token": "eyJ...",
"user": { "id": "uuid", "email": "admin@example.com", "role": "admin", "permissions": [] }
}

Issues a new 1-hour access token. The refresh token itself is permanent and does not rotate. Returns 401 if the token is invalid or has been 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.


Setup

Check Setup Status

GET /api/setup/status

Returns { "configured": false } if no admin account exists yet; { "configured": true } otherwise.

Create First Admin

POST /api/setup/first-admin

Only available when configured: false.

{ "email": "admin@example.com", "password": "secure-password" }

Me (Current User)

Get Profile

GET /api/me

Update Profile

PUT /api/me
{ "email": "new@example.com", "currentPassword": "old", "newPassword": "new" }

Models

List Models

GET /api/models

Create Model

POST /api/models
{
"id": "gpt-5-mini",
"provider": "openai",
"apiKey": "sk-...",
"inputPrice": 0.25,
"outputPrice": 2.0,
"contextWindow": 128000,
"capabilities": ["functionCalling", "json"]
}

Get Model

GET /api/models/:id

Update Model

PUT /api/models/:id

Delete Model

DELETE /api/models/:id

Rotate Model API Key

POST /api/models/:id/apikey
{ "apiKey": "sk-NEW_KEY" }

Projects

List Projects

GET /api/projects

Create Project

POST /api/projects
{
"name": "My App",
"slug": "my-app",
"defaultTimeoutMs": 30000,
"models": ["gpt-5-mini"]
}

Get Project

GET /api/projects/:slug

Update Project

PUT /api/projects/:slug

Delete Project

DELETE /api/projects/:slug

Project Tokens

List Tokens

GET /api/projects/:slug/tokens

Create Token

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.

Update Token

PUT /api/projects/:slug/tokens/:tokenId

Delete Token

DELETE /api/projects/:slug/tokens/:tokenId

Project Members

List Members

GET /api/projects/:slug/members

Add Member

POST /api/projects/:slug/members
{ "userId": "user-uuid", "role": "viewer" }

Update Member Role

PUT /api/projects/:slug/members/:userId
{ "role": "editor" }

Remove Member

DELETE /api/projects/:slug/members/:userId

Users

List Users

GET /api/users

Create User

POST /api/users
{ "email": "user@example.com", "password": "password", "role": "operator" }

Get User

GET /api/users/:id

Update User

PUT /api/users/:id

Delete User

DELETE /api/users/:id

Roles

List Roles

GET /api/roles

Create Role

POST /api/roles
{
"name": "billing_reviewer",
"permissions": ["project:read", "report:read"]
}

Update Role

PUT /api/roles/:name

Delete Role

DELETE /api/roles/:name

Usage

Query Usage Records

GET /api/usage

Query parameters:

ParameterTypeDescription
fromISO dateStart of range
toISO dateEnd of range
projectstringFilter by project slug
modelstringFilter by model ID
outcomestringsuccess, error, budget_exceeded
limitnumberMax records to return (default: 100)
offsetnumberPagination offset

Get Usage Record

GET /api/usage/:id

Returns the full record including the routing trace.


Settings

Get Settings

GET /api/settings

Update Settings

PUT /api/settings
{
"port": 3000,
"logLevel": "info",
"defaultTimeoutMs": 30000,
"publicUrl": "https://routerly.example.com"
}

Notifications

Test a Notification Channel

POST /api/notifications/test
{ "channelName": "my-smtp" }

Returns 200 OK on success or an error with details.


System

Get System Info

GET /api/system/info

Response:

{
"version": "1.2.3",
"uptime": 3600,
"node": "v22.0.0",
"platform": "darwin/arm64"
}