Get a takeover recording
Returns one recorded takeover session, decrypted with the
orchestrator key. Fuse-Recording-Kind says which kind it is.
A terminal session is an asciinema v2 cast
(application/x-asciicast): a JSON header line, then one
[seconds, "o" | "r", data] line per output chunk or resize. It
holds what the guest printed, never what the human typed. Play
it with asciinema play.
A desktop session is a DesktopRecording (application/json):
the input-action log plus the screenshots. It never holds the
keys the human typed or the text they pasted.
Requires hitl:read. A recording of an environment the caller’s
key does not cover is 404, the same as one that does not exist.
GET
/v1/hitl/recordings/{recordingId}Authorization
AuthorizationBearer token · headerrequired`Authorization: Bearer <token>` — either the static master token
(`ORCH_AUTH_TOKEN`) or a revocable API key issued via
/v1/api-keys (API keys require Postgres; without a database only
the master token is accepted). Master-only surfaces (exec,
attach, API key management) refuse API keys with 403. An expired
key is refused with 401 like an unknown one.
A key minted with `scopes` reaches only the hitl routes
(`/v1/interventions`, `/v1/hitl/*`, and POST /v1/api-keys to mint
a narrower key). Any other route is 403 code `forbidden`, reason
`env_scope`, except an `/v1/environments/{vmId}` route for an
environment the key does not cover, which is 404 so the key
cannot probe which environments exist.
**Authentication can be disabled entirely.** When neither
`ORCH_AUTH_TOKEN` nor an API key store (`DATABASE_URL`) is
configured — the default local-development posture — the bearer
middleware becomes a pass-through: every operation this document
marks as secured is reachable with no credentials, requests carry
no principal, and master-only surfaces therefore admit everyone.
Never run that configuration on a reachable network; set
`ORCH_REQUIRE_AUTH=true` to make the orchestrator refuse to start
without a master token.
or
fuse_sessionAPI key · cookierequiredHttpOnly session cookie set by POST /login for browser callers.
Consulted only when no Authorization header is present.
Path parameters
recordingIdstringrequiredThe `recording_id` of a `takeover_session` audit row.
Header parameters
Fuse-ActorstringThe person behind this request, as an opaque id (`user_42`,
`alice@corp.com`, `slack:U0123`). Fuse records it on hitl
interventions and the audit log and never checks it. Accepted on
every authenticated route; it matters wherever an actor is
recorded (raising, deciding, minting). At most 128 bytes, no
control characters; a malformed value is 400.
How the recorded actor is resolved:
- key pinned to an actor: that actor (`source: pinned`). A
different `Fuse-Actor` is 403 `forbidden`, reason
`actor_mismatch`.
- key with `hitl:act-as`: the header value (`source: asserted`,
with the asserting key's id), else `key:<key_id>`.
- any other key: `key:<key_id>` named after the key's label
(`source: key`). Sending the header is 403 `forbidden`, reason
`actor_not_allowed`, rather than silently dropped.
- master token: the header value (`source: asserted`), else
`master` (`source: key`).
An asserted actor is only as true as the key holder's own auth.
max length 128
Fuse-Actor-NamestringOptional display name for `Fuse-Actor`, at most 256 bytes. Sending
it without `Fuse-Actor` is 400.
max length 256
Responses
200The recording.
versionintegerrequiredAllowed:
1kindstringrequiredAllowed:
desktopintervention_idstringrequiredenv_idstringrequiredactorstringrequiredThe id of the actor who held the view.
started_atstring<date-time>requiredended_atstring<date-time>requiredtruncatedbooleanSet when screenshots passed 32 MiB or the log 50,000 entries.
input_log_incompletebooleanSet when the viewer sent something the log does not
understand, after which no more input was logged. The
screenshots carry on.
eventsobject[]requiredShow propertiesHide properties
Array of
objecttnumberrequiredSeconds since the session started.
typestringrequiredAllowed:
pointerkeytextclipboardxintegeryintegerbuttonsintegerkeystringcharsintegerbytesintegerscreenshotsobject[]requiredShow propertiesHide properties
Array of
objecttnumberrequiredSeconds since the session started.
pngstringrequiredBase64 PNG.
403The caller authenticated, but may not make this request.
Master-only surfaces (exec, attach, listing and revoking API keys)
refuse API keys; those 403 bodies carry code `unauthorized`. CIDR
allowlist rejections return 403 with code `forbidden` and no
reason. Access checks on the hitl routes and scoped keys return
403 with code `forbidden` and `details.reason` set to one of:
- `missing_scope`: the key lacks the scope the route needs
(`details.scope` names it). Full-access keys never hold
`hitl:decide`, `hitl:secret`, `hitl:takeover` or `hitl:act-as`.
- `env_scope`: a scoped key called a route outside the hitl
routes.
- `self_approval`: the key or actor that raised an intervention
tried to decide it.
- `actor_required`: the environment sets `require_actor` and the
decision names no pinned or asserted actor.
- `actor_mismatch`: `Fuse-Actor` differs from the key's pinned
actor.
- `actor_not_allowed`: `Fuse-Actor` sent by a key without
`hitl:act-as`.
- `hitl_denied`: a hitl gate in `deny` mode, or a gate's decider,
refused an exec, lifecycle or computer action, or an edit
matched a `deny` gate. `details.gate` names the gate and
`details.intervention_id` the terminal record; the message is
the gate's `reason`.
- `mint_escalation`: a scoped key tried to mint a key wider than
itself.
errorobjectrequiredShow propertiesHide properties
codestringrequiredStable machine-readable code. `route_not_found` (404)
means the URL matches no route this server exposes —
usually a wrong host, port, or path prefix — as opposed
to `not_found`, where the route exists but the resource
does not. `forbidden` is emitted by CIDR-allowlist
rejections and by hitl access checks, which set
`details.reason` (see the Forbidden response);
master-only refusals (exec, attach, listing and revoking
API keys) return 403 with code `unauthorized`.
Allowed:
not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequiredHuman-readable description.
detailsobjectOptional stable, non-sensitive metadata (e.g. ids,
counts). Omitted when empty. A 403 `forbidden` from a
hitl access check carries `reason` (`missing_scope`,
`env_scope`, `self_approval`, `actor_required`,
`actor_mismatch`, `actor_not_allowed`,
`mint_escalation`, `hitl_denied`), plus `scope` for
`missing_scope`, and `gate` and `intervention_id` for
`hitl_denied`. A 423 `locked` carries `intervention_id`
and `kind` (`takeover` or `stall`).
404Resource does not exist. Note the distinct code
`route_not_found`, returned when the URL matches no registered
route at all (wrong host, port, or path prefix) rather than a
known route with a missing resource.
errorobjectrequiredShow propertiesHide properties
codestringrequiredStable machine-readable code. `route_not_found` (404)
means the URL matches no route this server exposes —
usually a wrong host, port, or path prefix — as opposed
to `not_found`, where the route exists but the resource
does not. `forbidden` is emitted by CIDR-allowlist
rejections and by hitl access checks, which set
`details.reason` (see the Forbidden response);
master-only refusals (exec, attach, listing and revoking
API keys) return 403 with code `unauthorized`.
Allowed:
not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequiredHuman-readable description.
detailsobjectOptional stable, non-sensitive metadata (e.g. ids,
counts). Omitted when empty. A 403 `forbidden` from a
hitl access check carries `reason` (`missing_scope`,
`env_scope`, `self_approval`, `actor_required`,
`actor_mismatch`, `actor_not_allowed`,
`mint_escalation`, `hitl_denied`), plus `scope` for
`missing_scope`, and `gate` and `intervention_id` for
`hitl_denied`. A 423 `locked` carries `intervention_id`
and `kind` (`takeover` or `stall`).
500Unexpected server error.
errorobjectrequiredShow propertiesHide properties
codestringrequiredStable machine-readable code. `route_not_found` (404)
means the URL matches no route this server exposes —
usually a wrong host, port, or path prefix — as opposed
to `not_found`, where the route exists but the resource
does not. `forbidden` is emitted by CIDR-allowlist
rejections and by hitl access checks, which set
`details.reason` (see the Forbidden response);
master-only refusals (exec, attach, listing and revoking
API keys) return 403 with code `unauthorized`.
Allowed:
not_foundroute_not_foundconflictinvalid_argumentunauthorizedforbiddenunavailableinternalunimplementedlockedmessagestringrequiredHuman-readable description.
detailsobjectOptional stable, non-sensitive metadata (e.g. ids,
counts). Omitted when empty. A 403 `forbidden` from a
hitl access check carries `reason` (`missing_scope`,
`env_scope`, `self_approval`, `actor_required`,
`actor_mismatch`, `actor_not_allowed`,
`mint_escalation`, `hitl_denied`), plus `scope` for
`missing_scope`, and `gate` and `intervention_id` for
`hitl_denied`. A 423 `locked` carries `intervention_id`
and `kind` (`takeover` or `stall`).
Request
curl -X GET "http://localhost:8080/v1/hitl/recordings/string" \
-H "Authorization: Bearer YOUR_TOKEN"const response = await fetch("http://localhost:8080/v1/hitl/recordings/string", {
method: "GET",
headers: {
"Authorization": "Bearer YOUR_TOKEN"
}
});import requests
response = requests.get(
"http://localhost:8080/v1/hitl/recordings/string",
headers={
"Authorization": "Bearer YOUR_TOKEN"
},
)Response
{
"version": 1,
"kind": "desktop",
"intervention_id": "string",
"env_id": "string",
"actor": "string",
"started_at": "2024-01-01T00:00:00Z",
"ended_at": "2024-01-01T00:00:00Z",
"truncated": true,
"input_log_incomplete": true,
"events": [
{
"t": 0,
"type": "pointer",
"x": 0,
"y": 0,
"buttons": 0,
"key": "string",
"chars": 0,
"bytes": 0
}
],
"screenshots": [
{
"t": 0,
"png": "string"
}
]
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}{
"error": {
"code": "not_found",
"message": "string",
"details": {}
}
}