{"openapi":"3.1.0","info":{"title":"Platphorm Sonify API","description":"Robot sonification API. Send robot fleet events to generate real-time lofi beats. Each event_type and goto_outcome maps to a distinct sound.","version":"1.0.0","contact":{"name":"PH3AR","url":"https://platphormnews.com"},"license":{"name":"MIT"}},"servers":[{"url":"https://radio.platphormnews.com","description":"Production"}],"paths":{"/api/events":{"post":{"summary":"Send robot events","description":"Post a single event or array of events. Each event triggers a unique sound based on event_type and goto_outcome.","operationId":"postEvents","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RobotEvent"},{"type":"array","items":{"$ref":"#/components/schemas/RobotEvent"}}]}}}},"responses":{"200":{"description":"Events accepted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"count":{"type":"integer"},"total":{"type":"integer"},"latestSeq":{"type":"integer"}}}}}},"400":{"description":"Invalid request body"}}},"get":{"summary":"Retrieve events","description":"Get stored events. Use after_seq for cursor-based polling (only new events), or all=1 for full feed.","operationId":"getEvents","parameters":[{"name":"after_seq","in":"query","schema":{"type":"integer"},"description":"Return only events with sequence number > this value"},{"name":"all","in":"query","schema":{"type":"string","enum":["1"]},"description":"Return all stored events"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100},"description":"Max events to return"}],"responses":{"200":{"description":"Events list","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/RobotEvent"}},"latestSeq":{"type":"integer"},"total":{"type":"integer"}}}}}}}},"delete":{"summary":"Clear all events","operationId":"deleteEvents","responses":{"200":{"description":"Events cleared"}}}},"/api/health":{"get":{"summary":"Health check","operationId":"getHealth","responses":{"200":{"description":"Service health status"}}}}},"components":{"schemas":{"RobotEvent":{"type":"object","required":["robot_id","event_type"],"properties":{"robot_id":{"type":"string","description":"Robot identifier, e.g. xap035","example":"xap035"},"event_type":{"type":"string","description":"Event classification. Sound mapping: LOGIN=coins cascade, TASK_START=coin drop, TASK_END=warm bell, LOGOUT=descending tone, E_STOP=noise burst, TASK_CANCELLED=warning tone","enum":["TASK_START","TASK_END","LOGIN","LOGOUT","E_STOP","TASK_CANCELLED","EMERGENCY","ERROR","FAULT"],"example":"TASK_START"},"goto_outcome":{"type":"string","description":"Task outcome. Bad outcomes (INACTIVE, ABORTED, ABORTED_VIA_TOUCHSCREEN, CANCELLED, FAILED) trigger warning sounds.","example":"COMPLETED"},"time":{"type":"string","description":"Timestamp","example":"2026-01-19 18:48:30"},"task_id":{"type":"string","format":"uuid","description":"Unique task ID"},"destination":{"type":"string","description":"Task destination","example":"Charge 7"},"badge_code":{"type":"string","description":"Badge/location code"},"duration_sec":{"type":"number","description":"Task duration in seconds"}}}}}}