{"openapi":"3.1.0","info":{"title":"Beacon API","version":"0.1.0"},"components":{"schemas":{},"parameters":{}},"paths":{"/api/healthz":{"get":{"tags":["health"],"responses":{"200":{"description":"Worker health","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}},"required":["data"]}}}}}}},"/api/org-login":{"post":{"tags":["orgs"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"portal_token":{"type":"string"}},"required":["portal_token"]}}}},"responses":{"200":{"description":"Login result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"org_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string"},"role":{"type":"string"},"email":{"type":"string"}},"required":["org_id","name","slug","status","role","email"]}},"required":["data"]}}}}}}},"/api/admin/org-requests":{"post":{"tags":["admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"org_name":{"type":"string"},"slug":{"type":"string"},"contact_email":{"type":"string"}},"required":["org_name"]}}}},"responses":{"201":{"description":"Created organization request","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_name":{"type":"string"},"slug":{"type":"string"},"contact_email":{"type":"string"},"status":{"type":"string"},"org_id":{"type":"string","nullable":true},"portal_token":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_name","slug","contact_email","status"]}},"required":["data"]}}}}}},"get":{"tags":["admin"],"responses":{"200":{"description":"Organization requests","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"org_name":{"type":"string"},"slug":{"type":"string"},"contact_email":{"type":"string"},"status":{"type":"string"},"org_id":{"type":"string","nullable":true},"portal_token":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_name","slug","contact_email","status"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}}},"/api/admin/org-requests/{id}/approve":{"post":{"tags":["admin"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Approved request","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_name":{"type":"string"},"slug":{"type":"string"},"contact_email":{"type":"string"},"status":{"type":"string"},"org_id":{"type":"string","nullable":true},"portal_token":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_name","slug","contact_email","status"]}},"required":["data"]}}}}}}},"/api/admin/org-requests/{id}/reject":{"post":{"tags":["admin"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Rejected request","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}},"required":["id","status"]}},"required":["data"]}}}}}}},"/api/admin/orgs":{"get":{"tags":["admin"],"responses":{"200":{"description":"Organizations","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string"},"portal_token":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","slug","status"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string"}},"required":["name"]}}}},"responses":{"201":{"description":"Created organization","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string"},"portal_token":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","slug","status"]}},"required":["data"]}}}}}}},"/api/admin/orgs/{id}/token":{"post":{"tags":["admin"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Rotated portal token","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"portal_token":{"type":"string"}},"required":["id","portal_token"]}},"required":["data"]}}}}}}},"/api/artifacts/{id}/download":{"get":{"tags":["artifacts"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Artifact object","content":{"application/octet-stream":{"schema":{"nullable":true}}}}}}},"/api/audit":{"get":{"tags":["audit"],"responses":{"200":{"description":"Audit events","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"title":{"type":"string"},"detail":{"type":"string"},"subject_id":{"type":"string"},"status":{"type":"string","nullable":true},"actor":{"type":"string"},"created_at":{"type":"string"}},"required":["kind","title","detail","subject_id","status","actor","created_at"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}}},"/api/sites":{"get":{"tags":["sites"],"responses":{"200":{"description":"Sites","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","name","created_at"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["sites"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}}}},"responses":{"201":{"description":"Created site","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","name","created_at"]}},"required":["data"]}}}}}}},"/api/sites/{id}":{"get":{"tags":["sites"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Site","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","name","created_at"]}},"required":["data"]}}}}}},"delete":{"tags":["sites"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted site","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"required":["data"]}}}}}}},"/api/fleets/{id}":{"get":{"tags":["fleets"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Fleet","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"site_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","site_id","name","created_at"]}},"required":["data"]}}}}}},"delete":{"tags":["fleets"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted fleet","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"required":["data"]}}}}}}},"/api/fleets":{"get":{"tags":["fleets"],"responses":{"200":{"description":"Fleets","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"site_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","site_id","name","created_at"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["fleets"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"site_id":{"type":"string"},"name":{"type":"string"}},"required":["site_id","name"]}}}},"responses":{"201":{"description":"Created fleet","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"site_id":{"type":"string"},"name":{"type":"string"},"created_at":{"type":"string"}},"required":["id","org_id","site_id","name","created_at"]}},"required":["data"]}}}}}}},"/api/robots":{"get":{"tags":["robots"],"responses":{"200":{"description":"Robots","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"agent_version":{"type":"string","nullable":true},"last_seen_at":{"type":"string","nullable":true},"site_id":{"type":"string","nullable":true},"fleet_id":{"type":"string","nullable":true},"online":{"type":"boolean"}},"required":["id","name"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}}},"/api/robots/{id}":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Robot","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"agent_version":{"type":"string","nullable":true},"last_seen_at":{"type":"string","nullable":true},"site_id":{"type":"string","nullable":true},"fleet_id":{"type":"string","nullable":true},"online":{"type":"boolean"},"session_started_at":{"type":"string","nullable":true},"created_at":{"type":"string","nullable":true}},"required":["id","name"]}},"required":["data"]}}}}}},"delete":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted robot","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"required":["data"]}}}}}}},"/api/robots/{id}/tunnel-status":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Robot tunnel status","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/api/robots/{id}/health":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Robot health","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"nullable":true}}}}}}}}},"/api/robots/{id}/timeline":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Robot timeline","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"events":{"type":"array","items":{"nullable":true}}},"required":["events"]}},"required":["data"]}}}}}}},"/api/robots/{id}/logs":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Robot logs","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"logs":{"type":"array","items":{"nullable":true}},"density":{"type":"array","items":{"type":"object","properties":{"bucket":{"type":"string"},"count":{"type":"number"}},"required":["bucket","count"]}}},"required":["logs","density"]}},"required":["data"]}}}}}}},"/api/fleets/{id}/logs":{"get":{"tags":["fleets"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Fleet logs","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"logs":{"type":"array","items":{"nullable":true}},"density":{"type":"array","items":{"type":"object","properties":{"bucket":{"type":"string"},"count":{"type":"number"}},"required":["bucket","count"]}}},"required":["logs","density"]}},"required":["data"]}}}}}}},"/api/robots/{id}/rosbags":{"get":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Rosbag coverage","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"nullable":true}}}}}}}}},"/api/robots/{id}/rosbags/export":{"post":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"501":{"description":"Rosbag export not enabled","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/robots/{id}/ros/{command}":{"post":{"tags":["robots"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":true,"name":"command","in":"path"}],"responses":{"200":{"description":"ROS command result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"nullable":true}}}}}}}}},"/api/releases":{"get":{"tags":["releases"],"responses":{"200":{"description":"Releases","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"artifact_id":{"type":"string"},"semver":{"type":"string"},"notes":{"type":"string"},"manifest_json":{"type":"string"},"created_at":{"type":"string"}},"required":["id","semver"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["releases"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"semver":{"type":"string"},"notes":{"type":"string"},"artifact_kind":{"type":"string"},"artifact_sha256":{"type":"string"},"artifact_size":{"type":"number"},"storage_url":{"type":"string"},"manifest_json":{"type":"string"}},"required":["semver"]}}}},"responses":{"201":{"description":"Created release","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"artifact_id":{"type":"string"},"semver":{"type":"string"},"notes":{"type":"string"},"manifest_json":{"type":"string"},"created_at":{"type":"string"}},"required":["id","semver"]}},"required":["data"]}}}}}}},"/api/configs":{"get":{"tags":["configs"],"responses":{"200":{"description":"Configs","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"version":{"type":"number"},"checksum":{"type":"string"},"payload_json":{"type":"string"},"payload":{"type":"object","additionalProperties":{"nullable":true}},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","namespace"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["configs"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"payload":{"type":"object","additionalProperties":{"nullable":true}},"raw_payload":{"type":"string"},"format":{"type":"string"},"created_by":{"type":"string"}},"required":["name","namespace"]}}}},"responses":{"201":{"description":"Created config","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"version":{"type":"number"},"checksum":{"type":"string"},"payload_json":{"type":"string"},"payload":{"type":"object","additionalProperties":{"nullable":true}},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","namespace"]}},"required":["data"]}}}}}}},"/api/configs/deployments":{"get":{"tags":["configs"],"responses":{"200":{"description":"Config deployments","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"release_id":{"type":"string"},"config_blob_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","status"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["configs"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"config_blob_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"created_by":{"type":"string"}},"required":["config_blob_id","target_id"]}}}},"responses":{"201":{"description":"Created config deployment","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"release_id":{"type":"string"},"config_blob_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","status"]}},"required":["data"]}}}}}}},"/api/configs/deployments/{deploymentId}/events":{"get":{"tags":["configs"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"deploymentId","in":"path"}],"responses":{"200":{"description":"Config deployment events","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"nullable":true}},"cursor":{"type":"string"}},"required":["items"]}}}}}}},"/api/deployments":{"get":{"tags":["deployments"],"responses":{"200":{"description":"Deployments","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"release_id":{"type":"string"},"config_blob_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","status"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["deployments"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"release_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"scheduled_at":{"type":"string","nullable":true}},"required":["release_id","target_id"]}}}},"responses":{"201":{"description":"Created deployment","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"release_id":{"type":"string"},"config_blob_id":{"type":"string"},"target_kind":{"type":"string"},"target_id":{"type":"string"},"status":{"type":"string"},"scheduled_at":{"type":"string","nullable":true},"created_by":{"type":"string"},"created_at":{"type":"string"}},"required":["id","status"]}},"required":["data"]}}}}}}},"/api/deployments/{deploymentId}/events":{"get":{"tags":["deployments"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"deploymentId","in":"path"}],"responses":{"200":{"description":"Deployment events","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"nullable":true}},"cursor":{"type":"string"}},"required":["items"]}}}}}}},"/api/enrollment-keys":{"get":{"tags":["enrollment-keys"],"responses":{"200":{"description":"Enrollment keys","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"key_value":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"site_id":{"type":"string"},"fleet_id":{"type":"string"},"max_uses":{"type":"number"},"uses":{"type":"number"},"expires_at":{"type":"string","nullable":true},"revoked_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","name","site_id","fleet_id","max_uses","expires_at"]}},"cursor":{"type":"string"}},"required":["items"]}}}}}},"post":{"tags":["enrollment-keys"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"site_id":{"type":"string"},"fleet_id":{"type":"string"},"max_uses":{"type":"number"},"expires_in_hours":{"type":"number","nullable":true}},"required":["site_id","fleet_id"]}}}},"responses":{"201":{"description":"Created enrollment key","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"key_value":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"site_id":{"type":"string"},"fleet_id":{"type":"string"},"max_uses":{"type":"number"},"uses":{"type":"number"},"expires_at":{"type":"string","nullable":true},"revoked_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","name","site_id","fleet_id","max_uses","expires_at"]}},"required":["data"]}}}}}}},"/api/enrollment-keys/{id}/revoke":{"post":{"tags":["enrollment-keys"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Revoked enrollment key","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"key_value":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"site_id":{"type":"string"},"fleet_id":{"type":"string"},"max_uses":{"type":"number"},"uses":{"type":"number"},"expires_at":{"type":"string","nullable":true},"revoked_at":{"type":"string","nullable":true},"created_at":{"type":"string"}},"required":["id","name","site_id","fleet_id","max_uses","expires_at"]}},"required":["data"]}}}}}}},"/api/org-users":{"get":{"tags":["org-users"],"responses":{"200":{"description":"Organization users","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"nullable":true}},"invitations":{"type":"array","items":{"nullable":true}}},"required":["members","invitations"]}}}}}},"post":{"tags":["org-users"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string","enum":["viewer","developer","admin"]}},"required":["email","role"]}}}},"responses":{"201":{"description":"Created organization invitation","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/api/org-users/{id}/revoke":{"post":{"tags":["org-users"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Revoked legacy token user","content":{"application/json":{"schema":{"nullable":true}}}}}}}}}