Skip to content

Depot remote

Registers the remote-access routes on mux (wrapped by the caller in tenant.Middleware).

This page is generated from the Depot route table. Every operation carries the permission it needs and the anchor an agent can link to.

GET /api/v1/endpoints/{agentID}/remote/policy

Section titled “GET /api/v1/endpoints/{agentID}/remote/policy”

GETremote:initiatetenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

getRemoteAccessPolicy resolves the effective remote-access policy for this endpoint and the calling technician.

The resolver is stateless, so it is constructed here rather than threaded through MountRemote.

NameInTypeRequiredDescription
agentIDpathstringYes
StatusBodyDescription
200application/json, RemoteAccessPolicyViewSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:initiate.
404application/problem+json, ProblemDetailsEndpoint not found.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
aiControlrequiredRemoteAIControlView

remoteAIControlView is the remote policy view's aiControl (21.2).

aiControl.availablerequiredboolean
aiControl.reasonstring or null
allowedModesrequiredarray of string
escortQuorumrequiredinteger
idleReauthSourcerequiredstring
idleResumeRequiresReauthrequiredboolean
moderequiredstring
recordingRequiredrequiredboolean
sessionMaxSecondsrequiredinteger
sessionMaxSourcerequiredDurationSource

DurationSource says where a session's authorized length came from, so a technician whose session ran out can be told which setting to change (RD_VIEWER_UI_CONTRACTS.md section 7.1).

sessionMaxSource.kindrequiredstring
sessionMaxSource.originalKindstring
sessionMaxSource.originalSecondsinteger
sessionMaxSource.profileCountinteger
sessionMaxSource.profileIdstring
sessionMaxSource.profileNamestring
sourcerequiredstring
techIdlePauseMinutesrequiredinteger
transferrequiredRemoteTransferPolicyView

RemoteTransferPolicyView is the clipboard and file-transfer policy the relay will sign into the session's token, as the console reads it.

transfer.audit_hash_to_endpointrequiredstring, one of keyed, none, plain
transfer.audit_hash_to_technicianrequiredstring
transfer.audit_names_to_endpointrequiredstring, one of file_name, full_path, name_hash, path_hash
transfer.audit_names_to_technicianrequiredstring
transfer.audit_sizes_to_endpointrequiredstring, one of exact, summary
transfer.audit_sizes_to_technicianrequiredstring
transfer.clipboard_imagesrequiredarray of string
transfer.clipboard_textrequiredarray of string
transfer.filesrequiredarray of string
transfer.lockedByrequiredobject
transfer.max_file_bytesinteger

int64.

transfer.max_session_bytesinteger

int64.

transfer.require_verificationboolean
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/endpoints/{agentID}/remote/recordings

Section titled “GET /api/v1/endpoints/{agentID}/remote/recordings”

GETremote:view_recordingstenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

listRecordingsForAgent returns every recording of every session on the agent.

NameInTypeRequiredDescription
agentIDpathstringYes
pagequeryintegerNoOne-based page number. Defaults to 1.
pageSizequeryintegerNoRows per page, 1 to 200. Defaults to 50.
StatusBodyDescription
200application/json, PagedResultRecordingViewSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:view_recordings.
404application/problem+json, ProblemDetailsNo resource matches that id.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
itemsrequiredarray of RecordingView
items[].codecrequiredstring
items[].createdAtrequiredstring (date-time)
items[].durationSecondsrequiredinteger
items[].endedAtstring (date-time) or null
items[].recordingIdrequiredstring
items[].retentionExpiresAtstring (date-time) or null
items[].sessionIdrequiredstring
items[].sizeBytesrequiredinteger

int64.

items[].startedAtrequiredstring (date-time)
pagerequiredinteger
pageSizerequiredinteger
totalrequiredinteger
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings?page=0&pageSize=0' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/endpoints/{agentID}/remote/sessions

Section titled “GET /api/v1/endpoints/{agentID}/remote/sessions”

GETremote:readtenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

List remote sessions

