{"openapi":"3.0.0","info":{"title":"MyApi","version":"0.1.0","description":"Personal API platform with scope-aware discovery and automation-friendly endpoints."},"servers":[{"url":"https://myapi.techdigital.ci"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token"}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"DiscoveryRequest":{"type":"object","required":["websiteUrl"],"properties":{"websiteUrl":{"type":"string","format":"uri","example":"https://example.com"}}},"VaultTokenCreateRequest":{"type":"object","required":["name","service","token","websiteUrl"],"properties":{"name":{"type":"string","example":"GitHub PAT"},"service":{"type":"string","example":"github"},"token":{"type":"string","example":"ghp_xxx"},"websiteUrl":{"type":"string","format":"uri","example":"https://github.com"},"discoverApi":{"type":"boolean","example":true}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/v1/capabilities":{"get":{"summary":"Scope-aware capability manifest","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/v1/tokens/me/capabilities":{"get":{"summary":"Current token capabilities","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/v1/auth/register":{"post":{"summary":"Register user","responses":{"201":{"description":"Created"}}}},"/api/v1/auth/login":{"post":{"summary":"Login","responses":{"200":{"description":"OK"}}}},"/api/v1/auth/logout":{"post":{"summary":"Logout","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/v1/auth/me":{"get":{"summary":"Current user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/v1/identity":{"get":{"summary":"Read identity","security":[{"bearerAuth":[]}]}},"/api/v1/identity/professional":{"get":{"summary":"Read professional identity","security":[{"bearerAuth":[]}]}},"/api/v1/identity/availability":{"get":{"summary":"Read availability identity","security":[{"bearerAuth":[]}]}},"/api/v1/preferences":{"get":{"summary":"Get preferences","security":[{"bearerAuth":[]}]},"put":{"summary":"Update preferences","security":[{"bearerAuth":[]}]}},"/api/v1/vault/discover-api":{"post":{"summary":"Discover API metadata","security":[{"bearerAuth":[]}]}},"/api/v1/vault/tokens":{"get":{"summary":"List vault tokens","security":[{"bearerAuth":[]}]},"post":{"summary":"Store API token with optional API discovery","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultTokenCreateRequest"}}}},"responses":{"201":{"description":"Created"}}}},"/api/v1/vault/tokens/{id}/reveal":{"get":{"summary":"Decrypt and reveal vault token value (MASTER TOKEN REQUIRED)","description":"Returns the decrypted actual token/credential value. CRITICAL: This endpoint is required to retrieve stored credentials for use. Only master token can decrypt. All access is audit-logged.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Token decrypted successfully - check data.token for actual value"},"403":{"description":"Only master token can decrypt vault tokens"},"404":{"description":"Token not found"}}}},"/api/v1/vault/tokens/{id}":{"delete":{"summary":"Delete vault token","security":[{"bearerAuth":[]}]}},"/api/v1/tokens":{"get":{"summary":"List master tokens","security":[{"bearerAuth":[]}]},"post":{"summary":"Create master token","security":[{"bearerAuth":[]}]}},"/api/v1/tokens/{id}":{"get":{"summary":"Get token","security":[{"bearerAuth":[]}]},"put":{"summary":"Update token","security":[{"bearerAuth":[]}]},"delete":{"summary":"Revoke token","security":[{"bearerAuth":[]}]}},"/api/v1/tokens/{id}/regenerate":{"post":{"summary":"Regenerate token secret","security":[{"bearerAuth":[]}]}},"/api/v1/tokens/master/regenerate":{"post":{"summary":"Regenerate master token","security":[{"bearerAuth":[]}]}},"/api/v1/scopes":{"get":{"summary":"List scopes","security":[{"bearerAuth":[]}]}},"/api/v1/connectors":{"get":{"summary":"List connectors","security":[{"bearerAuth":[]}]},"post":{"summary":"Create connector","security":[{"bearerAuth":[]}]}},"/api/v1/gateway/context":{"get":{"summary":"Gateway context","security":[{"bearerAuth":[]}]}},"/api/v1/audit/log":{"get":{"summary":"Audit logs","security":[{"bearerAuth":[]}]}},"/api/v1/users/me":{"get":{"summary":"Get authenticated user identity","scope":"identity"}},"/api/v1/users":{"get":{"summary":"List users","security":[{"bearerAuth":[]}]},"post":{"summary":"Create user","security":[{"bearerAuth":[]}]}},"/api/v1/users/{id}/plan":{"put":{"summary":"Update user plan","security":[{"bearerAuth":[]}]}},"/api/v1/handshakes":{"get":{"summary":"List handshakes","security":[{"bearerAuth":[]}]},"post":{"summary":"Create handshake (public for AI agents)","description":"Submit an access request. Returns handshakeId for polling status."}},"/api/v1/handshakes/{id}/status":{"get":{"summary":"Poll handshake approval status","description":"Retrieve handshake status without authentication (public endpoint for AI agents to poll)."}},"/api/v1/handshakes/{id}/approve":{"post":{"summary":"Approve handshake","security":[{"bearerAuth":[]}]}},"/api/v1/handshakes/{id}/deny":{"post":{"summary":"Deny handshake","security":[{"bearerAuth":[]}]}},"/api/v1/handshakes/{id}":{"delete":{"summary":"Revoke handshake","security":[{"bearerAuth":[]}]}},"/api/v1/personas":{"get":{"summary":"List personas","security":[{"bearerAuth":[]}]},"post":{"summary":"Create persona","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}":{"get":{"summary":"Get persona","security":[{"bearerAuth":[]}]},"put":{"summary":"Update persona","security":[{"bearerAuth":[]}]},"delete":{"summary":"Delete persona","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}/activate":{"post":{"summary":"Activate persona","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}/documents":{"get":{"summary":"List persona docs","security":[{"bearerAuth":[]}]},"post":{"summary":"Attach doc to persona","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}/documents/{docId}":{"delete":{"summary":"Detach persona doc","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}/skills":{"get":{"summary":"List persona skills","security":[{"bearerAuth":[]}]},"post":{"summary":"Attach skill to persona","security":[{"bearerAuth":[]}]}},"/api/v1/personas/{id}/skills/{skillId}":{"delete":{"summary":"Detach skill from persona","security":[{"bearerAuth":[]}]}},"/api/v1/skills":{"get":{"summary":"List skills","description":"Returns all skills for the authenticated owner. Supports filtering via query params to avoid fetching large payloads.","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"query","description":"Filter by slug (skill name, case-insensitive)","schema":{"type":"string"}},{"name":"category","in":"query","description":"Filter by category (case-insensitive)","schema":{"type":"string"}},{"name":"q","in":"query","description":"Full-text search across name, description, category","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (1-200)","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Array of skills with origin metadata and slug field"}}},"post":{"summary":"Create skill","description":"Creates a skill. YAML frontmatter in scriptContent is automatically sanitized.","security":[{"bearerAuth":[]}]}},"/api/v1/skills/suggestions":{"get":{"summary":"Skill name suggestions (AI discovery)","description":"Returns up to 10 matching skills by name/description/category. Useful for AI agents that don't know the exact slug.","security":[{"bearerAuth":[]}],"parameters":[{"name":"q","in":"query","required":true,"description":"Search query","schema":{"type":"string"}}],"responses":{"200":{"description":"List of {id, slug, name, description, category} suggestions"}}}},"/api/v1/skills/_by_slug/{slug}":{"get":{"summary":"Get skill by slug/name","description":"Retrieve a skill directly by its name (slug) without needing the numeric ID. Preferred for AI agent access.","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"description":"Skill name (case-insensitive)","schema":{"type":"string"}}],"responses":{"200":{"description":"Skill object"},"404":{"description":"Not found"}}}},"/api/v1/skills/_batch":{"get":{"summary":"Batch fetch multiple skills","description":"Fetch multiple skills by numeric id or slug in a single request. Pass ?id=1&id=2 or ?slug=homeassistant&slug=tts.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"query","description":"Skill numeric ID (repeatable)","schema":{"type":"array","items":{"type":"integer"}}},{"name":"slug","in":"query","description":"Skill name/slug (repeatable)","schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Array of matching skills"}}}},"/api/v1/skills/{id}":{"get":{"summary":"Get skill","security":[{"bearerAuth":[]}]},"put":{"summary":"Update skill","security":[{"bearerAuth":[]}]},"delete":{"summary":"Delete skill","security":[{"bearerAuth":[]}]}},"/api/v1/skills/{id}/content":{"get":{"summary":"Get skill SKILL.md content","description":"Returns the raw SKILL.md content. Accept: text/markdown returns plain text; default JSON wraps it with metadata.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Skill content as JSON {id, slug, name, content} or text/markdown"}}}},"/api/v1/skills/{id}/skill.md":{"get":{"summary":"Get SKILL.md raw markdown","description":"Returns raw text/markdown of the skill content (alias for /:id/content with Accept: text/markdown).","security":[{"bearerAuth":[]}]},"put":{"summary":"Set SKILL.md content (YAML frontmatter auto-sanitized)","security":[{"bearerAuth":[]}]}},"/api/v1/skills/{id}/activate":{"post":{"summary":"Activate skill","security":[{"bearerAuth":[]}]}},"/api/v1/skills/{id}/documents":{"get":{"summary":"List skill docs","security":[{"bearerAuth":[]}]},"post":{"summary":"Attach doc to skill","security":[{"bearerAuth":[]}]}},"/api/v1/skills/{id}/documents/{docId}":{"delete":{"summary":"Detach doc from skill","security":[{"bearerAuth":[]}]}},"/api/v1/skills/{id}/attachments":{"get":{"summary":"List skill persona attachments","security":[{"bearerAuth":[]}]}},"/api/v1/memory":{"get":{"summary":"List memory entries","description":"Returns all stored memory entries for the owner, newest first. Included in gateway/context so every AI session starts with full memory.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of memory entries","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"mem_abc123"},"content":{"type":"string","example":"User prefers concise responses"},"created_at":{"type":"string","format":"date-time"}}}}}}}}}}},"post":{"summary":"Store a memory entry","description":"Persist a freeform markdown note. Appears in every future GET /api/v1/gateway/context call so any AI — regardless of platform — can resume context.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"Freeform markdown text to remember","example":"User is building a SaaS product. Prefers TypeScript. Timezone: US/Eastern."}}}}}},"responses":{"201":{"description":"Memory entry created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string"},"created_at":{"type":"string"}}}}}}}}}},"delete":{"summary":"Clear all memories","description":"Delete every memory entry for this owner. Irreversible.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"integer"}}}}}}}}},"/api/v1/memory/{id}":{"patch":{"summary":"Update a memory entry","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"summary":"Delete a memory entry","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/brain/knowledge-base":{"get":{"summary":"List KB docs","operationId":"listKBDocuments","security":[{"bearerAuth":[]}]},"post":{"summary":"Create KB doc","operationId":"createKBDocument","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content"],"properties":{"title":{"type":"string","description":"Document title"},"content":{"type":"string","description":"Document content (markdown or plain text)"},"source":{"type":"string","description":"Source identifier (defaults to \"agent\")","default":"agent"}}}}}},"responses":{"200":{"description":"Document created"}}}},"/api/v1/brain/knowledge-base/upsert":{"post":{"summary":"Create or update KB doc by title","operationId":"upsertKBDocument","description":"Creates a new document or updates an existing one with the same title. Ideal for agents maintaining persistent named documents like \"memory.md\".","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content"],"properties":{"title":{"type":"string","description":"Document title (used as unique key for upsert)"},"content":{"type":"string","description":"Full document content (markdown or plain text)"},"source":{"type":"string","description":"Source identifier (defaults to \"agent\")","default":"agent"}}}}}},"responses":{"200":{"description":"Document created or updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"action":{"type":"string","enum":["created","updated"]},"document":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}}}}}}}}}}},"/api/v1/brain/knowledge-base/{id}":{"get":{"summary":"Get KB doc","operationId":"getKBDocument","security":[{"bearerAuth":[]}]},"put":{"summary":"Update KB doc","operationId":"updateKBDocument","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"title":{"type":"string"},"content":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"summary":"Delete KB doc","operationId":"deleteKBDocument","security":[{"bearerAuth":[]}]}},"/api/v1/brain/knowledge-base/{id}/attachments":{"get":{"summary":"KB attachment usage","security":[{"bearerAuth":[]}]}},"/api/v1/brain/knowledge-base/upload":{"post":{"summary":"Upload KB document","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"document":{"type":"string","format":"binary"},"upload":{"type":"string","format":"binary"},"kbFile":{"type":"string","format":"binary"}}}}}},"responses":{"201":{"description":"Created"}}}},"/api/v1/marketplace/listings":{"get":{"summary":"List marketplace","security":[{"bearerAuth":[]}]},"post":{"summary":"Create listing","security":[{"bearerAuth":[]}]}},"/api/v1/marketplace/listings/{id}":{"get":{"summary":"Get listing","security":[{"bearerAuth":[]}]},"put":{"summary":"Update listing","security":[{"bearerAuth":[]}]},"delete":{"summary":"Delete listing","security":[{"bearerAuth":[]}]}},"/api/v1/marketplace/listings/{id}/rate":{"post":{"summary":"Rate listing","security":[{"bearerAuth":[]}]}},"/api/v1/marketplace/listings/{id}/install":{"post":{"summary":"Install listing","security":[{"bearerAuth":[]}]}},"/api/v1/marketplace/my-listings":{"get":{"summary":"My listings","security":[{"bearerAuth":[]}]}},"/api/v1/services/categories":{"get":{"summary":"Service categories","security":[{"bearerAuth":[]}]}},"/api/v1/services":{"get":{"summary":"List services","security":[{"bearerAuth":[]}]}},"/api/v1/services/{name}":{"get":{"summary":"Get service","security":[{"bearerAuth":[]}]}},"/api/v1/services/{serviceId}/methods":{"get":{"summary":"Service methods","security":[{"bearerAuth":[]}]}},"/api/v1/services/{serviceName}/execute":{"post":{"summary":"Execute service method","security":[{"bearerAuth":[]}]}},"/api/v1/services/{serviceName}/proxy":{"post":{"summary":"Proxy raw API request to service","security":[{"bearerAuth":[]}]}},"/api/v1/services/google/gmail/messages":{"get":{"operationId":"listGmailMessages","summary":"List Gmail messages","description":"Fetch recent emails from the connected Gmail account. Returns subject, sender, date, and snippet for each message.","security":[{"bearerAuth":[]}],"parameters":[{"name":"maxResults","in":"query","schema":{"type":"integer","default":5,"maximum":20},"description":"Number of messages to return"},{"name":"q","in":"query","schema":{"type":"string"},"description":"Gmail search query (e.g. \"is:unread\", \"from:boss@example.com\")"},{"name":"pageToken","in":"query","schema":{"type":"string"},"description":"Page token for pagination"}],"responses":{"200":{"description":"List of email messages","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"threadId":{"type":"string"},"subject":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"date":{"type":"string"},"snippet":{"type":"string"},"isUnread":{"type":"boolean"}}}},"nextPageToken":{"type":"string","nullable":true}}}}}},"403":{"description":"Google not connected"}}}},"/api/v1/services/google/gmail/messages/{messageId}":{"get":{"operationId":"getGmailMessage","summary":"Get a Gmail message","description":"Fetch the full content of a single Gmail message by ID.","security":[{"bearerAuth":[]}],"parameters":[{"name":"messageId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full email message","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"object","properties":{"id":{"type":"string"},"subject":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"date":{"type":"string"},"snippet":{"type":"string"},"body":{"type":"string"},"isUnread":{"type":"boolean"}}}}}}}}}},"delete":{"operationId":"trashGmailMessage","summary":"Move a Gmail message to Trash","description":"Moves a Gmail message to the Trash folder (not permanent deletion).","security":[{"bearerAuth":[]}],"parameters":[{"name":"messageId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Message trashed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string"},"trashed":{"type":"boolean"}}}}}}}}},"/api/v1/services/google/gmail/send":{"post":{"operationId":"sendGmailMessage","summary":"Send an email via Gmail","description":"Send an email from the connected Gmail account.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","subject","body"],"properties":{"to":{"type":"string","description":"Recipient email address"},"subject":{"type":"string","description":"Email subject"},"body":{"type":"string","description":"Plain text email body"},"cc":{"type":"string","description":"CC email address(es)","nullable":true},"bcc":{"type":"string","description":"BCC email address(es)","nullable":true}}}}}},"responses":{"200":{"description":"Email sent","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string"},"threadId":{"type":"string"}}}}}}}}},"/api/v1/services/google/drive/files":{"get":{"operationId":"listDriveFiles","summary":"List Google Drive files","description":"List files in the connected Google Drive. Supports Drive search query syntax.","security":[{"bearerAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Drive search query (e.g. \"name contains 'report'\")"},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"pageToken","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Drive files list"},"401":{"description":"Google not connected or missing drive.file scope"}}}},"/api/v1/services/google/drive/upload":{"post":{"operationId":"uploadDriveFile","summary":"Upload a file to Google Drive","description":"Upload text or binary content as a new file in Google Drive. Requires Google reconnect with drive.file scope.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","content"],"properties":{"name":{"type":"string","description":"Filename in Drive"},"content":{"type":"string","description":"File content (text or base64)"},"mimeType":{"type":"string","default":"text/plain"},"encoding":{"type":"string","enum":["utf8","base64"],"default":"utf8"},"folderId":{"type":"string","description":"Optional Drive folder ID"}}}}}},"responses":{"200":{"description":"File uploaded successfully"},"403":{"description":"Insufficient Drive scope — reconnect Google"}}}},"/api/v1/services/google/drive/files/{fileId}":{"delete":{"operationId":"deleteDriveFile","summary":"Delete a Google Drive file","security":[{"bearerAuth":[]}],"parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File deleted"}}}},"/api/v1/afp/devices":{"get":{"operationId":"listAfpDevices","summary":"List registered AFP devices (PCs)","description":"Returns all PCs with AFP daemon installed, their online/offline status, platform, and privilege level.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of AFP devices"}}}},"/api/v1/afp/{deviceId}/ls":{"get":{"operationId":"afpListDir","summary":"List a directory on a remote PC","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"Absolute path (e.g. C:\\Users or /home/user)"}],"responses":{"200":{"description":"Directory entries"},"503":{"description":"Device offline"}}}},"/api/v1/afp/{deviceId}/read":{"get":{"operationId":"afpReadFile","summary":"Read a file from a remote PC","description":"Returns file content as UTF-8 or base64 (for binary files).","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"path","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content"},"503":{"description":"Device offline"}}}},"/api/v1/afp/{deviceId}/write":{"post":{"operationId":"afpWriteFile","summary":"Write a file to a remote PC","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string"},"content":{"type":"string"},"encoding":{"type":"string","enum":["utf8","base64"],"default":"utf8"}}}}}},"responses":{"200":{"description":"File written"},"503":{"description":"Device offline"}}}},"/api/v1/afp/{deviceId}/exec":{"post":{"operationId":"afpExec","summary":"Execute a shell command on a remote PC","description":"Runs a shell command on the target PC. Returns stdout, stderr, and exit code. Hard timeout: 60s.","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"string","description":"Shell command to run","example":"whoami"},"cwd":{"type":"string","description":"Working directory"},"timeout":{"type":"integer","default":30000,"maximum":60000,"description":"Timeout in ms"}}}}}},"responses":{"200":{"description":"Command result with stdout/stderr/exitCode"},"503":{"description":"Device offline"},"504":{"description":"Command timed out"}}}},"/api/v1/afp/{deviceId}/stat":{"get":{"operationId":"afpStat","summary":"Get file/directory metadata on a remote PC","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"path","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File metadata"}}}},"/api/v1/afp/{deviceId}/rm":{"delete":{"operationId":"afpDelete","summary":"Delete a file or directory on a remote PC","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path"],"properties":{"path":{"type":"string"},"recursive":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Deleted"}}}},"/api/v1/afp/{deviceId}/mkdir":{"post":{"operationId":"afpMkdir","summary":"Create a directory on a remote PC","security":[{"bearerAuth":[]}],"parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path"],"properties":{"path":{"type":"string"},"recursive":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Directory created"}}}},"/api/v1/afp/download/{platform}":{"get":{"operationId":"downloadAfpDaemon","summary":"Download AFP daemon binary","description":"Download the AFP daemon executable for the target platform. No authentication required.","parameters":[{"name":"platform","in":"path","required":true,"schema":{"type":"string","enum":["linux","mac","mac-arm","win"]}}],"responses":{"200":{"description":"Binary file download"}}}},"/api/v1/oauth/authorize/{service}":{"get":{"summary":"OAuth authorize URL","security":[{"bearerAuth":[]}]}},"/api/v1/oauth/callback/{service}":{"get":{"summary":"OAuth callback","responses":{"200":{"description":"OK"}}}},"/api/v1/oauth/status":{"get":{"summary":"OAuth status","security":[{"bearerAuth":[]}]}},"/api/v1/oauth/disconnect/{service}":{"post":{"summary":"Disconnect OAuth service","security":[{"bearerAuth":[]}]}},"/api/v1/billing/plans":{"get":{"summary":"Billing plans"}},"/api/v1/billing/checkout":{"post":{"summary":"Billing checkout"}}}}