Docs / Admin API
Admin API Reference
REST API for managing proxies, consumers, plugins, and upstreams. Available in Database and Control Plane modes.
Authentication
All Admin API endpoints except /health, /status, and /metrics require a JWT in the
Authorization: Bearer <token> header. Tokens are verified against
your FERRUM_ADMIN_JWT_SECRET using HS256.
bash — generate JWT (example)
# Using jwt-cli (npm install -g jwt-cli)
jwt sign --secret "your-admin-jwt-secret" --expires 3600
# Or with curl + jq (generate manually)
# For production, use your auth service to issue admin tokens
bash — example request with auth
curl -H "Authorization: Bearer <your-jwt-token>" \
http://localhost:9000/proxies
In file mode (or when read-only mode is enabled), the Admin API is read-only. Write operations return
403 Forbidden.
Use Database or Control Plane mode for dynamic configuration management.
Unauthenticated Endpoints
| Method | Path | Description | Use for |
|---|---|---|---|
| GET | /health |
Basic liveness check. Returns 200 if the process is running. | Kubernetes livenessProbe |
| GET | /status |
Readiness check (alias for /health). Returns 200 when config is loaded. | Kubernetes readinessProbe |
| GET | /metrics |
Prometheus exposition format metrics. No auth required for scraping. | Prometheus scrape target |
API Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /proxies | List all proxy configurations |
| POST | /proxies | Create a new proxy |
| GET | /proxies/:id | Get a specific proxy by ID |
| PUT | /proxies/:id | Update a proxy configuration |
| DELETE | /proxies/:id | Delete a proxy |
| GET | /consumers | List all consumers |
| POST | /consumers | Create a new consumer |
| GET | /consumers/:id | Get a consumer by ID |
| PUT | /consumers/:id | Update a consumer |
| DELETE | /consumers/:id | Delete a consumer |
| PUT | /consumers/:id/credentials/:type | Update consumer credentials for a given type |
| DELETE | /consumers/:id/credentials/:type | Delete consumer credentials for a given type |
| GET | /plugins | List available plugin types |
| GET | /plugins/config | List all plugin configurations |
| POST | /plugins/config | Create a plugin config |
| GET | /plugins/config/:id | Get a plugin config by ID |
| PUT | /plugins/config/:id | Update a plugin config |
| DELETE | /plugins/config/:id | Delete a plugin config |
| GET | /upstreams | List all upstream configurations |
| POST | /upstreams | Create an upstream |
| GET | /upstreams/:id | Get an upstream by ID |
| PUT | /upstreams/:id | Update an upstream |
| DELETE | /upstreams/:id | Delete an upstream |
| GET | /admin/metrics | Comprehensive runtime metrics snapshot (JSON) |
| GET | /backup | Export full configuration as JSON |
| POST | /restore | Restore configuration from JSON backup (destructive) |
| POST | /batch | Batch create multiple resources in one request |
Request & Response Examples
Create a Proxy
bash
curl -X POST http://localhost:9000/proxies \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"listen_path": "/my-api",
"backend_protocol": "http",
"backend_host": "api-backend",
"backend_port": 3000,
"strip_listen_path": true,
"plugin_config_ids": [
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
]
}'
json — response
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"listen_path": "/my-api",
"backend_protocol": "http",
"backend_host": "api-backend",
"backend_port": 3000,
"strip_listen_path": true,
"plugin_config_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
Create a Consumer
bash
curl -X POST http://localhost:9000/consumers \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "mobile-app",
"custom_id": "app-v2",
"credentials": {
"key_auth": {
"key": "sk-live-abc123def456"
},
"jwt_auth": {
"subject": "mobile-app"
}
}
}'
Create an Upstream
bash
curl -X POST http://localhost:9000/upstreams \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "api-backend-pool",
"algorithm": "least_connections",
"targets": [
{ "host": "api-1.internal", "port": 3000, "weight": 100 },
{ "host": "api-2.internal", "port": 3000, "weight": 100 },
{ "host": "api-3.internal", "port": 3000, "weight": 50 }
],
"health_check": {
"enabled": true,
"type": "http",
"path": "/health",
"interval_seconds": 10,
"timeout_seconds": 3,
"healthy_threshold": 2,
"unhealthy_threshold": 3
}
}'
Batch Operations
bash
curl -X POST http://localhost:9000/batch \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{ "method": "POST", "path": "/proxies", "body": { "name": "proxy-a", ... } },
{ "method": "POST", "path": "/consumers", "body": { "username": "consumer-1", ... } },
{ "method": "PUT", "path": "/upstreams/upstr_123", "body": { ... } }
]
}'
Error Handling
| HTTP Status | Meaning | Common Cause |
|---|---|---|
| 400 | Bad Request | Invalid JSON, missing required fields, validation error |
| 401 | Unauthorized | Missing or invalid JWT token |
| 403 | Forbidden | Admin API is in read-only mode (file mode or read-only flag enabled) |
| 404 | Not Found | Resource with specified ID doesn't exist |
| 409 | Conflict | Resource name already exists |
| 500 | Internal Server Error | Database error, unexpected failure |
json — error response format
{
"error": "Field 'listen_path' is required"
}