# NxMesh API Specification ## Overview This document outlines the API structure for NxMesh. The system exposes: - **REST API** for external integrations and Web UI - **gRPC API** for master-agent communication - **WebSocket API** for real-time events --- ## REST API ### Base Information | Property | Value | |----------|-------| | Base URL | `https://api.nxmesh.io/v1` | | Content-Type | `application/json` | | Authentication | Bearer Token (JWT) | | Rate Limit | 1000 requests/minute | ### Authentication #### Login ```http POST /auth/login Content-Type: application/json { "email": "user@example.com", "password": "secure_password" } ``` Response: ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...", "expires_in": 3600, "token_type": "Bearer" } ``` #### Refresh Token ```http POST /auth/refresh Content-Type: application/json { "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..." } ``` --- ### Organizations #### List Organizations ```http GET /organizations?page=1&per_page=20 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Acme Corp", "slug": "acme-corp", "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 1 } } ``` #### Create Organization ```http POST /organizations Authorization: Bearer {token} Content-Type: application/json { "name": "Acme Corp", "slug": "acme-corp" } ``` #### Get Organization ```http GET /organizations/{organization_id} Authorization: Bearer {token} ``` #### Update Organization ```http PATCH /organizations/{organization_id} Authorization: Bearer {token} Content-Type: application/json { "name": "Acme Corporation" } ``` #### Delete Organization ```http DELETE /organizations/{organization_id} Authorization: Bearer {token} ``` --- ### Workspaces #### List Workspaces ```http GET /organizations/{organization_id}/workspaces?page=1&per_page=20 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "660e8400-e29b-41d4-a716-446655440001", "organization_id": "550e8400-e29b-41d4-a716-446655440000", "name": "Production", "slug": "production", "created_at": "2026-01-15T10:30:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 3 } } ``` #### Create Workspace ```http POST /organizations/{organization_id}/workspaces Authorization: Bearer {token} Content-Type: application/json { "name": "Staging", "slug": "staging" } ``` #### Get Workspace ```http GET /workspaces/{workspace_id} Authorization: Bearer {token} ``` #### Update Workspace ```http PATCH /workspaces/{workspace_id} Authorization: Bearer {token} Content-Type: application/json { "name": "Staging Environment" } ``` #### Delete Workspace ```http DELETE /workspaces/{workspace_id} Authorization: Bearer {token} ``` --- ### Agents #### List Agents ```http GET /workspaces/{workspace_id}/agents?page=1&per_page=20&state=online Authorization: Bearer {token} ``` Query Parameters: - `state` - Filter by state: `online`, `offline`, `degraded`, `all` - `label_selector` - Filter by labels: `env=production,region=us-east` Response: ```json { "data": [ { "id": "770e8400-e29b-41d4-a716-446655440002", "workspace_id": "660e8400-e29b-41d4-a716-446655440001", "name": "web-server-01", "hostname": "web-01.internal", "ip_address": "10.0.1.10", "version": "0.1.0", "state": "online", "deployment_mode": "docker_sidecar", "last_seen_at": "2026-03-02T12:00:00Z", "capabilities": ["http2", "websocket"], "labels": { "env": "production", "region": "us-east-1" }, "created_at": "2026-02-01T10:00:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 5 } } ``` #### Get Agent ```http GET /agents/{agent_id} Authorization: Bearer {token} ``` Response includes health details: ```json { "id": "770e8400-e29b-41d4-a716-446655440002", "workspace_id": "660e8400-e29b-41d4-a716-446655440001", "name": "web-server-01", "hostname": "web-01.internal", "ip_address": "10.0.1.10", "version": "0.1.0", "state": "online", "deployment_mode": "docker_sidecar", "last_seen_at": "2026-03-02T12:00:00Z", "capabilities": ["http2", "websocket"], "labels": { "env": "production", "region": "us-east-1" }, "health": { "nginx_status": "running", "nginx_uptime_seconds": 86400, "active_connections": 42, "requests_per_second": 150.5, "cpu_percent": 25.0, "memory_used_mb": 512, "config_version": 42 }, "created_at": "2026-02-01T10:00:00Z" } ``` #### Create Agent Registration Token ```http POST /workspaces/{workspace_id}/agents/tokens Authorization: Bearer {token} Content-Type: application/json { "name": "web-server-02", "labels": { "env": "production", "region": "us-west-1" }, "expires_in_hours": 24 } ``` Response: ```json { "token": "nxmesh_agent_eyJhZ2VudF9pZCI6ICI3NzBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDMi...", "agent_id": "770e8400-e29b-41d4-a716-446655440003", "expires_at": "2026-03-03T12:00:00Z" } ``` #### Update Agent ```http PATCH /agents/{agent_id} Authorization: Bearer {token} Content-Type: application/json { "name": "web-server-01-renamed", "labels": { "env": "production", "region": "us-east-1", "tier": "web" } } ``` #### Delete Agent ```http DELETE /agents/{agent_id} Authorization: Bearer {token} ``` #### Reload Agent Nginx ```http POST /agents/{agent_id}/reload Authorization: Bearer {token} ``` Response: ```json { "success": true, "message": "Nginx reloaded successfully", "timestamp": "2026-03-02T12:05:00Z" } ``` --- ### Virtual Hosts #### List Virtual Hosts ```http GET /workspaces/{workspace_id}/virtual-hosts?page=1&per_page=20 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "880e8400-e29b-41d4-a716-446655440004", "workspace_id": "660e8400-e29b-41d4-a716-446655440001", "name": "Main Website", "server_name": "example.com www.example.com", "listen_port": 443, "ssl_enabled": true, "ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005", "http2_enabled": true, "target_agents": { "type": "all" }, "created_at": "2026-02-01T10:00:00Z", "updated_at": "2026-02-15T14:30:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 10 } } ``` #### Create Virtual Host ```http POST /workspaces/{workspace_id}/virtual-hosts Authorization: Bearer {token} Content-Type: application/json { "name": "API Gateway", "server_name": "api.example.com", "listen_port": 443, "ssl_enabled": true, "ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005", "http2_enabled": true, "locations": [ { "path": "/api/v1", "upstream_id": "aa0e8400-e29b-41d4-a716-446655440006", "custom_headers": [ { "name": "X-Forwarded-Proto", "value": "$scheme" } ] }, { "path": "/health", "proxy_pass": "http://localhost:8080/health" } ], "target_agents": { "type": "selector", "label_selector": "env=production" } } ``` #### Get Virtual Host ```http GET /virtual-hosts/{virtual_host_id} Authorization: Bearer {token} ``` #### Update Virtual Host ```http PATCH /virtual-hosts/{virtual_host_id} Authorization: Bearer {token} Content-Type: application/json { "name": "API Gateway v2", "locations": [ { "path": "/api/v2", "upstream_id": "aa0e8400-e29b-41d4-a716-446655440007" } ] } ``` #### Delete Virtual Host ```http DELETE /virtual-hosts/{virtual_host_id} Authorization: Bearer {token} ``` --- ### Upstreams #### List Upstreams ```http GET /workspaces/{workspace_id}/upstreams?page=1&per_page=20 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "aa0e8400-e29b-41d4-a716-446655440006", "workspace_id": "660e8400-e29b-41d4-a716-446655440001", "name": "api-backend", "algorithm": "round_robin", "servers": [ { "address": "10.0.1.20:8080", "weight": 1, "backup": false, "max_fails": 3, "fail_timeout": 30 }, { "address": "10.0.1.21:8080", "weight": 1, "backup": false, "max_fails": 3, "fail_timeout": 30 } ], "health_check": { "enabled": true, "path": "/health", "interval": 10, "timeout": 5 }, "created_at": "2026-02-01T10:00:00Z", "updated_at": "2026-02-15T14:30:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 5 } } ``` #### Create Upstream ```http POST /workspaces/{workspace_id}/upstreams Authorization: Bearer {token} Content-Type: application/json { "name": "web-backend", "algorithm": "least_connections", "servers": [ { "address": "10.0.1.30:8080", "weight": 2, "backup": false }, { "address": "10.0.1.31:8080", "weight": 1, "backup": false }, { "address": "10.0.1.32:8080", "weight": 1, "backup": true } ], "health_check": { "enabled": true, "path": "/health", "interval": 10, "timeout": 5 } } ``` #### Get Upstream ```http GET /upstreams/{upstream_id} Authorization: Bearer {token} ``` #### Update Upstream ```http PATCH /upstreams/{upstream_id} Authorization: Bearer {token} Content-Type: application/json { "servers": [ { "address": "10.0.1.30:8080", "weight": 3, "backup": false } ] } ``` #### Delete Upstream ```http DELETE /upstreams/{upstream_id} Authorization: Bearer {token} ``` --- ### Certificates #### List Certificates ```http GET /workspaces/{workspace_id}/certificates?page=1&per_page=20 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "990e8400-e29b-41d4-a716-446655440005", "workspace_id": "660e8400-e29b-41d4-a716-446655440001", "domain": "example.com", "is_wildcard": false, "provider": "letsencrypt", "status": "active", "issued_at": "2026-02-01T10:00:00Z", "expires_at": "2026-05-01T10:00:00Z", "auto_renew": true, "created_at": "2026-02-01T10:00:00Z" } ], "meta": { "page": 1, "per_page": 20, "total": 3 } } ``` #### Request Certificate ```http POST /workspaces/{workspace_id}/certificates Authorization: Bearer {token} Content-Type: application/json { "domain": "api.example.com", "provider": "letsencrypt", "auto_renew": true } ``` #### Get Certificate ```http GET /certificates/{certificate_id} Authorization: Bearer {token} ``` #### Delete Certificate ```http DELETE /certificates/{certificate_id} Authorization: Bearer {token} ``` --- ### Metrics #### Get Workspace Metrics ```http GET /workspaces/{workspace_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z Authorization: Bearer {token} ``` Response: ```json { "requests_total": 1234567, "requests_per_second": 150.5, "error_rate": 0.001, "active_connections": 42, "bandwidth": { "in_bytes": 1073741824, "out_bytes": 5368709120 }, "status_codes": { "2xx": 1230000, "3xx": 4000, "4xx": 500, "5xx": 67 } } ``` #### Get Agent Metrics ```http GET /agents/{agent_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z Authorization: Bearer {token} ``` --- ### Access Logs #### Query Access Logs ```http GET /workspaces/{workspace_id}/access-logs?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z&status_code=500&limit=100 Authorization: Bearer {token} ``` Response: ```json { "data": [ { "id": "bb0e8400-e29b-41d4-a716-446655440008", "agent_id": "770e8400-e29b-41d4-a716-446655440002", "timestamp": "2026-03-02T10:30:00Z", "remote_addr": "192.168.1.100", "method": "GET", "uri": "/api/error", "protocol": "HTTP/1.1", "host": "api.example.com", "status": 500, "body_bytes_sent": 123, "response_time_ms": 150.5, "user_agent": "Mozilla/5.0...", "referer": "https://example.com/", "request_id": "req-123-456" } ], "meta": { "total": 67, "limit": 100 } } ``` --- ## Error Responses All errors follow this format: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "request_id": "req-abc-123", "details": [ { "field": "server_name", "message": "Invalid domain format", "code": "INVALID_FORMAT" } ] } } ``` ### Error Codes | Code | HTTP Status | Description | |------|-------------|-------------| | `UNAUTHORIZED` | 401 | Authentication required or invalid credentials | | `FORBIDDEN` | 403 | Insufficient permissions | | `NOT_FOUND` | 404 | Resource not found | | `VALIDATION_ERROR` | 422 | Request validation failed | | `CONFLICT` | 409 | Resource conflict (e.g., duplicate slug) | | `RATE_LIMITED` | 429 | Too many requests | | `INTERNAL_ERROR` | 500 | Server internal error | | `SERVICE_UNAVAILABLE` | 503 | Service temporarily unavailable | --- ## gRPC API (Master-Agent) ### Service Definition ```protobuf syntax = "proto3"; package nxmesh.agent.v1; option go_package = "github.com/nxmesh/api/agent/v1"; // AgentService defines the bidirectional communication between master and agents service AgentService { // Stream establishes a persistent connection for real-time communication rpc Stream(stream AgentMessage) returns (stream MasterMessage); // ReportHealth sends a health report to the master rpc ReportHealth(HealthReport) returns (Ack); // ReportMetrics sends metrics batch to the master rpc ReportMetrics(MetricsBatch) returns (Ack); } // Messages sent from agent to master message AgentMessage { string agent_id = 1; int64 timestamp = 2; oneof payload { RegistrationRequest registration = 3; HealthReport health = 4; ConfigStatus config_status = 5; MetricsBatch metrics = 6; LogBatch logs = 7; Event event = 8; } } // Messages sent from master to agent message MasterMessage { int64 timestamp = 1; oneof payload { RegistrationResponse registration_response = 2; ConfigUpdate config_update = 3; Command command = 4; Ack ack = 5; Error error = 6; } } // Registration message RegistrationRequest { string token = 1; string hostname = 2; string ip_address = 3; string version = 4; repeated string capabilities = 5; map labels = 6; DeploymentMode deployment_mode = 7; } message RegistrationResponse { string agent_id = 1; bool success = 2; string error_message = 3; int64 heartbeat_interval_seconds = 4; } enum DeploymentMode { DEPLOYMENT_MODE_UNSPECIFIED = 0; DOCKER_SIDECAR = 1; KUBERNETES_SIDECAR = 2; STANDALONE = 3; } // Health Reporting message HealthReport { NginxStatus nginx = 1; SystemMetrics system = 2; string config_checksum = 3; int64 config_version = 4; repeated Alert alerts = 5; } message NginxStatus { bool is_running = 1; uint32 pid = 2; uint64 uptime_seconds = 3; uint32 active_connections = 4; uint64 total_requests = 5; float requests_per_second = 6; } message SystemMetrics { float cpu_percent = 1; uint64 memory_used_bytes = 2; uint64 memory_total_bytes = 3; uint64 disk_used_bytes = 4; uint64 disk_total_bytes = 5; float load_average_1m = 6; } message Alert { string id = 1; string severity = 2; // info, warning, error, critical string message = 3; int64 timestamp = 4; } // Configuration message ConfigUpdate { string config_id = 1; int64 version = 2; repeated VirtualHost virtual_hosts = 3; repeated Upstream upstreams = 4; map certificates = 5; GlobalSettings global_settings = 6; } message VirtualHost { string id = 1; string name = 2; string server_name = 3; uint32 listen_port = 4; bool ssl_enabled = 5; string ssl_certificate_id = 6; bool http2_enabled = 7; bool http3_enabled = 8; repeated Location locations = 9; map custom_directives = 10; } message Location { string path = 1; string proxy_pass = 2; string upstream_id = 3; string root = 4; string index = 5; repeated Header custom_headers = 6; repeated RewriteRule rewrite_rules = 7; map custom_directives = 8; } message Header { string name = 1; string value = 2; bool always = 3; } message RewriteRule { string pattern = 1; string replacement = 2; string flag = 3; } message Upstream { string id = 1; string name = 2; LoadBalanceAlgorithm algorithm = 3; repeated UpstreamServer servers = 4; HealthCheckConfig health_check = 5; uint32 keepalive_connections = 6; } enum LoadBalanceAlgorithm { LOAD_BALANCE_ALGORITHM_UNSPECIFIED = 0; ROUND_ROBIN = 1; LEAST_CONNECTIONS = 2; IP_HASH = 3; WEIGHTED_ROUND_ROBIN = 4; } message UpstreamServer { string address = 1; uint32 weight = 2; bool backup = 3; bool down = 4; uint32 max_fails = 5; uint32 fail_timeout_seconds = 6; } message HealthCheckConfig { bool enabled = 1; string path = 2; uint32 interval_seconds = 3; uint32 timeout_seconds = 4; uint32 healthy_threshold = 5; uint32 unhealthy_threshold = 6; } message Certificate { string id = 1; string domain = 2; string certificate_pem = 3; string private_key_pem = 4; int64 expires_at = 5; } message GlobalSettings { map nginx_directives = 1; map env_vars = 2; } message ConfigStatus { string config_id = 1; int64 version = 2; ConfigApplyStatus status = 3; string error_message = 4; int64 applied_at = 5; } enum ConfigApplyStatus { CONFIG_APPLY_STATUS_UNSPECIFIED = 0; PENDING = 1; VALIDATING = 2; APPLYING = 3; SUCCESS = 4; FAILED = 5; ROLLED_BACK = 6; } // Metrics message MetricsBatch { int64 timestamp = 1; repeated Metric metrics = 2; } message Metric { string name = 1; double value = 2; int64 timestamp = 3; map labels = 4; MetricType type = 5; } enum MetricType { METRIC_TYPE_UNSPECIFIED = 0; GAUGE = 1; COUNTER = 2; HISTOGRAM = 3; } // Logs message LogBatch { repeated LogEntry entries = 1; } message LogEntry { int64 timestamp = 1; string level = 2; string message = 3; map fields = 4; } // Commands message Command { string command_id = 1; oneof command { ReloadCommand reload = 2; RestartCommand restart = 3; StopCommand stop = 4; GetStatusCommand get_status = 5; ValidateConfigCommand validate_config = 6; } } message ReloadCommand { bool graceful = 1; } message RestartCommand { bool force = 1; } message StopCommand { bool graceful = 1; uint32 timeout_seconds = 2; } message GetStatusCommand {} message ValidateConfigCommand { string config_content = 1; } // Events message Event { string event_id = 1; string event_type = 2; int64 timestamp = 3; map data = 4; } // Common messages message Ack { string message_id = 1; bool success = 2; string error_message = 3; } message Error { string code = 1; string message = 2; map details = 3; } ``` --- ## WebSocket API ### Connection Connect to WebSocket endpoint with JWT token: ```javascript const ws = new WebSocket('wss://api.nxmesh.io/v1/events?token={jwt_token}'); ``` ### Event Types #### Agent Connected ```json { "type": "agent.connected", "timestamp": "2026-03-02T12:00:00Z", "data": { "agent_id": "770e8400-e29b-41d4-a716-446655440002", "hostname": "web-01.internal", "ip_address": "10.0.1.10" } } ``` #### Agent Disconnected ```json { "type": "agent.disconnected", "timestamp": "2026-03-02T12:05:00Z", "data": { "agent_id": "770e8400-e29b-41d4-a716-446655440002", "reason": "connection_timeout" } } ``` #### Config Applied ```json { "type": "config.applied", "timestamp": "2026-03-02T12:10:00Z", "data": { "agent_id": "770e8400-e29b-41d4-a716-446655440002", "config_id": "config-123", "version": 42, "duration_ms": 150, "success": true } } ``` #### Health Alert ```json { "type": "health.alert", "timestamp": "2026-03-02T12:15:00Z", "data": { "agent_id": "770e8400-e29b-41d4-a716-446655440002", "alert_id": "alert-456", "severity": "warning", "message": "High CPU usage: 85%", "metric": "cpu_percent", "value": 85.0 } } ``` ### Subscribing to Events Clients can subscribe to specific event types: ```json { "action": "subscribe", "events": ["agent.*", "config.*"], "filter": { "workspace_id": "660e8400-e29b-41d4-a716-446655440001" } } ```