- Overview
- Base Configuration
- API Endpoints
- 1. Create API
- 2. Update API
- 3. Get API
- 4. List APIs
- 5. Delete API
- 6. List Endpoints
- 7. Add Endpoint
- 8. Get Endpoint
- 9. Update Endpoint
- 10. Delete Endpoint
- 11. Bulk Import
- 12. Export All
- 13. List Templates
- 14. Create from Template
- 15. Test Rule
- 16. Resolve Path
- 17. Reload Rules
- 18. Subscribe to Events
- 19. Rate Limit Check Endpoint
- Metrics API
- Configuration Reference
- Best Practices
This guide provides comprehensive documentation for testing the Admin API Management endpoints. The API allows you to dynamically register, configure, and manage APIs with rate limiting, routing, and reverse proxy capabilities.
Key Features:
- Reverse proxy with upstream URL configuration
- Sliding window rate limiting (always enabled)
- Bearer token authentication for admin endpoints
- Bot detection and IP blocking
- Real-time metrics and event streaming
- Strict HTTP method validation
- No path stripping (full paths forwarded to upstream)
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_TOKEN| Code | Description |
|---|---|
200 OK |
Successful GET/PUT request |
201 Created |
Successful POST request |
204 No Content |
Successful DELETE request |
400 Bad Request |
Invalid request body or parameters |
401 Unauthorized |
Missing or invalid admin token |
404 Not Found |
Resource not found |
405 Method Not Allowed |
HTTP method doesn't match endpoint |
409 Conflict |
Resource already exists |
500 Internal Server Error |
Server error |
Endpoint: POST /admin/apis
Creates a new API registration with routing, rate limiting, and upstream configuration.
{
"id": "user-service",
"service_id": "user-service-v1",
"name": "User Service API",
"description": "Handles user operations",
"upstream_url": "http://user-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000
},
"endpoints": [
{
"id": "get-users",
"path": "/api/users",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000
},
"priority": 10
},
{
"id": "create-user",
"path": "/api/users",
"method": "POST",
"limits": {
"requests_per_second": 20,
"burst_size": 40,
"block_duration": 600000000000
},
"priority": 20
},
{
"id": "get-user",
"path": "/api/users/{id}",
"method": "GET",
"limits": {
"requests_per_second": 60,
"burst_size": 120
},
"priority": 15
}
]
}Field Details:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | - | Unique API identifier |
service_id |
string | Yes | - | Service grouping identifier |
name |
string | No | - | Human-readable name |
description |
string | No | - | API description |
upstream_url |
string | Yes | - | Backend server URL |
status |
string | No | "active" | active, maintenance, deprecated, disabled |
default_limits |
object | No | - | Default rate limits for all endpoints |
endpoints |
array | Yes | - | Endpoint definitions (at least one required) |
Rate Limits Object:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
requests_per_second |
number | Yes | - | Maximum requests per second |
burst_size |
number | Yes | - | Burst capacity |
block_duration |
number (nanoseconds) | No | 300000000000 | Block duration (default: 5 minutes) |
use_sliding_window |
boolean | Auto | true | Always true (enforced by system) |
Endpoint Object:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | - | Unique endpoint identifier within API |
path |
string | Yes | - | Full URL path (e.g., /api/users) |
method |
string | Yes | - | HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) |
limits |
object | No | API defaults | Endpoint-specific rate limits |
priority |
number | No | 100 | Matching priority (lower = higher priority) |
enabled |
boolean | Auto | true | Always true (enforced by system) |
Important Notes:
- ✅ No
base_pathrequired - paths are used as-is - ✅ Full paths required - use
/api/users, not/users - ✅ Methods validated - must be valid HTTP methods, auto-uppercase
- ✅ At least one endpoint required - empty endpoints array rejected
- ❌ No
auth_typefield - authentication handled at middleware layer, not per-endpoint
{
"id": "user-service",
"service_id": "user-service-v1",
"name": "User Service API",
"description": "Handles user operations",
"upstream_url": "http://user-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000,
"use_sliding_window": true
},
"endpoints": [
{
"id": "get-users",
"path": "/api/users",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
},
{
"id": "create-user",
"path": "/api/users",
"method": "POST",
"limits": {
"requests_per_second": 20,
"burst_size": 40,
"block_duration": 600000000000,
"use_sliding_window": true
},
"priority": 20,
"enabled": true
}
],
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:00:00.000000000+05:00"
}Create Full API:
curl -X POST http://localhost:8080/admin/apis \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"id": "order-service",
"service_id": "commerce-v1",
"name": "Order Service",
"description": "Handles order processing",
"upstream_url": "http://order-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000
},
"endpoints": [
{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100
},
"priority": 10
},
{
"id": "create-order",
"path": "/api/orders",
"method": "POST",
"limits": {
"requests_per_second": 20,
"burst_size": 40,
"block_duration": 600000000000
},
"priority": 20
}
]
}'Create Minimal API (Required Fields Only):
curl -X POST http://localhost:8080/admin/apis \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"id": "minimal-api",
"service_id": "minimal-service",
"upstream_url": "http://minimal-backend:8080",
"endpoints": [
{
"id": "health",
"path": "/health",
"method": "GET"
}
]
}'Endpoint: PUT /admin/apis/{apiID}
Updates an existing API. Supports partial updates - only send fields you want to change.
{
"name": "Updated Order Service",
"description": "Updated description for order processing",
"upstream_url": "http://new-order-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 150,
"burst_size": 300,
"block_duration": 300000000000
}
}Update Name Only:
{
"name": "Updated API Name"
}Update Rate Limits Only:
{
"default_limits": {
"requests_per_second": 200,
"burst_size": 400,
"block_duration": 300000000000
}
}Update Status to Maintenance:
{
"status": "maintenance"
}Update Upstream URL:
{
"upstream_url": "http://new-backend:9000"
}Returns the complete updated API object.
{
"id": "order-service",
"service_id": "commerce-v1",
"name": "Updated Order Service",
"description": "Updated description for order processing",
"upstream_url": "http://new-order-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 150,
"burst_size": 300,
"block_duration": 300000000000,
"use_sliding_window": true
},
"endpoints": [...],
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:30:00.000000000+05:00"
}# Full update
curl -X PUT http://localhost:8080/admin/apis/order-service \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"name": "Updated Order Service",
"upstream_url": "http://new-backend:9000",
"default_limits": {
"requests_per_second": 150,
"burst_size": 300
}
}'
# Partial update - status only
curl -X PUT http://localhost:8080/admin/apis/order-service \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{"status": "maintenance"}'Endpoint: GET /admin/apis/{apiID}
Retrieves a single API by ID.
{
"id": "order-service",
"service_id": "commerce-v1",
"name": "Order Service",
"description": "Handles order processing",
"upstream_url": "http://order-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000,
"use_sliding_window": true
},
"endpoints": [
{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
}
],
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:00:00.000000000+05:00"
}curl http://localhost:8080/admin/apis/order-service \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/apis
Lists all registered APIs with optional filtering and pagination.
| Parameter | Type | Description | Example |
|---|---|---|---|
service_id |
string | Filter by service ID | commerce-v1 |
status |
string | Filter by status | active, maintenance |
search |
string | Search in name/description | order |
limit |
integer | Limit results | 10 |
offset |
integer | Pagination offset | 0 |
{
"apis": [
{
"id": "order-service",
"service_id": "commerce-v1",
"name": "Order Service",
"description": "Handles order processing",
"upstream_url": "http://order-backend:8080",
"status": "active",
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:00:00.000000000+05:00"
},
{
"id": "user-service",
"service_id": "user-service-v1",
"name": "User Service API",
"upstream_url": "http://user-backend:8080",
"status": "active",
"created_at": "2026-03-10T10:30:00.000000000+05:00",
"updated_at": "2026-03-10T10:30:00.000000000+05:00"
}
],
"count": 2
}# List all APIs
curl http://localhost:8080/admin/apis \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Filter by status
curl "http://localhost:8080/admin/apis?status=active" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Filter by service_id with pagination
curl "http://localhost:8080/admin/apis?service_id=commerce-v1&limit=10&offset=0" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: DELETE /admin/apis/{apiID}
Deletes an API and all its endpoints.
204 No Content - No response body
curl -X DELETE http://localhost:8080/admin/apis/order-service \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/apis/{apiID}/endpoints
Lists all endpoints for a specific API.
{
"endpoints": [
{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
},
{
"id": "create-order",
"path": "/api/orders",
"method": "POST",
"limits": {
"requests_per_second": 20,
"burst_size": 40,
"block_duration": 600000000000,
"use_sliding_window": true
},
"priority": 20,
"enabled": true
}
],
"count": 2
}curl http://localhost:8080/admin/apis/order-service/endpoints \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: POST /admin/apis/{apiID}/endpoints
Adds a new endpoint to an existing API.
{
"id": "update-order",
"path": "/api/orders/{id}",
"method": "PUT",
"limits": {
"requests_per_second": 15,
"burst_size": 30,
"block_duration": 300000000000
},
"priority": 25
}Field Details:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | - | Unique endpoint identifier within API |
path |
string | Yes | - | Full URL path (e.g., /api/orders/{id}) |
method |
string | Yes | - | HTTP method (auto-uppercase) |
limits |
object | No | API defaults | Endpoint-specific rate limits |
priority |
number | No | 100 | Matching priority |
{
"id": "update-order",
"path": "/api/orders/{id}",
"method": "PUT",
"limits": {
"requests_per_second": 15,
"burst_size": 30,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 25,
"enabled": true
}curl -X POST http://localhost:8080/admin/apis/order-service/endpoints \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"id": "update-order",
"path": "/api/orders/{id}",
"method": "PUT",
"limits": {
"requests_per_second": 15,
"burst_size": 30
},
"priority": 25
}'Endpoint: GET /admin/apis/{apiID}/endpoints/{endpointID}
Retrieves a specific endpoint.
{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
}curl http://localhost:8080/admin/apis/order-service/endpoints/list-orders \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: PUT /admin/apis/{apiID}/endpoints/{endpointID}
Updates an existing endpoint. Supports partial updates.
{
"path": "/api/orders/v2/{id}",
"method": "PATCH",
"limits": {
"requests_per_second": 25,
"burst_size": 50,
"block_duration": 300000000000
},
"priority": 15
}Update Limits Only:
{
"limits": {
"requests_per_second": 100,
"burst_size": 200
}
}Update Priority Only:
{
"priority": 5
}{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 5,
"enabled": true
}# Update limits
curl -X PUT http://localhost:8080/admin/apis/order-service/endpoints/list-orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"limits": {
"requests_per_second": 100,
"burst_size": 200
}
}'
# Update priority
curl -X PUT http://localhost:8080/admin/apis/order-service/endpoints/list-orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{"priority": 5}'Endpoint: DELETE /admin/apis/{apiID}/endpoints/{endpointID}
Deletes a specific endpoint.
204 No Content - No response body
curl -X DELETE http://localhost:8080/admin/apis/order-service/endpoints/update-order \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: POST /admin/apis/import
Imports multiple APIs at once.
{
"apis": [
{
"id": "bulk-api-1",
"service_id": "bulk-service",
"name": "Bulk API 1",
"upstream_url": "http://localhost:8082",
"default_limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000
},
"endpoints": [
{
"id": "get-data",
"path": "/api/data",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100
},
"priority": 10
}
]
},
{
"id": "bulk-api-2",
"service_id": "bulk-service",
"name": "Bulk API 2",
"upstream_url": "http://localhost:8083",
"default_limits": {
"requests_per_second": 30,
"burst_size": 60,
"block_duration": 300000000000
},
"endpoints": [
{
"id": "health",
"path": "/health",
"method": "GET",
"priority": 1
}
]
}
],
"overwrite_existing": false
}{
"imported": 2,
"updated": 0,
"failed": 0,
"errors": []
}With Errors:
{
"imported": 1,
"updated": 0,
"failed": 1,
"errors": [
"Failed to register bulk-api-2: API with ID bulk-api-2 already exists"
]
}curl -X POST http://localhost:8080/admin/apis/import \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"apis": [
{
"id": "imported-api",
"service_id": "imported-service",
"name": "Imported API",
"upstream_url": "http://imported-backend:8080",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200
},
"endpoints": [
{
"id": "health",
"path": "/health",
"method": "GET",
"priority": 1
}
]
}
],
"overwrite_existing": false
}'Endpoint: GET /admin/apis/export
Exports all APIs in JSON format for backup or migration.
{
"exported_at": "2026-03-10T10:30:00Z",
"count": 2,
"apis": [
{
"id": "order-service",
"service_id": "commerce-v1",
"name": "Order Service",
"upstream_url": "http://order-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000,
"use_sliding_window": true
},
"endpoints": [
{
"id": "list-orders",
"path": "/api/orders",
"method": "GET",
"limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
}
],
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:00:00.000000000+05:00"
}
]
}# Export to file
curl http://localhost:8080/admin/apis/export \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
> apis-backup-$(date +%Y%m%d).jsonEndpoint: GET /admin/apis/templates
Lists available service templates with predefined rate limits.
{
"templates": {
"standard": {
"requests_per_second": 100,
"burst_size": 200,
"window_size": 60000000000,
"block_duration": 300000000000
},
"premium": {
"requests_per_second": 500,
"burst_size": 1000,
"window_size": 60000000000,
"block_duration": 300000000000
},
"public": {
"requests_per_second": 1000,
"burst_size": 2000,
"window_size": 10000000000,
"block_duration": 60000000000
},
"secure": {
"requests_per_second": 10,
"burst_size": 15,
"window_size": 60000000000,
"block_duration": 900000000000
}
},
"count": 4
}curl http://localhost:8080/admin/apis/templates \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: POST /admin/apis/from-template
Creates an API from a predefined template with automatic rate limit defaults.
{
"api_id": "premium-api",
"service_id": "premium-service",
"name": "Premium API from Template",
"upstream_url": "http://premium-backend:8080",
"template": "premium",
"endpoints": [
{
"id": "get-data",
"path": "/api/data",
"method": "GET",
"priority": 10
},
{
"id": "post-data",
"path": "/api/data",
"method": "POST",
"priority": 20
}
]
}Template Values Applied:
standard: 100 RPS, 200 burst, 5min blockpremium: 500 RPS, 1000 burst, 5min blockpublic: 1000 RPS, 2000 burst, 1min blocksecure: 10 RPS, 15 burst, 15min block
{
"id": "premium-api",
"service_id": "premium-service",
"name": "Premium API from Template",
"upstream_url": "http://premium-backend:8080",
"status": "active",
"default_limits": {
"requests_per_second": 500,
"burst_size": 1000,
"window_size": 60000000000,
"block_duration": 300000000000,
"use_sliding_window": true
},
"endpoints": [
{
"id": "get-data",
"path": "/api/data",
"method": "GET",
"limits": {
"requests_per_second": 500,
"burst_size": 1000,
"window_size": 60000000000,
"block_duration": 300000000000,
"use_sliding_window": true
},
"priority": 10,
"enabled": true
}
],
"created_at": "2026-03-10T10:00:00.000000000+05:00",
"updated_at": "2026-03-10T10:00:00.000000000+05:00"
}curl -X POST http://localhost:8080/admin/apis/from-template \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"api_id": "my-premium-api",
"service_id": "my-service",
"name": "My Premium API",
"upstream_url": "http://backend:8080",
"template": "premium",
"endpoints": [
{
"id": "health",
"path": "/health",
"method": "GET",
"priority": 1
}
]
}'Endpoint: POST /admin/apis/test
Tests a rate limit rule against a path without applying it.
{
"path": "/api/orders/orders",
"method": "GET",
"rule": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000
}
}{
"path": "/api/orders/orders",
"method": "GET",
"matched_rule": {
"api_id": "order-service",
"endpoint_id": "list-orders",
"service_id": "commerce-v1",
"path": "/api/orders/orders",
"method": "GET",
"requests_per_second": 50,
"burst_size": 100,
"window_size": 60000000000,
"block_duration": 300000000000,
"use_sliding_window": true,
"priority": 10,
"enabled": true,
"upstream_url": "http://order-backend:8080",
"is_excluded": false
},
"would_apply": true,
"test_limits": {
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000
}
}curl -X POST http://localhost:8080/admin/apis/test \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"path": "/api/orders/orders",
"method": "GET",
"rule": {
"requests_per_second": 100,
"burst_size": 200
}
}'Endpoint: GET /admin/apis/resolve
Shows which rule would apply to a specific path.
| Parameter | Type | Required | Description |
|---|---|---|---|
path |
string | Yes | Path to resolve |
{
"path": "/api/orders/orders",
"resolved_rule": {
"api_id": "order-service",
"endpoint_id": "list-orders",
"service_id": "commerce-v1",
"path": "/api/orders/orders",
"method": "GET",
"requests_per_second": 50,
"burst_size": 100,
"window_size": 60000000000,
"block_duration": 300000000000,
"use_sliding_window": true,
"priority": 10,
"enabled": true,
"upstream_url": "http://order-backend:8080"
},
"excluded": false
}curl "http://localhost:8080/admin/apis/resolve?path=/api/orders/orders" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: POST /admin/apis/reload
Triggers a reload of all rate limiting rules from the registry file.
{
"status": "reloaded",
"message": "Rules reloaded successfully"
}curl -X POST http://localhost:8080/admin/apis/reload \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/apis/events
Subscribes to Server-Sent Events (SSE) for real-time API changes.
data: {"type": "connected", "timestamp": "2026-03-10T10:00:00Z"}
data: {"type": "api_created", "api_id": "new-api", "timestamp": "2026-03-10T10:05:00Z", "data": {"id": "new-api", ...}}
data: {"type": "api_updated", "api_id": "order-service", "timestamp": "2026-03-10T10:10:00Z"}
data: {"type": "api_deleted", "api_id": "old-api", "timestamp": "2026-03-10T10:15:00Z"}
# Stream events (requires -N for no buffering)
curl -N http://localhost:8080/admin/apis/events \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"The /check endpoint provides a dry-run rate limiting check that allows you to test whether a specific request would be allowed, blocked, or rate-limited without actually consuming quota or forwarding the request to the backend. This is useful for pre-flight checks, client-side rate limit awareness, and debugging.
Endpoint: POST /check
Tests a hypothetical request against the rate limiting rules and returns the decision without incrementing counters or blocking the client.
{
"service_id": "user-service",
"endpoint": "/api/users",
"ip": "192.168.1.100",
"user_id": "user_12345",
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json"
}
}Field Details:
| Field | Type | Required | Description |
|---|---|---|---|
service_id |
string | Yes | The service identifier to check against |
endpoint |
string | Yes | The full path of the endpoint to test |
ip |
string | Yes | Client IP address (IPv4 or IPv6) |
user_id |
string | No | User identifier for user-based limiting (if provided, takes precedence over IP) |
headers |
object | No | HTTP headers for bot detection analysis |
{
"allowed": true,
"reason": "allowed",
"service_id": "user-service",
"endpoint": "/api/users",
"client_id": "user_12345",
"limit_type": "user_based",
"remaining": 49,
"reset_at": "2026-03-10T10:05:00Z",
"rule": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000
}
}{
"allowed": false,
"reason": "bot_detected",
"service_id": "user-service",
"endpoint": "/api/users",
"client_id": "192.168.1.200",
"limit_type": "ip_based",
"details": "Missing or suspicious User-Agent header"
}{
"allowed": false,
"reason": "rate_limit_exceeded",
"service_id": "user-service",
"endpoint": "/api/users",
"client_id": "192.168.1.50",
"limit_type": "ip_based",
"retry_after": 45,
"details": "Rate limit exceeded. Try again in 45 seconds."
}{
"allowed": true,
"reason": "excluded_path",
"service_id": "user-service",
"endpoint": "/health",
"details": "Path is excluded from rate limiting"
}{
"error": "missing_required_fields",
"message": "service_id, endpoint, and ip are required"
}{
"error": "invalid_json",
"message": "Request body contains malformed JSON"
}{
"error": "unauthorized",
"message": "X-API-Key header is required"
}Basic Check (Allowed):
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"service_id": "user-service",
"endpoint": "/api/users",
"ip": "192.168.1.100",
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json"
}
}'Check with User ID (User-Based Limiting):
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"service_id": "order-service",
"endpoint": "/api/orders",
"ip": "192.168.1.101",
"user_id": "user_12345",
"headers": {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"Accept": "application/json"
}
}'Bot Detection Test (Should Return Blocked):
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"service_id": "user-service",
"endpoint": "/api/users",
"ip": "192.168.1.200",
"headers": {
"User-Agent": "curl/7.68.0",
"Accept": "*/*"
}
}'IPv6 Address Check:
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"service_id": "order-service",
"endpoint": "/api/orders",
"ip": "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"headers": {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
"Accept": "application/json"
}
}'Excluded Path Check (Health Check):
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"service_id": "user-service",
"endpoint": "/health",
"ip": "192.168.1.102",
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json"
}
}'| Field | Type | Description |
|---|---|---|
allowed |
boolean | Whether the request would be allowed |
reason |
string | Decision reason: allowed, rate_limit_exceeded, bot_detected, blocked_ip, excluded_path, service_not_found, endpoint_not_found |
service_id |
string | The service that was checked |
endpoint |
string | The endpoint path that was checked |
client_id |
string | The identifier used for limiting (IP or user_id) |
limit_type |
string | ip_based, user_based, or none |
remaining |
number | Remaining requests in current window (if applicable) |
reset_at |
string | ISO 8601 timestamp when the limit resets (if applicable) |
retry_after |
number | Seconds until retry is allowed (if rate limited) |
rule |
object | The rate limit rule that was applied |
details |
string | Human-readable explanation of the decision |
The /check endpoint includes bot detection that analyzes the User-Agent header and other request characteristics:
| Scenario | Result | Reason |
|---|---|---|
Missing User-Agent |
Blocked | bot_detected |
Empty User-Agent |
Blocked | bot_detected |
| Known bot signatures (curl, wget, python-requests, etc.) | Blocked | bot_detected |
| Suspicious patterns | Blocked | bot_detected |
| Valid browser User-Agent | Allowed | allowed |
The check endpoint evaluates limits in this priority order:
- Excluded Paths: If the path matches an exclusion list (e.g.,
/health), returnsallowedimmediately - Bot Detection: If bot detected, returns
blockedimmediately - Blocked IPs: If IP is in blocklist, returns
blockedwith remaining block time - User-Based Limiting: If
user_idprovided, check against user limits - IP-Based Limiting: If no
user_id, check against IP limits (with subnet normalization)
Important Notes:
- The
/checkendpoint is a dry-run - it does not consume quota or increment counters - It returns the current state of limits without modifying them
- Use this for pre-flight checks before making actual requests
- The endpoint requires
X-API-Keyauthentication (different from admin endpoints that useBearertokens)
Since /check doesn't consume quota, you can use it to safely test your rate limiting configuration:
# Test 1: Verify normal request is allowed
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: test-key" \
-d '{"service_id":"payment-service","endpoint":"/api/v1/payments","ip":"192.168.1.1","headers":{"User-Agent":"Mozilla/5.0"}}'
# Test 2: Verify bot is detected
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: test-key" \
-d '{"service_id":"payment-service","endpoint":"/api/v1/payments","ip":"192.168.1.1","headers":{"User-Agent":"curl/7.68.0"}}'
# Test 3: Verify excluded path
curl -X POST http://localhost:8080/check \
-H "Content-Type: application/json" \
-H "X-API-Key: test-key" \
-d '{"service_id":"payment-service","endpoint":"/health","ip":"192.168.1.1","headers":{"User-Agent":"Mozilla/5.0"}}'Where to insert: Place this entire block immediately before the "Additional System Endpoints" section (which starts with ### Health Check). The --- horizontal rule at the beginning creates proper separation from the previous Metrics API section.
Also, update your Table of Contents at the top of the README to include:
- Rate Limit Check Endpoint
- 19.1 Check Rate Limit (Dry Run)
- 19.2 Check Response Fields Reference
- 19.3 Bot Detection Behavior
- 19.4 Rate Limiting Behavior
- [19.5 Testing Rate Limits with Check Endpoint]
- [Testing-rate-limits-with-check-endpoint]
The Metrics API provides real-time and historical metrics for monitoring API usage and performance.
http://localhost:8080/admin/metrics
Endpoint: GET /admin/metrics
Returns all APIs with their current metrics summary.
{
"apis": [
{
"id": "order-service",
"total_requests": 1500,
"allowed_requests": 1450,
"blocked_requests": 50,
"rate_limited_requests": 30,
"avg_response_time_ms": 45.5,
"status_codes": {
"200": 1400,
"201": 50,
"429": 30,
"500": 20
}
}
],
"count": 1,
"generated_at": "2026-03-10T10:00:00Z"
}curl http://localhost:8080/admin/metrics \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/metrics/{apiID}
Query parameters for time range:
from- Start time (RFC3339)to- End time (RFC3339)range- Relative range:1h,6h,12h,24h,3d,7d,30d,90d,1y
| Endpoint | Description |
|---|---|
GET /admin/metrics/{apiID}/current |
Current hour |
GET /admin/metrics/{apiID}/today |
Today (00:00 to now) |
GET /admin/metrics/{apiID}/yesterday |
Yesterday full day |
GET /admin/metrics/{apiID}/week |
Last 7 days |
GET /admin/metrics/{apiID}/month |
Last 30 days |
GET /admin/metrics/{apiID}/year |
Last 365 days |
Endpoint: GET /admin/metrics/{apiID}/range
Query parameters:
days- Number of days backhours- Number of hours back
{
"api_id": "order-service",
"query_range": "last_7_days",
"from": "2026-03-03T10:00:00Z",
"to": "2026-03-10T10:00:00Z",
"total_requests": 10500,
"allowed_requests": 10000,
"blocked_requests": 300,
"rate_limited_requests": 200,
"avg_response_time_ms": 42.3,
"requests_per_hour": [
{"hour": "2026-03-03T10:00:00Z", "count": 150},
{"hour": "2026-03-03T11:00:00Z", "count": 180}
],
"top_ips": [
{"ip": "192.168.1.1", "requests": 500},
{"ip": "192.168.1.2", "requests": 300}
],
"status_codes": {
"200": 9500,
"201": 500,
"429": 200,
"500": 100
},
"endpoints": [
{
"endpoint_id": "list-orders",
"path": "/api/orders",
"method": "GET",
"requests": 8000,
"avg_response_time_ms": 35.0
}
]
}# Last 24 hours (default)
curl http://localhost:8080/admin/metrics/order-service \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Today only
curl http://localhost:8080/admin/metrics/order-service/today \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Last 7 days
curl http://localhost:8080/admin/metrics/order-service/week \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Custom range - last 3 days
curl http://localhost:8080/admin/metrics/order-service/range?days=3 \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Custom range - last 6 hours
curl http://localhost:8080/admin/metrics/order-service/range?hours=6 \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Specific date range
curl "http://localhost:8080/admin/metrics/order-service?from=2026-03-01T00:00:00Z&to=2026-03-10T00:00:00Z" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/metrics/{apiID}/stream
Server-Sent Events stream with real-time metrics updates every 5 seconds.
data: {"type": "connected", "timestamp": "2026-03-10T10:00:00Z", "metrics": {...}}
data: {"type": "update", "timestamp": "2026-03-10T10:00:05Z", "metrics": {...}}
curl -N http://localhost:8080/admin/metrics/order-service/stream \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Endpoint: GET /admin/metrics/{apiID}/export
Exports raw metrics data as JSON file.
Query parameters:
format- Export format (default:json)
File download with Content-Disposition: attachment
curl http://localhost:8080/admin/metrics/order-service/export \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
> order-service-metrics.json| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | - | Unique API identifier |
service_id |
string | Yes | - | Service grouping identifier |
name |
string | No | - | Human-readable name |
description |
string | No | - | Detailed description |
upstream_url |
string | Yes | - | Backend server URL |
status |
string | No | "active" | active, maintenance, deprecated, disabled |
default_limits |
object | No | {} |
Default rate limits |
endpoints |
array | Yes | - | Endpoint definitions (at least one) |
created_at |
string | Auto | current time | ISO 8601 timestamp |
updated_at |
string | Auto | current time | ISO 8601 timestamp |
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
requests_per_second |
number | Yes | - | Maximum requests per second |
burst_size |
number | Yes | - | Maximum burst size |
block_duration |
number (nanoseconds) | No | 300000000000 | Block duration (5 minutes) |
use_sliding_window |
boolean | Auto | true |
Always true (enforced) |
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | - | Unique endpoint identifier |
path |
string | Yes | - | Full URL path (e.g., /api/users) |
method |
string | Yes | - | HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) |
limits |
object | No | API defaults | Endpoint-specific rate limits |
priority |
number | No | 100 | Matching priority (lower = higher) |
enabled |
boolean | Auto | true |
Always true (enforced) |
| Status | Description |
|---|---|
active |
Operational and accepting requests |
maintenance |
Maintenance mode, requests may be rejected |
deprecated |
Deprecated but still operational |
disabled |
Disabled, not accepting requests |
| Duration | Nanoseconds | Use Case |
|---|---|---|
| 1 minute | 60000000000 | Short blocks |
| 5 minutes | 300000000000 | Standard block duration (default) |
| 10 minutes | 600000000000 | Medium blocks |
| 15 minutes | 900000000000 | Secure API blocks |
| 30 minutes | 1800000000000 | Long blocks |
Returned by Test Rule and Resolve Path endpoints:
| Field | Type | Description |
|---|---|---|
api_id |
string | Parent API identifier |
endpoint_id |
string | Matched endpoint identifier |
service_id |
string | Service grouping |
path |
string | Full request path |
method |
string | HTTP method |
requests_per_second |
number | Applied RPS limit |
burst_size |
number | Applied burst limit |
window_size |
number | Time window in nanoseconds |
block_duration |
number | Block duration in nanoseconds |
use_sliding_window |
boolean | Always true |
priority |
number | Endpoint priority |
enabled |
boolean | Always true |
upstream_url |
string | Backend URL |
is_excluded |
boolean | Whether path is excluded |
| Feature | Behavior |
|---|---|
| Path Forwarding | Full paths forwarded as-is (no stripping) |
| Method Validation | Strict matching required (405 if mismatch) |
| Authentication | Handled by middleware layer, not per-endpoint |
| Rate Limiting | Applied before proxying |
| Request Body | Preserved and forwarded correctly |
- Request arrives:
POST http://localhost:8080/api/users - Registry lookup: Finds endpoint with path
/api/usersand methodPOST - Method validation: Checks if
POST == POST✓ - Rate limiting: Checks limits for the endpoint
- Proxy request: Forwards to
http://backend:8080/api/users(unchanged path)
Request: GET /api/users
Endpoint: POST /api/users
Result: 405 Method Not Allowed
Error: {"error": "method_not_allowed", "message": "Method GET not allowed for this endpoint. Expected: POST"}
Public/High-Traffic APIs:
{
"requests_per_second": 1000,
"burst_size": 2000,
"block_duration": 60000000000
}Standard APIs:
{
"requests_per_second": 100,
"burst_size": 200,
"block_duration": 300000000000
}Secure/Sensitive APIs:
{
"requests_per_second": 10,
"burst_size": 15,
"block_duration": 900000000000
}| Priority | Use Case | Example |
|---|---|---|
| 1-5 | Health checks, critical endpoints | /health, /ready |
| 10-20 | Standard read operations | GET /api/users |
| 20-30 | Standard write operations | POST /api/users |
| 30-50 | Destructive operations | DELETE /api/users/{id} |
| 50-100 | Administrative operations | POST /admin/reset |
✅ DO:
- Use full paths:
/api/users,/api/orders/{id} - Include version in path:
/api/v1/users - Use consistent naming conventions
❌ DON'T:
- Use relative paths:
/users(unless backend expects this) - Omit leading slash:
api/users - Use
base_pathfield (deprecated, ignored by proxy)
# 1. Create API with multiple endpoints
curl -X POST http://localhost:8080/admin/apis \
-H "Content-Type: application/json" \
-H "Authorization: Bearer admin-token" \
-d '{
"id": "payment-service",
"service_id": "payments-v1",
"name": "Payment Service",
"upstream_url": "http://payment-backend:8080",
"default_limits": {
"requests_per_second": 50,
"burst_size": 100,
"block_duration": 300000000000
},
"endpoints": [
{
"id": "health",
"path": "/health",
"method": "GET",
"limits": {"requests_per_second": 1000, "burst_size": 2000},
"priority": 1
},
{
"id": "list-payments",
"path": "/api/v1/payments",
"method": "GET",
"limits": {"requests_per_second": 50, "burst_size": 100},
"priority": 10
},
{
"id": "create-payment",
"path": "/api/v1/payments",
"method": "POST",
"limits": {"requests_per_second": 20, "burst_size": 40, "block_duration": 600000000000},
"priority": 20
}
]
}'
# 2. Verify creation
curl http://localhost:8080/admin/apis/payment-service \
-H "Authorization: Bearer admin-token"
# 3. Test routing
curl "http://localhost:8080/admin/apis/resolve?path=/api/v1/payments" \
-H "Authorization: Bearer admin-token"
# 4. Test the proxy
curl http://localhost:8080/api/v1/payments \
-H "Authorization: Bearer user-token"
# 5. Monitor metrics
curl http://localhost:8080/admin/metrics/payment-service \
-H "Authorization: Bearer admin-token"
# 6. Stream real-time events
curl -N http://localhost:8080/admin/apis/events \
-H "Authorization: Bearer admin-token"
# 7. Export for backup
curl http://localhost:8080/admin/apis/export \
-H "Authorization: Bearer admin-token" > backup.json400 Bad Request - Invalid JSON:
{"error": "invalid request body"}400 Bad Request - Missing Required Fields:
{"error": "id, service_id, and upstream_url are required"}400 Bad Request - Empty Endpoints:
{"error": "at least one endpoint is required"}400 Bad Request - Invalid Method:
{"error": "invalid HTTP method: INVALID"}401 Unauthorized:
{"error": "unauthorized"}404 Not Found - API:
{"error": "API not found"}404 Not Found - Endpoint:
{"error": "Endpoint not found"}405 Method Not Allowed:
{"error": "method_not_allowed", "message": "Method GET not allowed for this endpoint. Expected: POST"}409 Conflict - Duplicate:
{"error": "API with ID payment-service already exists"}curl http://localhost:8080/healthResponse: OK
curl http://localhost:8080/config \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"curl http://localhost:8080/admin/stats \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Response:
{
"allowed": 1500,
"blocked": 50,
"bot_blocked": 10,
"in_flight": 5,
"window_start": "2026-03-10T10:00:00Z"
}| # | Change | Description |
|---|---|---|
| 1 | Removed base_path requirement |
Field is now optional per code comments ("base_path is now optional") |
| 2 | Removed auth_type from endpoints |
Authentication handled at middleware layer, not per-endpoint (code comments: "REMOVED: auth_type handling - no longer supported") |
| 3 | Removed metadata field |
Not present in actual API structures |
| 4 | Added complete Metrics API section | Full documentation for metrics endpoints from metrics_handler.go |
| 5 | Fixed endpoints array requirement |
Validated as required (code checks len(api.Endpoints) == 0) |
| 6 | Added strict HTTP method validation | Invalid methods rejected with 400 error |
| 7 | Removed window_size from user input |
Auto-calculated by system, not user-configurable |
| 8 | Updated reverse proxy behavior | Documents no path stripping and strict method matching |
| 9 | Added timestamp fields | created_at and updated_at present in all responses |
| 10 | Corrected nanosecond durations | Using actual code values (e.g., 300000000000 for 5 minutes) |
| 11 | Added Rate Limit Check (/check) endpoint |
Complete documentation for dry-run rate limit testing with bot detection, user/IP-based limiting, and excluded paths |
Version: 3.0
Last Updated: March 10, 2026
Maintained By: Sraraa