{"openapi":"3.1.0","info":{"title":"airstack-edge-web","description":"The AIR-T Edge service provides secure, low-level access to radio hardware\nand system configuration, enabling control, monitoring, and signal processing. It allows\nclients to configure and manage radio streams, record and process IQ data, transmit signals,\nregister system endpoints, and perform predictive analyses using AI models.\nThe service exposes APIs for setup, hardware access, reception, transmission,\nand prediction, making it suitable for advanced RF applications, research, and testing.\nFor further information go to: https://deepwave.ai/software-products/airstack-edge/","contact":{"name":"Deepwave Digital, Inc.","email":"info@deepwavedigital.com"},"license":{"name":""},"version":"1.0.0"},"paths":{"/airstack-edge/v1/apps/cancel":{"post":{"tags":["Apps"],"summary":"Cancel streaming inference","description":"Sets the inference cancel flag so that any currently running streaming inference task stops reading samples and sending them to the model.\nThe cancellation is cooperative: the running stream will detect the flag and exit its loop, cleaning up resources.\n\n**Note**: This does not stop the existing input_buffers from completing processing which may cause your webhook to continue receiving data for some time.","operationId":"cancel_infer_stream","responses":{"200":{"description":"Streaming inference cancelled successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/disable":{"post":{"tags":["Config"],"summary":"Unload an inference model","description":"Requests the inference server to unload a specific model version from memory.\n* `model_name`: Name of the model to unload\n\nThis model will not be available for subsequent `apps/run` calls.","operationId":"unload_triton","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelLoadReq"}}},"required":true},"responses":{"200":{"description":"Model unloaded successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/enable":{"post":{"tags":["Config"],"summary":"Load inference model","description":"Requests the inference server to load or reload a specific model into memory so that it is ready to handle prediction requests.\n* `model_name`: Name of the model to load\n* `parameters`: Optional Triton repository load parameters\n\nThis ensures that the model is available for subsequent `apps/run` calls.","operationId":"load_triton","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelLoadReq"}}},"required":true},"responses":{"200":{"description":"Model loaded successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/info":{"post":{"tags":["Config"],"summary":"Fetch model metadata","description":"Retrieves detailed configuration and metadata for a specific model from the inference server.\nThis includes information such as:\n* Model name and version\n* Input/output tensor shapes and types\n* Deployment status\n* Any additional configuration parameters required by the model\n\nThis endpoint is useful for inspecting models before running predictions, ensuring correct configuration, and debugging.","operationId":"get_model_info","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelReq"}}},"required":true},"responses":{"200":{"description":"Model metadata returned","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/list":{"get":{"tags":["Config"],"summary":"List inference models","description":"Retrieves the models currently exposed by the configured inference server.\nEach model includes:\n* `name`: The model name\n* `version`: The model version\n* `state`: The model deployment state (e.g., READY, LOADING, UNAVAILABLE)\n\nThis endpoint is useful for discovering available models before making prediction requests.","operationId":"list_triton","responses":{"200":{"description":"List of models returned as a JSON string.","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/stats":{"post":{"tags":["Config"],"summary":"Fetch model statistics","description":"Returns runtime statistics for a specific model, including counters and performance metrics such as:\n* Number of inferences performed\n* Average inference time\n* Success and failure counts\n* Any other relevant runtime metrics exposed by the inference server\n\nThis endpoint helps monitor model performance and utilization.","operationId":"get_model_stats","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelReq"}}},"required":true},"responses":{"200":{"description":"Model runtime statistics returned","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/config/upload":{"post":{"tags":["Config"],"summary":"Upload Triton model","description":"Accepts a compressed Triton model repository archive and extracts it into the configured model directory.\nSupported compression formats:\n- `.tar`\n- `.tar.gz` / `.tgz`\n- `.tar.bz2` / `.tbz` / `.tbz2`\n- `.tar.zst` / `.tzst`\n\n**Note**:\n* Only one model archive per request is supported.\n* Overwriting existing models is not currently supported.\n* Use `load_model` endpoint after upload to load the model into memory.","operationId":"upload","requestBody":{"content":{"application/json":{"schema":{"default":null}}},"required":true},"responses":{"200":{"description":"File uploaded and extracted successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/inject":{"post":{"tags":["Apps"],"summary":"Inject samples and predict","description":"Injects user-provided IQ samples through an internal loopback capture, forwards the captured data to the inference server, and returns the model predictions.\nThis endpoint is useful for testing models with custom input data or for debugging data flows.\n\nSupported features:\n* Specify buffer contents (`I16` or `F32`) and channel indices\n* Adjust stream parameters for frequency, sample rate, gain, and AGC usage\n* Returns predictions in raw bytes for further processing\n\nRequest body is a two-element JSON array: `[inject_read_req, model_req]`. \n\n**Note**: Only `F32` buffers are currently supported.","operationId":"inject_predict","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InjectPredictReq"}}},"required":true},"responses":{"200":{"description":"Prediction result returned as raw bytes.","content":{"application/octet-stream":{"schema":{"type":"array","items":{"type":"integer","format":"int32","minimum":0}}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/playback":{"post":{"tags":["Apps"],"summary":"Run prediction using binary input buffers","description":"This endpoint accepts raw binary IQ data (`application/octet-stream`) in the request body \n        and additional parameters via HTTP headers, then submits the data directly to the inference server.\n**Notes**:\n- This endpoint does **not** interact with the RF frontend (unlike `/run`).\n- The raw data input should be binary data representing float 32 values. The buffer length must be a multiple of 4 bytes for correct alignment.\n- The x-metadata header is optional but if used must be a string representing `SigMF` metadata\n- The required `x-data-return` header controls whether the response is returned as bytes, JSON, or an empty 200 response.","operationId":"playback_infer","parameters":[{"name":"x-model-name","in":"header","description":"Name of the model to run","required":true,"schema":{"type":"string"},"example":"avg_power_net"},{"name":"x-model-version","in":"header","description":"Model version","required":true,"schema":{"type":"string"},"example":"1"},{"name":"x-data-return","in":"header","description":"Result return type (`Byte`, `Json`, `Discard`)","required":true,"schema":{"type":"string"},"example":"Byte"},{"name":"x-metadata","in":"header","description":"Optional metadata sent as UTF-8 string","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"default":null}}},"required":true},"responses":{"200":{"description":"Prediction accepted but response body discarded when `x-data-return` is `discard`.","content":{"text/plain":{"schema":{"default":null}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/restart_server":{"post":{"tags":["Apps"],"summary":"Restart Inference Server","description":"Attemps to stop and then restart the running inference server.\nAny currently enabled models will need to be re enabled after restart.","operationId":"restart_triton","responses":{"200":{"description":"Inference Server Restarted Succesfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/run":{"post":{"tags":["Apps"],"summary":"Run prediction (single or stream)","description":"Combines the single-batch and streaming inference endpoints. The `stream_mode` field selects behavior:\n* `single`: Runs one prediction and returns results based on `SingleInferReq`\n* `continuous`: Starts continuous streaming inference and posts outputs to registered webhooks (webhooks required)\n\n**Note**: For single stream mode, setting return_input to True is only supported with `Byte` return type. If this is selected \n            the byte response is encoded as: [u64 output_len][output_bytes][input_bytes]","operationId":"run_predict","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictReq"}}},"required":true},"responses":{"200":{"description":"Streaming inference started when `stream_mode` is `continuous`; results are posted to configured webhooks.","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/apps/status":{"get":{"tags":["Apps"],"summary":"Inspect app task status","description":"Returns app/inference task status history, stream state, RX channel frequency, sample rate, gain, AGC, device timing settings, and the current streaming model when one is active. Stream locks are checked without waiting, so a running app task is reported as `in_use` without being interrupted.","operationId":"probe_infer","responses":{"200":{"description":"App task status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RadioTaskState"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/gps":{"get":{"tags":["Device"],"summary":"Get GPS status","description":"Returns the current GPS status (mode, lat, long, altitude) reported by the radio, or null if GPS data is unavailable.","operationId":"get_gps_status","responses":{"200":{"description":"GPS status retrieved successfully.","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GpsState"}]}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/info":{"get":{"tags":["Device"],"summary":"Read radio hardware info","description":"Returns hardware capabilities, driver information, available RX/TX channels, supported sample rates, gains, frequencies, and related configuration for the currently opened device as a JSON string. \n*Note*: Sample rates listed are available for the default master clock rate","operationId":"info","responses":{"200":{"description":"Radio hardware information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RadioInfo"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/read_settings":{"post":{"tags":["Device"],"summary":"Read device level settings","description":"Reads device-level or channel-specific SoapySDR settings. Omit `direction` and `channel` for device settings; provide both for channel settings.","operationId":"read_settings","requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeviceSettingKey"}}}},"required":true},"responses":{"200":{"description":"Device settings read successfully.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeviceSetting"}}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/release":{"post":{"tags":["Device"],"summary":"Release radio device","description":"Releases exclusive access to the SDR device, closes any active streams, and clears the device lock. After this call, other clients may take control of the hardware using the `/setup` endpoint.","operationId":"release","responses":{"200":{"description":"Released control of the radio frontend.","content":{"text/plain":{"schema":{"type":"string"},"example":"Device released successfully"}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/setup":{"post":{"tags":["Device"],"summary":"Lock radio device","description":"Opens the AIR-T SDR device and marks it as in-use. While locked, no other session can access or modify the hardware. This endpoint must be called before configuring receive, transmit, or inference streams. \n*Note*: Non authentication failures indicate another program is using the device outside of Edge","operationId":"take","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeviceOpts"}]}}}},"responses":{"200":{"description":"Device opened successfully.","content":{"text/plain":{"schema":{"type":"string"},"example":"Device opened successfully"}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/time":{"get":{"tags":["Device"],"summary":"Read hardware timestamp","description":"Returns the hardware clock timestamp in nanoseconds. This hardware time is used for timed transmit and receive scheduling and will reset to 0 if the device is restarted.","operationId":"get_hardware_time","responses":{"200":{"description":"Hardware time returned successfully.","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/device/write_settings":{"post":{"tags":["Device"],"summary":"Configure device level settings","description":"Writes device-level or channel-specific SoapySDR settings. Omit `direction` and `channel` for device settings; provide both for channel settings.","operationId":"write_settings","requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeviceSetting"}}}},"required":true},"responses":{"200":{"description":"Device configured successfully.","content":{"text/plain":{"schema":{"type":"string"},"example":"Device configured successfully"}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/cancel":{"post":{"tags":["Receive"],"summary":"Cancel active receive tasks","description":"Sets the internal cancel flag, signaling any scheduled receive task to immediately stop streaming samples. This operation is safe to call even if no receive task is currently running.","operationId":"cancel_rx","responses":{"200":{"description":"Receive task cancelled successfully.","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/close":{"post":{"tags":["Receive"],"summary":"Close receive stream","description":"Closes the currently active RX stream.\nThis frees the device so that new receive sessions can be opened.\n* Ensures any ongoing recordings or injections are stopped.\n* Clears internal stream state to prevent conflicts for future RX operations.","operationId":"close_rx","responses":{"200":{"description":"Stream closed successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/inject":{"post":{"tags":["Receive"],"summary":"Inject and read loopback samples","description":"Performs an internal loopback on the RX stream for debugging purposes.\nThe process:\n* Enables internal loopback on the device\n* Injects the provided IQ samples into the stream\n* Captures the resulting received samples\n* Returns raw binary data\n\nUseful for verifying data integrity, checking stream configuration, and debugging RX processing.","operationId":"inject_read","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InjectReadReq"}}},"required":true},"responses":{"200":{"description":"Returned samples from loopback operation","content":{"application/octet-stream":{"schema":{"type":"array","items":{"type":"integer","format":"int32","minimum":0}}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/open":{"post":{"tags":["Receive"],"summary":"Open receive stream","description":"Initializes an RX stream with the provided parameters so subsequent record calls can read samples.","operationId":"open","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RxStreamConfig"}}},"required":true},"responses":{"200":{"description":"Stream opened successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/start":{"post":{"tags":["Receive"],"summary":"Record IQ samples","description":"Reads samples from an open RX stream based on the provided parameters.\n* `stream_mode.single`: Captures one buffer and returns data based on the embedded `return_type` (`byte`, `json`, or `discard`).When data is returned, capture metadata is included in the `X-Metadata` header. If applicable results will also be posted to provided webhooks. \n* `stream_mode.periodic`: Schedules repeated captures posted to the requested webhooks and returns an acknowledgement message (timer mode requires at least one webhook).\n\n*Note*: An open RX Stream is required, use `/receive/open`.","operationId":"record","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordReq"}}},"required":true},"responses":{"200":{"description":"Loop recording scheduled for timer mode; results will be posted to the configured webhooks.","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/receive/status":{"get":{"tags":["Receive"],"summary":"Inspect receive task status","description":"Returns receive task status history, stream state, RX channel frequency, sample rate, gain, AGC, and device timing settings. Stream locks are checked without waiting, so a running receive task is reported as `in_use` without being interrupted.","operationId":"status_rx","responses":{"200":{"description":"Receive task status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RadioTaskState"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/transmit/cancel":{"post":{"tags":["Transmit"],"summary":"Cancel scheduled transmits","description":"Sets the transmit cancel flag so any queued transmissions are aborted before they run.","operationId":"cancel_tx","responses":{"200":{"description":"Device details","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/transmit/close":{"post":{"tags":["Transmit"],"summary":"Close transmit stream","description":"Releases the active TX stream so a new transmission session can be configured later.","operationId":"close_tx","responses":{"200":{"description":"Stream closed successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/transmit/open":{"post":{"tags":["Transmit"],"summary":"Open transmit stream","description":"Initializes a TX (transmit) stream on the AIR-T with the provided configuration.\nThis endpoint verifies that a stream is not already open and prepares the device so that IQ buffers can be transmitted.\n* Applies overall radio settings like clock sources\n* Configures data type and optional stream overrides\n* Prepares hardware for sending IQ samples","operationId":"open_tx","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TxStreamConfig"}}},"required":true},"responses":{"200":{"description":"TX stream opened successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/transmit/start":{"post":{"tags":["Transmit"],"summary":"Schedule transmit buffers","description":"Queues the provided IQ samples for transmission using the active TX stream.\n* `buffer`: IQ samples to transmit (I16 or F32)\n* `time_ns`: Optional hardware timestamp to schedule the transmission\n* `stream_opts`: Optional stream settings to override the current TX configuration\n* `repeat_rate`: Optional interval for repeated transmissions\n\nThe server will handle scheduling and ensure the TX stream is active before sending samples.","operationId":"send_samples","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransmitRequest"}}},"required":true},"responses":{"200":{"description":"Transmit scheduled successfully","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/transmit/status":{"get":{"tags":["Transmit"],"summary":"Inspect transmit status","description":"Returns detailed information about the current TX stream, including:\n* `Number Successful TX`: Number of successfully transmitted IQ buffers\n* `Number Late TX`: Number of transmissions that occurred later than scheduled\n* `Last TX Result`: Status or message of the last transmission\n* `TX Stream`: Whether the stream is `open`, `closed`, or `in_use`\n\nUseful for monitoring the health and performance of the TX stream, as well as debugging transmission timing issues.","operationId":"probe_tx","responses":{"200":{"description":"Transmit stream details returned.","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/webhooks/delete":{"post":{"tags":["Webhooks"],"summary":"Delete a registered postback client","description":"Removes a previously registered postback client using its unique ID.","operationId":"delete_client","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostClientData"}}},"required":true},"responses":{"200":{"description":"Client successfully deleted"},"404":{"description":"Client not found"}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/webhooks/list":{"get":{"tags":["Webhooks"],"summary":"List registered postback clients","description":"Returns a JSON array of all registered postback clients and their configuration.","operationId":"list_clients","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RegisteredClient"}}}}}},"security":[{"bearer_auth":[]}]}},"/airstack-edge/v1/webhooks/register":{"post":{"tags":["Webhooks"],"summary":"Register postback client","description":"Registers a client callback endpoint so long-running jobs can send their results asynchronously. The server validates optional initialization parameters and stores the client's postback URL and authentication information.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterClientRequest"}}},"required":true},"responses":{"200":{"description":"Client successfully registered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostClientData"}}}}},"security":[{"bearer_auth":[]}]}}},"components":{"schemas":{"AppTaskInfo":{"type":"object","description":"Currently running app task, when an app stream owns the radio.","required":["model_name","model_version","mode"],"properties":{"mode":{"type":"string"},"model_name":{"type":"string"},"model_version":{"type":"string"}}},"ChannelInfo":{"type":"object","required":["direction","channel","freq_ranges","sample_rates","antennas"],"properties":{"antennas":{"type":"array","items":{"type":"string"}},"channel":{"type":"integer","minimum":0},"direction":{"type":"string"},"freq_ranges":{"type":"array","items":{"$ref":"#/components/schemas/NumericRange"}},"sample_rates":{"type":"array","items":{"$ref":"#/components/schemas/NumericRange"}}}},"ClientInfo":{"type":"object","required":["name","post_call","post_type"],"properties":{"auth":{"type":["string","null"]},"name":{"type":"string"},"post_call":{"type":"string"},"post_type":{"$ref":"#/components/schemas/ReturnType"}}},"DataType":{"type":"string","enum":["c_i16","c_f32"]},"DeviceOpts":{"type":"object","description":"Consistent parameters for opening a device.\n* `device_args`: Optional SoapySDR device args used to open the device (default: driver=SoapyAIRT)\n* `time_opts`: Optional time related parameters (time_source, clock_source, master_clock_rate)","properties":{"device_args":{"type":["string","null"],"example":"driver=SoapyAIRT"},"time_opts":{"$ref":"#/components/schemas/TimeOpts"}},"additionalProperties":false,"example":{"device_args":"driver=SoapyAIRT","time_opts":{"clock_source":"internal","master_clock_rate":125000000,"time_source":"internal"}}},"DeviceSetting":{"type":"object","description":"A SoapySDR setting key and value. Omit `direction` and `channel` for device-level settings; provide both for channel-specific settings. Use this endpoint for channel settings such as RX `rx_path` and TX `tx_amp_bypass`.","required":["key","value"],"properties":{"channel":{"type":["integer","null"],"example":0,"minimum":0},"direction":{"type":"string","example":"rx"},"key":{"type":"string","example":"rx_path"},"value":{"type":"string","example":"preselect"}},"example":{"channel":0,"direction":"rx","key":"rx_path","value":"preselect"}},"DeviceSettingKey":{"type":"object","description":"A SoapySDR setting key. Omit `direction` and `channel` for device-level settings; provide both for channel-specific settings, including RX `rx_path` and TX `tx_amp_bypass`.","required":["key"],"properties":{"channel":{"type":["integer","null"],"example":0,"minimum":0},"direction":{"type":"string","example":"rx"},"key":{"type":"string","example":"rx_path"}},"example":{"channel":0,"direction":"rx","key":"rx_path"}},"GpsState":{"type":"object","required":["mode","latitude","longitude","altitude"],"properties":{"altitude":{"type":"number","format":"float"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"mode":{"type":"string"}}},"IQBuffer":{"oneOf":[{"type":"object","required":["F32"],"properties":{"F32":{"type":"array","items":{"type":"number","format":"float"}}}},{"type":"object","required":["I16"],"properties":{"I16":{"type":"array","items":{"type":"integer","format":"int32"}}}}],"description":"IQ data buffer for RX or loopback operations.\n* `F32`: Vector of f32 samples (complex float)\n* `I16`: Vector of i16 samples (complex integer)","example":{"I16":[0,1,-1,32767,-32768]}},"InferStreamMode":{"oneOf":[{"type":"object","required":["single"],"properties":{"single":{"$ref":"#/components/schemas/SingleInferReq"}}},{"type":"string","enum":["continuous"]}],"description":"Streaming mode for inference requests. Options:\n* `single`: Capture a single buffer and return according to `SingleInferReq`\n* `continuous`: Continuously capture and post to registered webhooks","example":{"single":{"return_input":false,"return_type":"json","start_time":null}}},"InjectPredictReq":{"type":"object","description":"Request body is a JSON array with two elements: the `InjectReadReq` followed by the `ModelReq`.","required":["inject","model"],"properties":{"inject":{"$ref":"#/components/schemas/InjectReadReq"},"model":{"$ref":"#/components/schemas/ModelReq"}}},"InjectReadReq":{"type":"object","description":"Parameters for injecting data into the RX stream and reading it back.\n* `buffer`: IQ samples to inject\n* `channel`: Channels to write and read from\n* `stream_opts`: Stream parameters to use for this injection","required":["buffer","channel","stream_opts"],"properties":{"buffer":{"$ref":"#/components/schemas/IQBuffer"},"channel":{"type":"array","items":{"type":"integer","minimum":0},"example":"[0]"},"stream_opts":{"$ref":"#/components/schemas/StreamOpts"}},"example":{"buffer":{"I16":[1,1,1,1]},"channel":[0],"stream_opts":{"frequency":2400000000,"sample_rate":31250000,"use_agc":true}}},"ModelLoadReq":{"type":"object","description":"Specifies the model to load.\n* `model_name`: Name of the model\n* `parameters`: Optional Triton repository load parameters","required":["model_name"],"properties":{"model_name":{"type":"string"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}},"example":{"model_name":"avg_power_net","parameters":{"key":"value"}}},"ModelReq":{"type":"object","description":"Specifies the model to use for inference or configuration.\n* `model_name`: Name of the model\n* `model_version`: Version number of the model (string)","required":["model_name","model_version"],"properties":{"model_name":{"type":"string"},"model_version":{"type":"string"}},"example":{"model_name":"avg_power_net","model_version":"0"}},"NumericRange":{"type":"object","required":["minimum","maximum"],"properties":{"maximum":{"type":"number","format":"double"},"minimum":{"type":"number","format":"double"}}},"PostClientData":{"type":"object","description":"Details required to post results to a client endpoint.","required":["client_id"],"properties":{"client_id":{"type":"string","description":"UUID returned from the setup API representing the client"}},"example":{"client_id":"uuid-of-registered-client"}},"PredictReq":{"type":"object","description":"Parameters for running inference with a model.\n* `model_name`: Name of the model\n* `model_version`: Version of the model as string\n* `batch_size`: Number of batches (1 if batching is disabled) \n* `num_samples`: Number of samples to process per batch\n* `stream_mode`: Choose `single` or `continuous` inference. If single more input is required see `SingleInferReq`\n* `stream_opts`: Optional override stream parameters\n* `webhooks`: Optional list of webhooks to receive posted results","required":["model_name","model_version","batch_size","num_samples","stream_mode"],"properties":{"batch_size":{"type":"integer","minimum":0},"model_name":{"type":"string"},"model_version":{"type":"string"},"num_samples":{"type":"integer","minimum":0},"stream_mode":{"$ref":"#/components/schemas/InferStreamMode"},"stream_opts":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StreamOpts"}]},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/PostClientData"},"example":"[]"}},"example":{"batch_size":1,"model_name":"avg_power_net","model_version":"0","num_samples":256,"stream_mode":{"single":{"return_input":false,"return_type":"byte","start_time":null}}}},"RadioChannelState":{"type":"object","description":"Current read-only settings for one radio channel.","required":["direction","channel"],"properties":{"channel":{"type":"integer","minimum":0},"direction":{"type":"string"},"frequency":{"type":["number","null"],"format":"double"},"gain":{"type":["number","null"],"format":"double"},"sample_rate":{"type":["number","null"],"format":"double"},"use_agc":{"type":["boolean","null"]}}},"RadioDeviceState":{"type":"object","description":"Current device-level radio settings.","required":["args"],"properties":{"args":{"type":"string"},"clock_source":{"type":["string","null"]},"hardware_time":{"type":["integer","null"],"format":"int64"},"master_clock_rate":{"type":["number","null"],"format":"double"},"time_source":{"type":["string","null"]}}},"RadioInfo":{"type":"object","required":["args","rx_channels","tx_channels"],"properties":{"args":{"type":"string"},"rx_channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelInfo"}},"tx_channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelInfo"}}}},"RadioStreamState":{"type":"object","description":"Current stream lock/open state tracked by the Edge service.","required":["status"],"properties":{"channels":{"type":["array","null"],"items":{"type":"integer","minimum":0}},"data_type":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DataType"}]},"status":{"type":"string"}}},"RadioTaskState":{"type":"object","description":"Current state of the opened radio without changing stream configuration.","required":["device","stream","channels","task_details"],"properties":{"app_task":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AppTaskInfo"}]},"channels":{"type":"array","items":{"$ref":"#/components/schemas/RadioChannelState"}},"device":{"$ref":"#/components/schemas/RadioDeviceState"},"stream":{"$ref":"#/components/schemas/RadioStreamState"},"task_details":{"$ref":"#/components/schemas/StreamDetails"}}},"RecordReq":{"type":"object","description":"Parameters to request a recording of RX samples.\n* `num_samples`: Number of samples to record (min 1)\n* `stream_mode`: `single` for a single capture or `periodic` with the repeat interval in nanoseconds\n* `start_time`: Optional timestamp in nanoseconds to start recording\n* `stream_opts`: Optional override stream parameters\n* `webhooks`: Optional list of webhooks to receive output data.","required":["num_samples","stream_mode"],"properties":{"num_samples":{"type":"integer","example":512,"minimum":0},"start_time":{"type":["integer","null"],"format":"int64","example":null},"stream_mode":{"$ref":"#/components/schemas/StreamMode"},"stream_opts":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StreamOpts"}]},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/PostClientData"},"example":"[]"}},"example":{"num_samples":256,"stream_mode":{"periodic":6000000},"webhooks":[{"client_id":"uuid-of-registered-client-1"},{"client_id":"uuid-of-registered-client-2"}]}},"RegisterClientRequest":{"type":"object","required":["name","content_type","post_path"],"properties":{"authentication":{"type":["string","null"],"description":"Optional authentication token passed to downstream services.","example":"Bearer my-secret-random-string"},"content_type":{"$ref":"#/components/schemas/ReturnType","description":"Content-type applied to post call (json, bytes, discard)"},"init_path":{"type":["string","null"],"description":"Optional endpoint the server should call before starting jobs.","example":"http://url:port/api/setup/init"},"init_payload":{"description":"Optional json body sent along with the `init_path` POST."},"name":{"type":"string","description":"Name of Post Client.","example":"My Post Client"},"post_path":{"type":"string","description":"Callback URL that receives results of long-running jobs.","example":"http://url:port/api/add_result"}},"example":{"authentication":"Bearer my-secret-random-string","content_type":"json","init_path":"http://url:port/api/setup/init","init_payload":{"priority":10,"task":"configure"},"name":"My Post Client","post_path":"http://url:port/api/add_result"}},"RegisteredClient":{"type":"object","required":["client","info"],"properties":{"client":{"$ref":"#/components/schemas/PostClientData"},"info":{"$ref":"#/components/schemas/ClientInfo"}}},"ReturnType":{"type":"string","description":"Returned data format type. Options:\n* `json`: Return data as JSON in the response\n* `byte`: Return data as raw bytes\n* `discard`: Discard the data without storing or returning it","enum":["json","byte","discard"],"example":"json"},"RxStreamConfig":{"type":"object","description":"Consistent parameters for opening an RX radio stream.\n* `channel`: Channel(s) to open\n* `time_opts`: Time related parameters (time_source, clock_source, master_clock_rate)\n* `data_type`: Sample type (CI16 or CF32)\n* `stream_opts`: Stream-specific parameters (frequency, sample_rate, gain, AGC)\n\nConfigure channel-specific SoapySDR settings such as `rx_path` with the `/write_settings` endpoint.","required":["channel","data_type","time_opts","stream_opts"],"properties":{"channel":{"type":"array","items":{"type":"integer","minimum":0},"example":"[0]"},"data_type":{"$ref":"#/components/schemas/DataType"},"stream_opts":{"$ref":"#/components/schemas/StreamOpts"},"time_opts":{"$ref":"#/components/schemas/TimeOpts"}},"additionalProperties":false,"example":{"channel":[0],"data_type":"c_f32","stream_opts":{"frequency":2400000000,"sample_rate":31250000,"use_agc":true},"time_opts":{"clock_source":"internal","master_clock_rate":125000000,"time_source":"internal"}}},"SingleInferReq":{"type":"object","description":"Parameters to request a single inference stream.\n* `return_type`: Data format for client returned data \n* `return_input`: If `true` input data passed to inference model will be returned with the result\n* `start_time`: Optional timestamp in nanoseconds to start recording","required":["return_type","return_input"],"properties":{"return_input":{"type":"boolean","description":"If true and `return_type` is `byte`, append the input buffer to the output bytes"},"return_type":{"$ref":"#/components/schemas/ReturnType","description":"How to return the result for this single inference"},"start_time":{"type":["integer","null"],"format":"int64","description":"Optional hardware time (ns) to schedule the first capture"}},"example":{"return_input":false,"return_type":"byte","start_time":null}},"StreamDetails":{"type":"object","description":"Rolling status history for the stream.\nKeeps up to the last 10 status messages for both posting results and sample streaming.","required":["post_results","stream_results"],"properties":{"post_results":{"type":"array","items":{"type":"string"}},"stream_results":{"type":"array","items":{"type":"string"}}}},"StreamMode":{"oneOf":[{"type":"object","required":["single"],"properties":{"single":{"$ref":"#/components/schemas/ReturnType"}}},{"type":"object","required":["periodic"],"properties":{"periodic":{"type":"integer","format":"int64"}}}],"description":"Streaming mode for record requests. Options:\n* `Single`: Capture a single buffer and return according to `ReturnType`\n* `Periodic`: Continuously capture and post to registered webhooks at the given interval (nanoseconds)","example":"single"},"StreamOpts":{"type":"object","description":"Parameters that can be changed while the stream is open.\n* `frequency`: Center frequency in Hz\n* `sample_rate`: Sample rate in Hz\n* `gain`: Optional gain in dB\n* `use_agc`: Optional flag to enable automatic gain control","required":["frequency","sample_rate"],"properties":{"frequency":{"type":"number","format":"double","example":2400000000},"gain":{"type":["number","null"],"format":"double","example":0},"sample_rate":{"type":"number","format":"double","example":31250000},"use_agc":{"type":["boolean","null"],"example":true}},"example":{"frequency":2400000000,"gain":0,"sample_rate":31250000,"use_agc":true}},"TimeOpts":{"type":"object","description":"Consistent parameters for opening a device.\n* `clock_source`: Optional clock source (default: internal)\n* `time_source`: Optional time source (default: internal)\n* `master_clock_rate`: Optional master clock rate in Hz","properties":{"clock_source":{"type":["string","null"],"example":"internal"},"master_clock_rate":{"type":["number","null"],"format":"double","example":"125e6"},"time_source":{"type":["string","null"],"example":"internal"}},"example":{"clock_source":"internal","master_clock_rate":125000000,"time_source":"internal"}},"TransmitRequest":{"type":"object","description":"Parameters to transmit IQ samples over the SDR.\n* `buffer`: IQ samples to transmit (I16 or F32)\n* `time_ns`: Optional hardware timestamp in nanoseconds to schedule the transmission\n* `stream_opts`: Optional stream settings to override current RX/TX configuration\n* `repeat_rate`: Optional repeat interval in nanoseconds for repeated transmissions","required":["buffer"],"properties":{"buffer":{"$ref":"#/components/schemas/IQBuffer"},"repeat_rate":{"type":["integer","null"],"format":"int64","example":null},"stream_opts":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TxStreamOpts"}]},"time_ns":{"type":["integer","null"],"format":"int64","example":null}},"example":{"buffer":{"I16":[1,1,1,1]},"repeat_rate":null,"stream_opts":null,"time_ns":null}},"TxStreamConfig":{"type":"object","description":"Consistent parameters for opening a radio stream.\n* `channel`: Channel(s) to open\n* `time_opts`: Time related parameters (time_source, clock_source, master_clock_rate)\n* `data_type`: Sample type (CI16 or CF32)\n* `stream_opts`: Stream-specific parameters (frequency, sample_rate, gain)\n\nConfigure channel-specific SoapySDR settings such as `tx_amp_bypass` with the `/write_settings` endpoint.","required":["channel","data_type","time_opts","stream_opts"],"properties":{"channel":{"type":"array","items":{"type":"integer","minimum":0},"example":"[0]"},"data_type":{"$ref":"#/components/schemas/DataType"},"stream_opts":{"$ref":"#/components/schemas/TxStreamOpts"},"time_opts":{"$ref":"#/components/schemas/TimeOpts"}},"additionalProperties":false,"example":{"channel":[0],"data_type":"c_f32","stream_opts":{"frequency":2400000000,"sample_rate":31250000},"time_opts":{"clock_source":"internal","master_clock_rate":125000000,"time_source":"internal"}}},"TxStreamOpts":{"type":"object","description":"Parameters that can be changed while the stream is open.\n* `frequency`: Center frequency in Hz\n* `sample_rate`: Sample rate in Hz\n* `gain`: Optional gain in dB","required":["frequency","sample_rate"],"properties":{"frequency":{"type":"number","format":"double","example":2400000000},"gain":{"type":["number","null"],"format":"double","example":0},"sample_rate":{"type":"number","format":"double","example":31250000}},"example":{"frequency":2400000000,"gain":0,"sample_rate":31250000}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer"}}},"tags":[{"name":"Device","description":"Device API services manage exclusive access to the AIR-T hardware and retrieve device-level information.\n\n**Capabilities**:\n- Setup ownership of the RF Frontend\n- Release ownership of the RF Frontend\n- Configure device level settings of RF Frontend\n- Read device hardware time\n- Fetch hardware configuration and capabilities\n- Get current GPS status"},{"name":"Receive","description":"Receive Api services allow for configuring and controlling RX streams.\n\n**Capabilities**:\n- Open RX Stream\n- Close RX Stream\n- Check Stream Status (Open, Closed, In Use)\n- Record IQ Samples (Once or Repeated)\n- Cancel Receive Taks\n- [Debug] Loopback Inject and Receive Samples"},{"name":"Apps","description":"Inference APIs for predictions \n\n**Capabilities**:\n- Request a prediction\n- Start an inference stream\n- Cancel an inference stream\n- Playback inference data\n- [Debug] Restart the inference server\n- [Debug] Inject samples and recevie a prediction"},{"name":"Config","description":"Inference APIs for model management \n\n**Capabilities**:\n- List available inference models\n- Enable a specific model / version combination\n- Disable a specific model / version combination\n- Inspect a specific model for generic information\n- Probe a specific model for inference statistics\n- Upload a new inference model version"},{"name":"Transmit","description":"Transmit Api services allow for configuring and controlling TX streams.\n\n**Capabilities**:\n- Open TX Stream\n- Close TX Stream\n- Transmit IQ Samples (Once or Repeated)\n- Probe Transmission Status\n- Cancel Transmit Taks"},{"name":"Webhooks","description":"Webhooks Api services are used to configure endpoints to send results.\n\n**Capabilities**:\n- Register Endpoint to Send Results\n- List Available Endpoints\n- Delete Endpoint"}],"x-tagGroups":[{"name":"Device","tags":["Device"]},{"name":"Receive","tags":["Receive"]},{"name":"Apps","tags":["Apps","Config"]},{"name":"Transmit","tags":["Transmit"]},{"name":"Webhooks","tags":["Webhooks"]}]}