NameInTypeRequiredDescription
agentIDpathstringYes
pagequeryintegerNoOne-based page number. Defaults to 1.
pageSizequeryintegerNoRows per page, 1 to 200. Defaults to 50.
StatusBodyDescription
200application/json, PagedResultRemoteSessionSummarySuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:read.
404application/problem+json, ProblemDetailsNo resource matches that id.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
itemsrequiredarray of RemoteSessionSummary
items[].agentIdrequiredstring
items[].capabilitiesrequiredarray of string
items[].createdAtrequiredstring (date-time)
items[].endReasonrequiredstring
items[].endedAtstring (date-time) or null
items[].loggedInUserstring or null
items[].moderequiredstring
items[].recordingEnabledrequiredboolean
items[].sessionIdrequiredstring
items[].startedAtstring (date-time) or null
items[].staterequiredstring
items[].targetrequiredany

Arbitrary JSON.

items[].technicianNamerequiredstring
items[].technicianUserIdrequiredstring
pagerequiredinteger
pageSizerequiredinteger
totalrequiredinteger
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions?page=0&pageSize=0' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

POST /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/escort

Section titled “POST /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/escort”

POSTremote:escorttenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

Join escort

NameInTypeRequiredDescription
agentIDpathstringYes
sessionIDpathstringYes
StatusBodyDescription
200application/json, EscortViewSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:escort.
404application/problem+json, ProblemDetailsSession not found.
409application/problem+json, ProblemDetailsSession is not an escorted session.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
presentEscortsrequiredinteger
sessionIdrequiredstring
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X POST 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

DELETE /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/escort

Section titled “DELETE /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/escort”

DELETEremote:escorttenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

Leave escort

NameInTypeRequiredDescription
agentIDpathstringYes
sessionIDpathstringYes
StatusBodyDescription
200application/json, EscortViewSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:escort.
404application/problem+json, ProblemDetailsSession not found.
409application/problem+json, ProblemDetailsSession is not an escorted session.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
presentEscortsrequiredinteger
sessionIdrequiredstring
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X DELETE 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/recordings

Section titled “GET /api/v1/endpoints/{agentID}/remote/sessions/{sessionID}/recordings”

GETremote:view_recordingstenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

listRecordingsForSession returns every recording of one session on the agent.

NameInTypeRequiredDescription
agentIDpathstringYes
sessionIDpathstringYes
pagequeryintegerNoOne-based page number. Defaults to 1.
pageSizequeryintegerNoRows per page, 1 to 200. Defaults to 50.
StatusBodyDescription
200application/json, PagedResultRecordingViewSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:view_recordings.
404application/problem+json, ProblemDetailsSession not found.
500application/problem+json, ProblemDetailsNo client store in request context.

200 response body

FieldTypeDescription
itemsrequiredarray of RecordingView
items[].codecrequiredstring
items[].createdAtrequiredstring (date-time)
items[].durationSecondsrequiredinteger
items[].endedAtstring (date-time) or null
items[].recordingIdrequiredstring
items[].retentionExpiresAtstring (date-time) or null
items[].sessionIdrequiredstring
items[].sizeBytesrequiredinteger

int64.

items[].startedAtrequiredstring (date-time)
pagerequiredinteger
pageSizerequiredinteger
totalrequiredinteger
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings?page=0&pageSize=0' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/endpoints/{agentID}/remote/signal

Section titled “GET /api/v1/endpoints/{agentID}/remote/signal”

GETremote:initiatetenant facehosteditmspremoteIdempotentWebSocket

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

remoteSignal upgrades the request to a WebSocket and hands the session to the relay.

The endpoint must exist in this client’s database; the initiating technician is the authenticated operator. The relay owns the session for the life of the socket, so this handler blocks until the session ends.

NameInTypeRequiredDescription
agentIDpathstringYes
StatusBodyDescription
101NoneSwitching protocols. The connection continues as a websocket; see x-outpost-transport.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:initiate.
404application/problem+json, ProblemDetailsEndpoint not found.
500application/problem+json, ProblemDetailsNo client context in request.
503application/problem+json, ProblemDetailsThe media relay is not available.
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This endpoint upgrades to a WebSocket. The sample shows the handshake only.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/endpoints/{agentID}/remote/targets

