Skip to main content

Signals API

Connect a real sensor feed to DomeCommand over a simple HTTP API. Authenticate, POST detections, and the live picture is driven by your data.

:::note This is the integration page Everywhere else these docs describe the product. This page is for engineers wiring a sensor feed, bridge or middleware into DomeCommand. It documents the live HTTP API. :::

Every sensor, bridge or fusion box speaks to DomeCommand the same way: it POSTs detections to the signals endpoint. Each detection is a signal, one observation from one sensor. DomeCommand ingests the stream, fuses it into tracks (see Sensor fusion), and drives the live picture from it.

Base URL & versioning

All endpoints are served under the /v1 prefix on your DomeCommand backend:

https://<your-backend-host>/v1

Authentication

Every request must be authenticated and scoped to a workspace.

Authenticate with either a bearer token or a workspace API key:

Authorization: Bearer <jwt>
#, or —
X-API-Key: dak_<your_api_key>

And always identify the workspace the data belongs to:

X-Workspace-Id: <workspace-uuid>

:::tip Use an API key for machine-to-machine feeds A long-lived, workspace-scoped API key (prefixed dak_) is the right credential for a sensor bridge or middleware that runs unattended. Bearer tokens suit interactive sessions. :::

Push detections, POST /v1/signals

Send a JSON array of detections in one request, batching is expected and efficient. Only source and kind are required; the server stamps the workspace and arrival time for you, and confidence defaults to 1.0 if you omit it.

curl -X POST https://<your-backend-host>/v1/signals \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '[
{
"source": "giraffe-radar-01",
"kind": "radar",
"track_id": "0148",
"classification": "fpv",
"lat": 1.2841,
"lng": 103.8510,
"heading_deg": 215.0,
"speed_mps": 34.5,
"confidence": 0.92,
"observed_at": "2026-06-02T08:14:22Z"
},
{
"source": "rf-detector-03",
"kind": "rf",
"track_id": "0148",
"classification": "fpv",
"confidence": 0.74
}
]'

A successful call returns the number of signals stored:

{ "ingested": 2 }

From JavaScript

await fetch("https://<your-backend-host>/v1/signals", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"X-Workspace-Id": workspaceId,
"Content-Type": "application/json",
},
body: JSON.stringify([
{
source: "eoir-tracker-02",
kind: "eo-ir",
track_id: "0148",
classification: "fpv",
lat: 1.2843, lng: 103.8512,
heading_deg: 214.0, speed_mps: 35.1,
confidence: 0.88,
},
]),
});

Signal fields

FieldRequiredTypeMeaning
sourceyesstringWhich sensor or feed produced the detection (e.g. giraffe-radar-01).
kindyesstringThe kind of sensor / signal (e.g. radar, rf, eo-ir, acoustic).
track_idnostringYour identifier for the contact. Detections sharing a track_id are associated.
classificationnostringWhat the source believes it is (e.g. fpv, loiter-muni, cruise).
lat, lngnonumberGeographic position.
x, ynonumberPosition in map-frame units, if you work in a local frame.
heading_degnonumberHeading in degrees.
speed_mpsnonumberSpeed in metres per second.
confidencenonumberDetection confidence 0.0–1.0. Defaults to 1.0.
observed_atnotimestampWhen the sensor saw it (ISO-8601). Defaults to ingest time.
payloadnoobjectAny source-specific extras you want to carry along.

Read it back, GET /v1/signals

Query recent signals for the workspace, newest first:

curl "https://<your-backend-host>/v1/signals?kind=radar&limit=200&since=2026-06-02T08:00:00Z" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"
Query paramDefaultNotes
limit200Maximum rows to return (capped at 2000).
kind,Filter to one sensor kind.
since,Only signals at or after this ISO-8601 timestamp.

Counts by kind, GET /v1/signals/stats

A quick health check, how many signals of each kind have landed:

curl https://<your-backend-host>/v1/signals/stats \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"
[
{ "kind": "radar", "n": 1284 },
{ "kind": "rf", "n": 642 },
{ "kind": "eo-ir", "n": 210 }
]

The console uses this to show a live signals indicator, the running count of ingested detections, or a dash when the feed is unreachable.

How the ingested stream becomes the picture

Once your detections are flowing in, DomeCommand associates them by contact, fuses across sensor kinds, and renders the result as the live air picture the operator works from. You push raw detections; DomeCommand turns them into one clean, current view.

Read how that fusion works in Sensor fusion.