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.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, RemoteAccessPolicyView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:initiate. |
404 | application/problem+json, ProblemDetails | Endpoint not found. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
aiControlrequired | RemoteAIControlView | remoteAIControlView is the remote policy view's aiControl (21.2). |
aiControl.availablerequired | boolean | |
aiControl.reason | string or null | |
allowedModesrequired | array of string | |
escortQuorumrequired | integer | |
idleReauthSourcerequired | string | |
idleResumeRequiresReauthrequired | boolean | |
moderequired | string | |
recordingRequiredrequired | boolean | |
sessionMaxSecondsrequired | integer | |
sessionMaxSourcerequired | DurationSource | 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.kindrequired | string | |
sessionMaxSource.originalKind | string | |
sessionMaxSource.originalSeconds | integer | |
sessionMaxSource.profileCount | integer | |
sessionMaxSource.profileId | string | |
sessionMaxSource.profileName | string | |
sourcerequired | string | |
techIdlePauseMinutesrequired | integer | |
transferrequired | RemoteTransferPolicyView | 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_endpointrequired | string, one of keyed, none, plain | |
transfer.audit_hash_to_technicianrequired | string | |
transfer.audit_names_to_endpointrequired | string, one of file_name, full_path, name_hash, path_hash | |
transfer.audit_names_to_technicianrequired | string | |
transfer.audit_sizes_to_endpointrequired | string, one of exact, summary | |
transfer.audit_sizes_to_technicianrequired | string | |
transfer.clipboard_imagesrequired | array of string | |
transfer.clipboard_textrequired | array of string | |
transfer.filesrequired | array of string | |
transfer.lockedByrequired | object | |
transfer.max_file_bytes | integer | int64. |
transfer.max_session_bytes | integer | int64. |
transfer.require_verification | boolean |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy";
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/policy");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes | |
page | query | integer | No | One-based page number. Defaults to 1. |
pageSize | query | integer | No | Rows per page, 1 to 200. Defaults to 50. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, PagedResultRecordingView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:view_recordings. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of RecordingView | |
items[].codecrequired | string | |
items[].createdAtrequired | string (date-time) | |
items[].durationSecondsrequired | integer | |
items[].endedAt | string (date-time) or null | |
items[].recordingIdrequired | string | |
items[].retentionExpiresAt | string (date-time) or null | |
items[].sessionIdrequired | string | |
items[].sizeBytesrequired | integer | int64. |
items[].startedAtrequired | string (date-time) | |
pagerequired | integer | |
pageSizerequired | integer | |
totalrequired | integer |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings?page=0&pageSize=0' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings"params = { "page": "0", "pageSize": "0",}headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, params=params, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings?page=0&pageSize=0", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = new URL("https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings");url.searchParams.set("page", "0");url.searchParams.set("pageSize", "0");
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/recordings?page=0&pageSize=0");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes | |
page | query | integer | No | One-based page number. Defaults to 1. |
pageSize | query | integer | No | Rows per page, 1 to 200. Defaults to 50. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, PagedResultRemoteSessionSummary | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:read. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of RemoteSessionSummary | |
items[].agentIdrequired | string | |
items[].capabilitiesrequired | array of string | |
items[].createdAtrequired | string (date-time) | |
items[].endReasonrequired | string | |
items[].endedAt | string (date-time) or null | |
items[].loggedInUser | string or null | |
items[].moderequired | string | |
items[].recordingEnabledrequired | boolean | |
items[].sessionIdrequired | string | |
items[].startedAt | string (date-time) or null | |
items[].staterequired | string | |
items[].targetrequired | any | Arbitrary JSON. |
items[].technicianNamerequired | string | |
items[].technicianUserIdrequired | string | |
pagerequired | integer | |
pageSizerequired | integer | |
totalrequired | integer |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions?page=0&pageSize=0' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions"params = { "page": "0", "pageSize": "0",}headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, params=params, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions?page=0&pageSize=0", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = new URL("https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions");url.searchParams.set("page", "0");url.searchParams.set("pageSize", "0");
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions?page=0&pageSize=0");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes | |
sessionID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, EscortView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:escort. |
404 | application/problem+json, ProblemDetails | Session not found. |
409 | application/problem+json, ProblemDetails | Session is not an escorted session. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
presentEscortsrequired | integer | |
sessionIdrequired | string |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.post(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort";
const response = await fetch(url, { method: "POST", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes | |
sessionID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, EscortView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:escort. |
404 | application/problem+json, ProblemDetails | Session not found. |
409 | application/problem+json, ProblemDetails | Session is not an escorted session. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
presentEscortsrequired | integer | |
sessionIdrequired | string |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Delete ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.delete(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodDelete, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort";
const response = await fetch(url, { method: "DELETE", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Delete, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/escort");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes | |
sessionID | path | string | Yes | |
page | query | integer | No | One-based page number. Defaults to 1. |
pageSize | query | integer | No | Rows per page, 1 to 200. Defaults to 50. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, PagedResultRecordingView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:view_recordings. |
404 | application/problem+json, ProblemDetails | Session not found. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of RecordingView | |
items[].codecrequired | string | |
items[].createdAtrequired | string (date-time) | |
items[].durationSecondsrequired | integer | |
items[].endedAt | string (date-time) or null | |
items[].recordingIdrequired | string | |
items[].retentionExpiresAt | string (date-time) or null | |
items[].sessionIdrequired | string | |
items[].sizeBytesrequired | integer | int64. |
items[].startedAtrequired | string (date-time) | |
pagerequired | integer | |
pageSizerequired | integer | |
totalrequired | integer |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings?page=0&pageSize=0' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings"params = { "page": "0", "pageSize": "0",}headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, params=params, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings?page=0&pageSize=0", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = new URL("https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings");url.searchParams.set("page", "0");url.searchParams.set("pageSize", "0");
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/sessions/<sessionID>/recordings?page=0&pageSize=0");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
101 | None | Switching protocols. The connection continues as a websocket; see x-outpost-transport. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:initiate. |
404 | application/problem+json, ProblemDetails | Endpoint not found. |
500 | application/problem+json, ProblemDetails | No client context in request. |
503 | application/problem+json, ProblemDetails | The media relay is not available. |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal";
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/signal");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, array of object | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:initiate. |
404 | application/problem+json, ProblemDetails | Endpoint not found. |
500 | application/problem+json, ProblemDetails | Could not read endpoint. |
503 | application/problem+json, ProblemDetails | Target discovery is unavailable. |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets";
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/endpoints/<agentID>/remote/targets");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
recordingID | path | string | Yes |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | None | Success. The body shape was not resolved; see x-outpost-unresolved. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold remote:view_recordings. |
404 | application/problem+json, ProblemDetails | Recording not found. |
422 | application/problem+json, ProblemDetails | This recording contains no video. |
500 | application/problem+json, ProblemDetails | No client context in request. |
503 | application/problem+json, ProblemDetails | Recording playback is not available. |
Request samples
Section titled “Request samples”# 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>'# 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.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/remote/recordings/<recordingID>/media' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# 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.
import requests
url = "https://depot.example.com/api/v1/remote/recordings/<recordingID>/media"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// 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.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/remote/recordings/<recordingID>/media", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// 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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/remote/recordings/<recordingID>/media";
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// 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.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/remote/recordings/<recordingID>/media");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());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.