Section titled “GET /api/v1/endpoints/{agentID}/remote/targets”

GETremote:initiatetenant facehosteditmspremoteIdempotent

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

Source: [object Object]

Remote targets

NameInTypeRequiredDescription
agentIDpathstringYes
StatusBodyDescription
200application/json, array of objectSuccess.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:initiate.
404application/problem+json, ProblemDetailsEndpoint not found.
500application/problem+json, ProblemDetailsCould not read endpoint.
503application/problem+json, ProblemDetailsTarget discovery is unavailable.
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

GET /api/v1/remote/recordings/{recordingID}/media

Section titled “GET /api/v1/remote/recordings/{recordingID}/media”

GETremote:view_recordingstenant facehosteditmspremoteIdempotentNot fully resolved

From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.

What this page does not know
  • response

These are parts of the route the extractor could not read from the source. Everything else on this page came straight from it.

Source: [object Object]

playRecording looks up the recording, unwraps its DEK with the tenant KEK, and serves it to the browser as a seekable fragmented MP4.

WHICH FORMAT IS ON DISK COMES FROM THE ROW, never from the file. Recordings are VP9-in-IVF today and were raw H.264 before that; rec.Codec says which, and recording.CountFrames / recording.MuxToFMP4 dispatch on it so a recording made under either pipeline plays byte-for-byte as it always did. The response is fragmented MP4 in both cases, so nothing past this handler knows the difference.

The stored media is read twice and the muxed result is written to a temporary file, which is then served with http.ServeContent. Three problems make that the right shape rather than streaming straight to the response:

  • What is stored is a bare elementary stream with no timing in it at all. The recording’s sidecar timing index supplies a real duration per frame; without one (anything recorded before the index existed) the first pass counts frames so the session’s wall-clock duration can be spread over them, which gets the total right and everything inside it approximately right. The count is cheap and is taken either way, since it is also what tells an empty recording apart from a broken one.
  • Streaming the mux directly means no Content-Length and no byte ranges. The browser then reports the duration of whatever it has buffered so far (a 967-second session showed as 38 seconds), and the scrub bar cannot reach anything not yet downloaded. Reviewing a session is mostly seeking, so that is close to unusable.
  • Nothing reaches the client until the mux has fully succeeded, so an unplayable recording produces a JSON problem response rather than a truncated video the browser stalls on.

ServeContent then handles Range, If-Range, 206 and HEAD.

ponytail: the rendition is rebuilt per request and deleted afterwards, so each Range request re-muxes (~120 ms for a 16-minute recording, measured). Caching it next to the recording is the upgrade if playback traffic ever justifies the disk, and lands naturally with object-storage upload.

NameInTypeRequiredDescription
recordingIDpathstringYes
StatusBodyDescription
200NoneSuccess. The body shape was not resolved; see x-outpost-unresolved.
401application/problem+json, ProblemDetailsNo signed-in identity.
403application/problem+json, ProblemDetailsThe identity does not hold remote:view_recordings.
404application/problem+json, ProblemDetailsRecording not found.
422application/problem+json, ProblemDetailsThis recording contains no video.
500application/problem+json, ProblemDetailsNo client context in request.
503application/problem+json, ProblemDetailsRecording playback is not available.
Terminal window
# Sign in first. outpost_console is a session cookie, so send it with every request.
# This operation is idempotent. Repeating it does not repeat its effect.
curl -X GET 'https://depot.example.com/api/v1/remote/recordings/<recordingID>/media' \
-H 'X-CSRF-Token: <csrf-token>' \
-H 'Accept: application/json' \
-b 'outpost_console=<console-session>'

Content is licensed CC BY 4.0. Code samples are MIT. Outpost and the Outpost mark are trademarks of Outpost Business Solutions, PBC and are not covered by either license.