# MSP Mode API Specification **Version:** 1.0.0 **Last Updated:** 2026-01-16 **Status:** Design Phase --- ## Overview FastAPI-based REST API providing secure access to MSP tracking database on Jupiter server. Designed for multi-machine access with JWT authentication and comprehensive audit logging. --- ## Base Configuration **Base URL:** `https://msp-api.azcomputerguru.com` **API Version:** `/api/v1/` **Protocol:** HTTPS only (no HTTP) **Authentication:** JWT Bearer tokens **Content-Type:** `application/json` --- ## Authentication ### JWT Token Structure #### Access Token (Short-lived: 1 hour) ```json { "sub": "mike@azcomputerguru.com", "scopes": ["msp:read", "msp:write", "msp:admin"], "machine": "windows-workstation", "exp": 1234567890, "iat": 1234567890, "jti": "unique-token-id" } ``` #### Refresh Token (Long-lived: 30 days) - Stored securely in Gitea config - Used to obtain new access tokens - Can be revoked server-side ### Permission Scopes - **`msp:read`** - Read sessions, clients, work items - **`msp:write`** - Create/update sessions, work items - **`msp:admin`** - Manage clients, credentials, delete operations ### Authentication Endpoints #### POST /api/v1/auth/token Obtain JWT access token. **Request:** ```json { "refresh_token": "string" } ``` **Response:** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "bearer", "expires_in": 3600, "scopes": ["msp:read", "msp:write"] } ``` **Status Codes:** - `200` - Token issued successfully - `401` - Invalid refresh token - `403` - Token revoked #### POST /api/v1/auth/refresh Refresh expired access token. **Request:** ```json { "refresh_token": "string" } ``` **Response:** ```json { "access_token": "eyJhbGciOiJIUzI1NiIs...", "expires_in": 3600 } ``` --- ## Core API Endpoints ### Machine Detection & Management #### GET /api/v1/machines List all registered machines. **Query Parameters:** - `is_active` (boolean) - Filter by active status - `platform` (string) - Filter by platform (win32, darwin, linux) **Response:** ```json { "machines": [ { "id": "uuid", "hostname": "ACG-M-L5090", "friendly_name": "Main Laptop", "platform": "win32", "has_vpn_access": true, "vpn_profiles": ["dataforth", "grabb"], "has_docker": true, "powershell_version": "7.4", "available_mcps": ["claude-in-chrome", "filesystem"], "available_skills": ["pdf", "commit", "review-pr"], "last_seen": "2026-01-16T10:30:00Z" } ] } ``` #### POST /api/v1/machines Register new machine (auto-detection on first session). **Request:** ```json { "hostname": "ACG-M-L5090", "machine_fingerprint": "sha256hash", "platform": "win32", "os_version": "Windows 11 Pro", "username": "MikeSwanson", "friendly_name": "Main Laptop", "has_vpn_access": true, "vpn_profiles": ["dataforth", "grabb"], "has_docker": true, "powershell_version": "7.4", "preferred_shell": "powershell", "available_mcps": ["claude-in-chrome"], "available_skills": ["pdf", "commit"] } ``` **Response:** ```json { "id": "uuid", "machine_fingerprint": "sha256hash", "created_at": "2026-01-16T10:00:00Z" } ``` #### GET /api/v1/machines/{fingerprint} Get machine by fingerprint (for session start auto-detection). **Response:** ```json { "id": "uuid", "hostname": "ACG-M-L5090", "friendly_name": "Main Laptop", "capabilities": { "vpn_profiles": ["dataforth", "grabb"], "has_docker": true, "powershell_version": "7.4" } } ``` #### PUT /api/v1/machines/{id} Update machine capabilities. ### Sessions #### POST /api/v1/sessions Create new MSP session. **Request:** ```json { "client_id": "uuid", "project_id": "uuid", "machine_id": "uuid", "session_date": "2026-01-16", "start_time": "2026-01-16T10:00:00Z", "session_title": "Dataforth - DOS UPDATE.BAT enhancement", "technician": "Mike Swanson", "status": "in_progress" } ``` **Response:** ```json { "id": "uuid", "session_date": "2026-01-16", "start_time": "2026-01-16T10:00:00Z", "status": "in_progress", "created_at": "2026-01-16T10:00:00Z" } ``` **Status Codes:** - `201` - Session created - `400` - Invalid request data - `401` - Unauthorized - `404` - Client/Project not found #### GET /api/v1/sessions Query sessions with filters. **Query Parameters:** - `client_id` (uuid) - Filter by client - `project_id` (uuid) - Filter by project - `machine_id` (uuid) - Filter by machine - `date_from` (date) - Start date range - `date_to` (date) - End date range - `is_billable` (boolean) - Filter billable sessions - `status` (string) - Filter by status - `limit` (int) - Max results (default: 50) - `offset` (int) - Pagination offset **Response:** ```json { "sessions": [ { "id": "uuid", "client_name": "Dataforth", "project_name": "DOS Machine Management", "session_date": "2026-01-15", "duration_minutes": 210, "billable_hours": 3.5, "session_title": "DOS UPDATE.BAT v2.0 completion", "summary": "Completed UPDATE.BAT automation...", "status": "completed" } ], "total": 45, "limit": 50, "offset": 0 } ``` #### GET /api/v1/sessions/{id} Get session details with related work items. **Response:** ```json { "id": "uuid", "client_id": "uuid", "client_name": "Dataforth", "project_name": "DOS Machine Management", "session_date": "2026-01-15", "start_time": "2026-01-15T14:00:00Z", "end_time": "2026-01-15T17:30:00Z", "duration_minutes": 210, "billable_hours": 3.5, "session_title": "DOS UPDATE.BAT v2.0", "summary": "markdown summary", "work_items": [ { "id": "uuid", "category": "development", "title": "Enhanced UPDATE.BAT with version checking", "status": "completed" } ], "tags": ["dos", "batch", "automation", "dataforth"], "technologies_used": ["dos-6.22", "batch", "networking"] } ``` #### PUT /api/v1/sessions/{id} Update session (typically at session end). **Request:** ```json { "end_time": "2026-01-16T12:30:00Z", "status": "completed", "summary": "markdown summary", "billable_hours": 2.5, "notes": "Additional session notes" } ``` ### Work Items #### POST /api/v1/work-items Create work item for session. **Request:** ```json { "session_id": "uuid", "category": "troubleshooting", "title": "Fixed Apache SSL certificate expiration", "description": "Problem: ERR_SSL_PROTOCOL_ERROR\nCause: Cert expired\nFix: certbot renew", "status": "completed", "priority": "high", "is_billable": true, "actual_minutes": 45, "affected_systems": ["jupiter", "172.16.3.20"], "technologies_used": ["apache", "ssl", "certbot"] } ``` **Response:** ```json { "id": "uuid", "session_id": "uuid", "category": "troubleshooting", "title": "Fixed Apache SSL certificate expiration", "created_at": "2026-01-16T10:15:00Z" } ``` #### GET /api/v1/work-items Query work items. **Query Parameters:** - `session_id` (uuid) - Filter by session - `category` (string) - Filter by category - `status` (string) - Filter by status - `date_from` (date) - Start date - `date_to` (date) - End date ### Clients #### GET /api/v1/clients List all clients. **Query Parameters:** - `type` (string) - Filter by type (msp_client, internal, project) - `is_active` (boolean) - Active clients only **Response:** ```json { "clients": [ { "id": "uuid", "name": "Dataforth", "type": "msp_client", "network_subnet": "192.168.0.0/24", "is_active": true } ] } ``` #### POST /api/v1/clients Create new client record. **Request:** ```json { "name": "Client Name", "type": "msp_client", "network_subnet": "192.168.1.0/24", "domain_name": "client.local", "primary_contact": "John Doe", "notes": "Additional information" } ``` **Requires:** `msp:admin` scope #### GET /api/v1/clients/{id} Get client details with infrastructure. **Response:** ```json { "id": "uuid", "name": "Dataforth", "network_subnet": "192.168.0.0/24", "infrastructure": [ { "hostname": "AD2", "ip_address": "192.168.0.6", "asset_type": "domain_controller", "os": "Windows Server 2022" } ], "active_projects": 3, "recent_sessions": 15 } ``` ### Credentials #### GET /api/v1/credentials Query credentials (encrypted values not returned by default). **Query Parameters:** - `client_id` (uuid) - Filter by client - `service_id` (uuid) - Filter by service - `credential_type` (string) - Filter by type **Response:** ```json { "credentials": [ { "id": "uuid", "client_name": "Dataforth", "service_name": "AD2 Administrator", "username": "sysadmin", "credential_type": "password", "requires_vpn": true, "last_rotated_at": "2025-12-01T00:00:00Z" } ] } ``` **Note:** Password values not included. Use decrypt endpoint. #### POST /api/v1/credentials Store new credential (encrypted). **Request:** ```json { "client_id": "uuid", "service_name": "AD2 Administrator", "username": "sysadmin", "password": "plaintext-password", "credential_type": "password", "requires_vpn": true, "requires_2fa": false } ``` **Response:** ```json { "id": "uuid", "service_name": "AD2 Administrator", "created_at": "2026-01-16T10:00:00Z" } ``` **Requires:** `msp:write` scope #### GET /api/v1/credentials/{id}/decrypt Decrypt and return credential value. **Response:** ```json { "credential_id": "uuid", "service_name": "AD2 Administrator", "username": "sysadmin", "password": "decrypted-password", "accessed_at": "2026-01-16T10:30:00Z" } ``` **Side Effects:** - Creates audit log entry - Records access in `credential_audit_log` table **Requires:** `msp:read` scope minimum ### Infrastructure #### GET /api/v1/infrastructure Query infrastructure assets. **Query Parameters:** - `client_id` (uuid) - Filter by client - `asset_type` (string) - Filter by type - `hostname` (string) - Search by hostname **Response:** ```json { "infrastructure": [ { "id": "uuid", "client_name": "Dataforth", "hostname": "D2TESTNAS", "ip_address": "192.168.0.9", "asset_type": "nas_storage", "os": "ReadyNAS OS", "environmental_notes": "Manual WINS install, SMB1 only", "powershell_version": null, "has_gui": true } ] } ``` #### GET /api/v1/infrastructure/{id}/insights Get environmental insights for infrastructure. **Response:** ```json { "infrastructure_id": "uuid", "hostname": "D2TESTNAS", "insights": [ { "category": "custom_installations", "title": "WINS: Manual Samba installation", "description": "WINS service manually installed via Samba nmbd...", "examples": ["ssh root@192.168.0.9 'ps aux | grep nmbd'"], "priority": 9 } ], "limitations": ["no_native_wins_service", "smb1_only"], "recommended_commands": { "check_wins": "ssh root@192.168.0.9 'ps aux | grep nmbd'" } } ``` ### Commands & Failures #### POST /api/v1/commands Log command execution (with failure tracking). **Request:** ```json { "work_item_id": "uuid", "session_id": "uuid", "command_text": "Get-LocalUser", "host": "old-server-2008", "shell_type": "powershell", "success": false, "exit_code": 1, "error_message": "Get-LocalUser : The term Get-LocalUser is not recognized", "failure_category": "compatibility" } ``` **Response:** ```json { "id": "uuid", "created_at": "2026-01-16T10:00:00Z", "failure_logged": true } ``` **Side Effects:** - If failure: Triggers Failure Analysis Agent - May create `failure_patterns` entry - May update `environmental_insights` #### GET /api/v1/failure-patterns Query known failure patterns. **Query Parameters:** - `infrastructure_id` (uuid) - Patterns for specific infrastructure - `pattern_type` (string) - Filter by type **Response:** ```json { "patterns": [ { "id": "uuid", "pattern_signature": "PowerShell 7 cmdlets on Server 2008", "error_pattern": "Get-LocalUser.*not recognized", "root_cause": "Server 2008 only has PowerShell 2.0", "recommended_solution": "Use Get-WmiObject Win32_UserAccount", "occurrence_count": 5, "severity": "major" } ] } ``` ### Tasks & Todo Items #### GET /api/v1/pending-tasks Query open tasks. **Query Parameters:** - `client_id` (uuid) - Filter by client - `priority` (string) - Filter by priority - `status` (string) - Filter by status **Response:** ```json { "tasks": [ { "id": "uuid", "client_name": "Dataforth", "title": "Create Datasheets share", "priority": "high", "status": "blocked", "blocked_by": "Waiting on Engineering", "due_date": "2026-01-20" } ] } ``` #### POST /api/v1/pending-tasks Create pending task. **Request:** ```json { "client_id": "uuid", "project_id": "uuid", "title": "Task title", "description": "Task description", "priority": "high", "due_date": "2026-01-20" } ``` ### External Integrations #### GET /api/v1/integrations List configured integrations (SyncroMSP, MSP Backups, etc.). **Response:** ```json { "integrations": [ { "integration_name": "syncro", "integration_type": "psa", "is_active": true, "last_tested_at": "2026-01-15T08:00:00Z", "last_test_status": "success" } ] } ``` #### POST /api/v1/integrations/{name}/test Test integration connection. **Response:** ```json { "integration_name": "syncro", "status": "success", "message": "Connection successful", "tested_at": "2026-01-16T10:00:00Z" } ``` #### GET /api/v1/syncro/tickets Search SyncroMSP tickets. **Query Parameters:** - `customer` (string) - Filter by customer name - `subject` (string) - Search ticket subjects - `status` (string) - Filter by status **Response:** ```json { "tickets": [ { "ticket_id": "12345", "ticket_number": "T12345", "subject": "Backup configuration for NAS", "customer": "Dataforth", "status": "open", "created_at": "2026-01-10T12:00:00Z" } ] } ``` #### POST /api/v1/syncro/tickets/{id}/comment Add comment to SyncroMSP ticket. **Request:** ```json { "comment": "Work completed: configured Veeam backup..." } ``` **Response:** ```json { "comment_id": "67890", "created_at": "2026-01-16T10:00:00Z" } ``` **Side Effects:** - Creates `external_integrations` log entry - Links to current session ### Health & Monitoring #### GET /api/v1/health Health check endpoint. **Response:** ```json { "status": "healthy", "database": "connected", "timestamp": "2026-01-16T10:00:00Z", "version": "1.0.0" } ``` **Status Codes:** - `200` - Service healthy - `503` - Service unavailable #### GET /api/v1/metrics Prometheus metrics (optional). **Response:** Prometheus format metrics --- ## Error Handling ### Standard Error Response Format ```json { "error": { "code": "INVALID_REQUEST", "message": "Client ID is required", "details": { "field": "client_id", "constraint": "not_null" } }, "timestamp": "2026-01-16T10:00:00Z", "request_id": "uuid" } ``` ### HTTP Status Codes - **200** - Success - **201** - Created - **400** - Bad Request (invalid input) - **401** - Unauthorized (missing/invalid token) - **403** - Forbidden (insufficient permissions) - **404** - Not Found - **409** - Conflict (duplicate record) - **429** - Too Many Requests (rate limit) - **500** - Internal Server Error (never expose DB errors) - **503** - Service Unavailable ### Error Codes - `INVALID_REQUEST` - Malformed request - `UNAUTHORIZED` - Missing or invalid authentication - `FORBIDDEN` - Insufficient permissions - `NOT_FOUND` - Resource not found - `DUPLICATE_ENTRY` - Unique constraint violation - `RATE_LIMIT_EXCEEDED` - Too many requests - `DATABASE_ERROR` - Internal database error (details hidden) - `ENCRYPTION_ERROR` - Credential encryption/decryption failed --- ## Rate Limiting **Default Limits:** - 100 requests per minute per token - 1000 requests per hour per token - Credential decryption: 20 per minute **Headers:** ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 87 X-RateLimit-Reset: 1234567890 ``` **Exceeded Response:** ```json { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Retry after 60 seconds.", "retry_after": 60 } } ``` --- ## Agent Coordination Patterns ### Agent API Access All specialized agents use the same API with agent-specific tokens: **Agent Token Claims:** ```json { "sub": "agent:context-recovery", "agent_type": "context_recovery", "scopes": ["msp:read"], "parent_session": "uuid", "exp": 1234567890 } ``` ### Agent Communication Flow ``` Main Claude (JWT: user token) ↓ Launches Agent (JWT: agent token, scoped to parent session) ↓ Agent makes API calls (authenticated with agent token) ↓ API logs agent activity (tracks parent session) ↓ Agent returns summary to Main Claude ``` ### Example: Context Recovery Agent **Request Flow:** 1. Main Claude: POST /api/v1/agents/context-recovery 2. API issues agent token (scoped: msp:read, session_id) 3. Agent executes: - GET /api/v1/sessions?client_id=X&limit=5 - GET /api/v1/pending-tasks?client_id=X - GET /api/v1/infrastructure?client_id=X 4. Agent processes results, generates summary 5. Agent returns to Main Claude (API logs all agent activity) **Agent Audit Trail:** - All agent API calls logged with parent session - Agent execution time tracked - Agent results cached (avoid redundant queries) --- ## Security Considerations ### Encryption - **In Transit:** HTTPS only (TLS 1.2+) - **At Rest:** AES-256-GCM for credentials - **Key Management:** Environment variable or vault (not in database) ### Authentication - JWT tokens with short expiration (1 hour access, 30 day refresh) - Token rotation supported - Revocation list for compromised tokens ### Audit Logging - All credential access logged (`credential_audit_log`) - All API requests logged (`api_audit_log`) - User ID, IP address, timestamp, action recorded ### Input Validation - Pydantic models validate all inputs - SQL injection prevention via SQLAlchemy ORM - XSS prevention (JSON only, no HTML) ### Rate Limiting - Per-token rate limits - Credential access rate limits (stricter) - IP-based limits (optional) --- ## Configuration Storage ### Gitea Repository **Repo:** `azcomputerguru/msp-config` **File:** `msp-api-config.json` ```json { "api_url": "https://msp-api.azcomputerguru.com", "refresh_token": "encrypted_token_value", "database_schema_version": "1.0.0", "machine_id": "uuid" } ``` **Encryption:** git-crypt or encrypted JSON values --- ## Implementation Status - [OK] API Design (this document) - ⏳ FastAPI implementation - ⏳ Database schema deployment - ⏳ JWT authentication flow - ⏳ Agent token system - ⏳ External integrations (SyncroMSP, MSP Backups) --- ## Version History **v1.0.0 (2026-01-16):** - Initial API specification - Machine detection endpoints - Core CRUD operations - Authentication flow - Agent coordination patterns - External integrations design