Authentication
Two headers on every request: a credential, and the workspace it acts in. Set them once here; every guide uses these variables.
1. Get a key
Settings → Access → NEW KEY. Name it after the bridge or script that will hold it. The
secret starts with dak_, is shown once, does not expire, and is revoked from the same
list.
Or mint one from a signed-in session:
# A session token comes from signing in to the console. It lasts thirty minutes;
# a key lasts until it is revoked, which is what an unattended script wants
curl -s -X POST https://<your-backend-host>/api/keys \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "X-Workspace-Id: wsp_…" \
-H "Content-Type: application/json" \
-d '{ "name": "harbour-bridge" }' \
| jq '.data | {name, prefix, secret}'
# → { "name": "harbour-bridge", "prefix": "dak_o9yF", "secret": "dak_o9yF…" }
# copy secret now: the server keeps only a hash
2. Find the workspace
# Every workspace this credential can act in, with your role in each
curl -s https://<your-backend-host>/api/me \
-H "Authorization: Bearer $SESSION_TOKEN" \
| jq '.data.workspaces[] | {id, name, role}'
# → { "id": "wsp_3465c050…", "name": "Harbour", "role": "owner" }
A key belongs to the workspace it was minted in, and already names it. The guides send
X-Workspace-Id anyway: it is required with a session token, and a key sent with the wrong
one is refused rather than quietly acting somewhere else.
3. Set the variables
# Every integration guide uses these three, and repeats none of them
export DOME=https://<your-backend-host>/api # the deployment's API root
export KEY=dak_… # from step 1
export WS=wsp_… # from step 2
Every request then carries both headers:
# Check both work: the workspace's current environment and run state
curl -s $DOME/sim/state \
-H "X-Api-Key: $KEY" \
-H "X-Workspace-Id: $WS"
# → {"ok":true,"data":{"mode":"live","simulator":"lite","run":"idle"}}
4. Open the stream
The event stream takes neither the key nor a token. It takes a one-time ticket, good for a minute:
# Mint a ticket with the key ...
TICKET=$(curl -s -X POST $DOME/auth/stream-ticket \
-H "X-Api-Key: $KEY" -H "X-Workspace-Id: $WS" \
| jq -r '.data.ticket') # → stk_8Fw6CVdP…
# ... and spend it opening the stream. It names the workspace for you
curl -sN "$DOME/stream?ticket=$TICKET"
# → event: snapshot the whole picture, once
# event: track_update then one event per change
Reconnecting needs a new ticket. Events: Picture & stream.
When it is refused
| Answer | Means |
|---|---|
401 unauthenticated | No credential, or a key that was revoked or never issued. |
400 invalid_input | A session token with no X-Workspace-Id. The error points at GET /api/me. |
403 forbidden | A key sent with a workspace it does not belong to. |
403 not_a_member | A session token naming a workspace you are not in. |
403 on a write | A read-only role. |
Every answer is { "ok": true, "data": … } or { "ok": false, "error": "…", "code": "…" }.
See API overview.
Next: Running a simulation · Working with assets · Commanding assets