{"asyncapi":"3.1.0","info":{"title":"AirPlx device ↔ server (M2a)","version":"0.2","description":"Subprotocol airplx.v1. Binary layouts: TBD."},"servers":{"this":{"host":"device-staging.airplx.com","protocol":"wss","pathname":"/airplx/v1/device","description":"Offer Sec-WebSocket-Protocol: airplx.v1"}},"channels":{"device":{"address":"/airplx/v1/device","messages":{"hello":{"$ref":"#/components/messages/hello"},"welcome":{"$ref":"#/components/messages/welcome"},"upload":{"$ref":"#/components/messages/upload"},"quiet":{"$ref":"#/components/messages/quiet"},"ACK1":{"$ref":"#/components/messages/ACK1"},"TRQ1":{"$ref":"#/components/messages/TRQ1"},"TRS1":{"$ref":"#/components/messages/TRS1"},"status":{"$ref":"#/components/messages/status"},"event":{"$ref":"#/components/messages/event"},"claim":{"$ref":"#/components/messages/claim"},"claim_result":{"$ref":"#/components/messages/claim_result"},"unclaim":{"$ref":"#/components/messages/unclaim"},"test_capture":{"$ref":"#/components/messages/test_capture"},"test_capture_result":{"$ref":"#/components/messages/test_capture_result"},"cmd":{"$ref":"#/components/messages/cmd"},"cmd_result":{"$ref":"#/components/messages/cmd_result"},"error":{"$ref":"#/components/messages/error"}}}},"operations":{"boxSends":{"action":"receive","channel":{"$ref":"#/channels/device"},"summary":"Box to server","messages":[{"$ref":"#/channels/device/messages/hello"},{"$ref":"#/channels/device/messages/upload"},{"$ref":"#/channels/device/messages/quiet"},{"$ref":"#/channels/device/messages/TRQ1"},{"$ref":"#/channels/device/messages/status"},{"$ref":"#/channels/device/messages/event"},{"$ref":"#/channels/device/messages/claim"},{"$ref":"#/channels/device/messages/unclaim"},{"$ref":"#/channels/device/messages/test_capture"},{"$ref":"#/channels/device/messages/cmd_result"}]},"serverSends":{"action":"send","channel":{"$ref":"#/channels/device"},"summary":"Server to box","messages":[{"$ref":"#/channels/device/messages/welcome"},{"$ref":"#/channels/device/messages/ACK1"},{"$ref":"#/channels/device/messages/TRS1"},{"$ref":"#/channels/device/messages/claim_result"},{"$ref":"#/channels/device/messages/test_capture_result"},{"$ref":"#/channels/device/messages/cmd"},{"$ref":"#/channels/device/messages/error"}]}},"components":{"messages":{"hello":{"name":"hello","title":"hello","summary":"First message on every connection.","description":"This server: Replies with welcome. Anything else first, or a device_id outside 1–999999, closes 1002. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"hello"},"device_id":{"type":"integer","description":"1–999999"},"boot_seq":{"description":"Type TBD."},"ack_watermark":{"description":"The box resumes after max(welcome.ack, ack_watermark)."},"journal":{"description":"Type TBD."},"caps":{"description":"What the firmware supports."}},"additionalProperties":true},"examples":[{"payload":{"type":"hello","device_id":123456}}]},"welcome":{"name":"welcome","title":"welcome","summary":"Reply to hello, within 2 s. Nothing is sent before it.","description":"This server: ack and config_rev are 0. pending_commands holds cmd messages queued while the box was offline. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"welcome"},"ack":{"description":"Type TBD."},"config_rev":{"description":"Type TBD."},"pending_commands":{"description":"Type TBD."}},"additionalProperties":true},"examples":[{"payload":{"type":"welcome","ack":0,"config_rev":0,"pending_commands":[]}}]},"upload":{"name":"upload","title":"upload","summary":"One 1 s audio record. Header fields: device_id, boot_seq, chunk_id, flags, monotonic_counter, utc_ms, time anchor, channel_mask, levels, audio_state, AGC, clips, payload_crc32, header_crc32.","description":"This server: Recognised by magic and length, then logged. Not parsed or acknowledged until the header layout is known.","contentType":"application/octet-stream","payload":{"type":"string","format":"binary","description":"32520 B, little-endian.\n    0       4  magic  0x414C5058\n    4       4  frame_len  32,512\n    8     512  header v2  Layout TBD (Appendix A.1).\n  520  32,000  payload  8,000 frames × (L int16, R int16), 8 kHz, 16-bit PCM, uncompressed. R = 0 on the single-channel board."}},"quiet":{"name":"quiet","title":"quiet","summary":"Header only, for a quiet second. Proposed. The Q-042 answer is heartbeats instead.","description":"This server: Recognised and logged like upload.","contentType":"application/octet-stream","payload":{"type":"string","format":"binary","description":"520 B, little-endian.\n    0       4  magic  0x414C5058\n    4       4  frame_len  512\n    8     512  header v2  Layout TBD (Appendix A.1)."}},"ACK1":{"name":"ACK1","title":"ACK1","summary":"Cumulative acknowledgement: every chunk_id up to it is stored.","description":"This server: Not sent yet. Layout TBD.","contentType":"application/octet-stream","payload":{"type":"string","format":"binary","description":"12 B, little-endian.\nLayout TBD."}},"TRQ1":{"name":"TRQ1","title":"TRQ1","summary":"Time request: seq, t1. Up to 8 after every welcome and every hour.","description":"This server: Logged, not answered. Layout TBD.","contentType":"application/octet-stream","payload":{"type":"string","format":"binary","description":"16 B, little-endian.\nLayout TBD."}},"TRS1":{"name":"TRS1","title":"TRS1","summary":"Time response: seq, t1, t2, t3. offset = ((t2 − t1) + (t3 − t4)) / 2.","description":"This server: Not sent yet. Layout TBD.","contentType":"application/octet-stream","payload":{"type":"string","format":"binary","description":"32 B, little-endian.\nLayout TBD."}},"status":{"name":"status","title":"status","summary":"Every 60 s. Groups: state, capture, upload, network, audio, health, storage, system, counters.","description":"This server: Stored as the box's last status. No reply. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"status"},"state":{"description":"Type TBD."},"capture":{"description":"Type TBD."},"upload":{"description":"Type TBD."},"network":{"description":"Type TBD."},"audio":{"description":"Type TBD."},"health":{"description":"Type TBD."},"storage":{"description":"Type TBD."},"system":{"description":"Type TBD."},"counters":{"description":"Type TBD."}},"additionalProperties":true},"examples":[{"payload":{"type":"status"}}]},"event":{"name":"event","title":"event","summary":"Events and alarms. De-duplicated by (device_id, boot_seq, seq).","description":"This server: Stored once per (boot_seq, seq). No reply. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"event"},"boot_seq":{"description":"Type TBD."},"seq":{"description":"Type TBD."}},"additionalProperties":true},"examples":[{"payload":{"type":"event"}}]},"claim":{"name":"claim","title":"claim","summary":"Associates the box with an account and location. The claim token goes backend → app → box → server.","description":"This server: Replies with claim_result, no fields yet. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"claim"}},"additionalProperties":true},"examples":[{"payload":{"type":"claim"}}]},"claim_result":{"name":"claim_result","title":"claim_result","summary":"Result of claim. Refused if the box is associated elsewhere.","description":"This server: Sent with no fields yet. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"claim_result"}},"additionalProperties":true},"examples":[{"payload":{"type":"claim_result"}}]},"unclaim":{"name":"unclaim","title":"unclaim","summary":"The box left its account.","description":"This server: Logged. No reply. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"unclaim"}},"additionalProperties":true},"examples":[{"payload":{"type":"unclaim"}}]},"test_capture":{"name":"test_capture","title":"test_capture","summary":"Onboarding test. Its frames are flagged as a test and uploaded first.","description":"This server: Replies with test_capture_result straight away, no fields yet. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"test_capture"}},"additionalProperties":true},"examples":[{"payload":{"type":"test_capture"}}]},"test_capture_result":{"name":"test_capture_result","title":"test_capture_result","summary":"Sent once the test capture is stored.","description":"This server: Sent with no fields yet. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"test_capture_result"}},"additionalProperties":true},"examples":[{"payload":{"type":"test_capture_result"}}]},"cmd":{"name":"cmd","title":"cmd","summary":"Remote command. Same names, args and codes as BLE (M2b §7). The same request_id again returns the stored result.","description":"This server: Sent from POST /api/v1/devices/{id}/cmd, or in the next welcome if the box is offline.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"cmd"},"request_id":{"type":"string","description":"uuid"},"name":{"type":"string","description":"See Remote commands."},"args":{"type":"object","description":"Per command (M2b §7.2)."},"timeout_ms":{"type":"integer","description":"30000 in the deck's example."}},"additionalProperties":true},"examples":[{"payload":{"type":"cmd","request_id":"<uuid>","name":"find_device","args":{},"timeout_ms":30000}}]},"cmd_result":{"name":"cmd_result","title":"cmd_result","summary":"accepted (≤ 2 s), in_progress (long commands only), then completed or failed with a code.","description":"This server: Stored with the command. No reply.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"cmd_result"},"request_id":{"type":"string","description":"From cmd."},"state":{"type":"string","description":"accepted · in_progress · completed · failed"},"code":{"type":"string","description":"\"OK\" or an error code."},"data":{"type":"object"}},"additionalProperties":true},"examples":[{"payload":{"type":"cmd_result","request_id":"<uuid>","state":"completed","code":"OK","data":{}}}]},"error":{"name":"error","title":"error","summary":"A message that could not be processed. Either side can send one.","description":"This server: Sent with no fields for bad JSON or an unknown type. Other fields TBD.","contentType":"application/json","payload":{"type":"object","required":["type"],"properties":{"type":{"const":"error"}},"additionalProperties":true},"examples":[{"payload":{"type":"error"}}]}}}}