Depot tickets
Registers the ticket routes on mux.
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/ticket-macros
Section titled “GET /api/v1/ticket-macros”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
listTicketMacrosForConsole returns the canned responses a technician can apply from the composer, on “ticket:read” for the same reason the views list is.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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, PagedResultTicketMacroView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TicketMacroView | |
items[].addTags | array of string | |
items[].bodyrequired | string | |
items[].namerequired | string | |
items[].publicIdrequired | string | |
items[].setAssigneeId | string | |
items[].setPriority | string | |
items[].setStatus | 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/ticket-macros?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/ticket-macros?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/ticket-macros"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/ticket-macros?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/ticket-macros");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/ticket-macros?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/ticket-queues
Section titled “GET /api/v1/ticket-queues”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
List ticket queues for console
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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, PagedResultTicketQueueView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TicketQueueView | |
items[].namerequired | string | |
items[].openCountrequired | integer | |
items[].publicIdrequired | 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/ticket-queues?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/ticket-queues?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/ticket-queues"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/ticket-queues?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/ticket-queues");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/ticket-queues?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/ticket-views
Section titled “GET /api/v1/ticket-views”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
listTicketViewsForConsole returns the saved views this technician can use: their own plus the shared ones.
This is a “ticket:read” route and the CRUD that maintains views is not. A technician has no admin permission and still has to see their sidebar, so serving the list from the admin route would leave the sidebar empty for exactly the people who work the queue.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
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, PagedResultTicketSavedViewView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TicketSavedViewView | |
items[].countrequired | integer | |
items[].namerequired | string | |
items[].publicIdrequired | string | |
items[].queryrequired | object | |
items[].sharedrequired | boolean | |
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/ticket-views?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/ticket-views?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/ticket-views"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/ticket-views?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/ticket-views");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/ticket-views?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/tickets
Section titled “GET /api/v1/tickets”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
List tickets
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentId | query | string | No | |
assigneeId | query | string | No | |
breached | query | string | No | |
category | query | string | No | |
createdAfter | query | string | No | |
createdBefore | query | string | No | |
hostname | query | string | No | |
page | query | integer | No | One-based page number. Defaults to 1. |
pageSize | query | integer | No | Rows per page, 1 to 200. Defaults to 50. |
priority | query | string, one of critical, high, normal, urgent | No | Comma-separated set. An unrecognised value is refused. |
q | query | string | No | |
queueId | query | string | No | |
requesterId | query | string | No | |
sort | query | string | No | |
status | query | string | No | |
statusCategory | query | string | No | |
statusCategoryNot | query | string | No | |
subcategory | query | string | No | |
tag | query | string | No | |
viewId | query | string | No |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, PagedResultTicketSummaryView | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
404 | application/problem+json, ProblemDetails | Saved view not found. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TicketSummaryView | |
items[].agentId | string | |
items[].assigneeId | string | |
items[].assigneeName | string | |
items[].channelrequired | string | |
items[].createdAtrequired | string (date-time) | |
items[].hostname | string | |
items[].lastPublicReplyAt | string (date-time) or null | |
items[].messageCountrequired | integer | |
items[].numberrequired | integer | int64. |
items[].parentId | string | |
items[].priorityrequired | string | |
items[].publicIdrequired | string | |
items[].queueId | string | |
items[].queueName | string | |
items[].referencerequired | string | |
items[].requesterConfidencerequired | string | |
items[].requesterEmail | string | |
items[].requesterId | string | |
items[].requesterNamerequired | string | |
items[].siteName | string | |
items[].slaBreachedrequired | boolean | |
items[].slaNextEventAt | string (date-time) or null | |
items[].statusrequired | string | |
items[].statusCategoryrequired | string | |
items[].statusNamerequired | string | |
items[].subcategory | string | |
items[].subjectrequired | string | |
items[].tagsrequired | array of string | |
items[].typerequired | string | |
items[].unreadrequired | boolean | |
items[].updatedAtrequired | 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/tickets?agentId=<agentId>&assigneeId=<assigneeId>&breached=<breached>&category=<category>&createdAfter=<createdAfter>&createdBefore=<createdBefore>' \ -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/tickets?agentId=<agentId>&assigneeId=<assigneeId>&breached=<breached>&category=<category>&createdAfter=<createdAfter>&createdBefore=<createdBefore>' ` -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/tickets"params = { "agentId": "<agentId>", "assigneeId": "<assigneeId>", "breached": "<breached>", "category": "<category>", "createdAfter": "<createdAfter>", "createdBefore": "<createdBefore>",}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/tickets?agentId=<agentId>&assigneeId=<assigneeId>&breached=<breached>&category=<category>&createdAfter=<createdAfter>&createdBefore=<createdBefore>", 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/tickets");url.searchParams.set("agentId", "<agentId>");url.searchParams.set("assigneeId", "<assigneeId>");url.searchParams.set("breached", "<breached>");url.searchParams.set("category", "<category>");url.searchParams.set("createdAfter", "<createdAfter>");url.searchParams.set("createdBefore", "<createdBefore>");
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/tickets?agentId=<agentId>&assigneeId=<assigneeId>&breached=<breached>&category=<category>&createdAfter=<createdAfter>&createdBefore=<createdBefore>");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/tickets
Section titled “POST /api/v1/tickets”POSTticket:writetenant facehosteditmspremote
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
Create ticket
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
agentIdrequired | string | |
descriptionrequired | string | |
priorityrequired | string | |
queueIdrequired | string | |
requesterIdrequired | string | |
subcategoryrequired | string | |
subjectrequired | string | |
tagsrequired | array of string | |
typerequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
201 | application/json, TicketDetailView | Created. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches. |
409 | application/problem+json, ProblemDetails | The request conflicts with the current state. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
507 | application/problem+json, ProblemDetails | The storage profile for this client is over its configured quota. Raise the quota or remove attachments. |
201 response body
| Field | Type | Description |
|---|---|---|
agentId | string | |
assigneeId | string | |
assigneeName | string | |
channelrequired | string | |
childCountrequired | integer | |
contactAlertsrequired | array of ContactAlertView | |
contactAlerts[].colorrequired | string | |
contactAlerts[].descriptionrequired | string | |
contactAlerts[].displayNamerequired | string | |
contactAlerts[].labelrequired | string | |
contactAlerts[].namedUserIdrequired | string | |
contactAlerts[].tagCoderequired | string | |
createdAtrequired | string (date-time) | |
customFieldsrequired | object | |
descriptionrequired | string | |
hostname | string | |
lastPublicReplyAt | string (date-time) or null | |
linksrequired | array of TicketLinkView | |
links[].kindrequired | string | |
links[].otherPublicIdrequired | string | |
links[].otherReferencerequired | string | |
links[].otherStatusrequired | string | |
links[].otherStatusCategoryrequired | string | |
links[].otherSubjectrequired | string | |
links[].publicIdrequired | string | |
mergedIntoPublicId | string | |
messageCountrequired | integer | |
numberrequired | integer | int64. |
parent | TicketParentView | ticketParentView is the parent breadcrumb on a child's detail. |
parent.publicIdrequired | string | |
parent.referencerequired | string | |
parent.statusCategoryrequired | string | |
parent.subjectrequired | string | |
parentId | string | |
participantsrequired | array of TicketParticipantView | |
participants[].email | string | |
participants[].namerequired | string | |
participants[].rolerequired | string | |
participants[].userPublicId | string | |
priorityrequired | string | |
projectLinksrequired | array of TicketProjectLinkView | |
projectLinks[].kindrequired | string | |
projectLinks[].projectNamerequired | string | |
projectLinks[].projectPublicIdrequired | string | |
projectLinks[].projectReferencerequired | string | |
projectLinks[].publicIdrequired | string | |
projectLinks[].taskPublicId | string | |
publicIdrequired | string | |
queueId | string | |
queueName | string | |
referencerequired | string | |
requesterConfidencerequired | string | |
requesterEmail | string | |
requesterId | string | |
requesterNamerequired | string | |
siteName | string | |
slaBreachedrequired | boolean | |
slaNextEventAt | string (date-time) or null | |
slaReason | string | |
statusrequired | string | |
statusCategoryrequired | string | |
statusNamerequired | string | |
subcategory | string | |
subjectrequired | string | |
tagsrequired | array of string | |
typerequired | string | |
unreadrequired | boolean | |
updatedAtrequired | string (date-time) |
Request samples
Section titled “Request samples”# Sign in first. outpost_console is a session cookie, so send it with every request.curl -X POST 'https://depot.example.com/api/v1/tickets' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}'# Sign in first. outpost_console is a session cookie, so send it with every request.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/tickets' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$response | ConvertTo-Json -Depth 10# Sign in first. outpost_console is a session cookie, so send it with every request.
import requests
url = "https://depot.example.com/api/v1/tickets"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string", ], "type": "string",}
response = requests.post(url, headers=headers, cookies=cookies, json=payload, timeout=30)response.raise_for_status()print(response.json())// Sign in first. outpost_console is a session cookie, so send it with every request.package main
import ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/tickets", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/tickets";
const response = await fetch(url, { method: "POST", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string" }),});
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.
using System;using System.Net.Http;using System.Text;
using var client = new HttpClient();
const string body = """{ "agentId": "string", "description": "string", "priority": "string", "queueId": "string", "requesterId": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/tickets");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());GET /api/v1/tickets/{ticketID}
Section titled “GET /api/v1/tickets/{ticketID}”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
Get ticket
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TicketDetailView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | The request conflicts with the current state. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
507 | application/problem+json, ProblemDetails | The storage profile for this client is over its configured quota. Raise the quota or remove attachments. |
200 response body
| Field | Type | Description |
|---|---|---|
agentId | string | |
assigneeId | string | |
assigneeName | string | |
channelrequired | string | |
childCountrequired | integer | |
contactAlertsrequired | array of ContactAlertView | |
contactAlerts[].colorrequired | string | |
contactAlerts[].descriptionrequired | string | |
contactAlerts[].displayNamerequired | string | |
contactAlerts[].labelrequired | string | |
contactAlerts[].namedUserIdrequired | string | |
contactAlerts[].tagCoderequired | string | |
createdAtrequired | string (date-time) | |
customFieldsrequired | object | |
descriptionrequired | string | |
hostname | string | |
lastPublicReplyAt | string (date-time) or null | |
linksrequired | array of TicketLinkView | |
links[].kindrequired | string | |
links[].otherPublicIdrequired | string | |
links[].otherReferencerequired | string | |
links[].otherStatusrequired | string | |
links[].otherStatusCategoryrequired | string | |
links[].otherSubjectrequired | string | |
links[].publicIdrequired | string | |
mergedIntoPublicId | string | |
messageCountrequired | integer | |
numberrequired | integer | int64. |
parent | TicketParentView | ticketParentView is the parent breadcrumb on a child's detail. |
parent.publicIdrequired | string | |
parent.referencerequired | string | |
parent.statusCategoryrequired | string | |
parent.subjectrequired | string | |
parentId | string | |
participantsrequired | array of TicketParticipantView | |
participants[].email | string | |
participants[].namerequired | string | |
participants[].rolerequired | string | |
participants[].userPublicId | string | |
priorityrequired | string | |
projectLinksrequired | array of TicketProjectLinkView | |
projectLinks[].kindrequired | string | |
projectLinks[].projectNamerequired | string | |
projectLinks[].projectPublicIdrequired | string | |
projectLinks[].projectReferencerequired | string | |
projectLinks[].publicIdrequired | string | |
projectLinks[].taskPublicId | string | |
publicIdrequired | string | |
queueId | string | |
queueName | string | |
referencerequired | string | |
requesterConfidencerequired | string | |
requesterEmail | string | |
requesterId | string | |
requesterNamerequired | string | |
siteName | string | |
slaBreachedrequired | boolean | |
slaNextEventAt | string (date-time) or null | |
slaReason | string | |
statusrequired | string | |
statusCategoryrequired | string | |
statusNamerequired | string | |
subcategory | string | |
subjectrequired | string | |
tagsrequired | array of string | |
typerequired | string | |
unreadrequired | boolean | |
updatedAtrequired | string (date-time) |
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/tickets/<ticketID>' \ -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/tickets/<ticketID>' ` -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/tickets/<ticketID>"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/tickets/<ticketID>", 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/tickets/<ticketID>";
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/tickets/<ticketID>");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());PATCH /api/v1/tickets/{ticketID}
Section titled “PATCH /api/v1/tickets/{ticketID}”PATCHticket:writetenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
Patch ticket
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
assigneeId | string or null | |
priority | string or null | |
queueId | string or null | |
status | string or null | |
statusCategory | string or null | |
subcategory | string or null | |
subject | string or null | |
tagsrequired | array of string | |
type | string or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TicketDetailView | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Authentication is required. |
403 | application/problem+json, ProblemDetails | Changing who a ticket is assigned to requires the ticket:assign permission. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | The request conflicts with the current state. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
507 | application/problem+json, ProblemDetails | The storage profile for this client is over its configured quota. Raise the quota or remove attachments. |
200 response body
| Field | Type | Description |
|---|---|---|
agentId | string | |
assigneeId | string | |
assigneeName | string | |
channelrequired | string | |
childCountrequired | integer | |
contactAlertsrequired | array of ContactAlertView | |
contactAlerts[].colorrequired | string | |
contactAlerts[].descriptionrequired | string | |
contactAlerts[].displayNamerequired | string | |
contactAlerts[].labelrequired | string | |
contactAlerts[].namedUserIdrequired | string | |
contactAlerts[].tagCoderequired | string | |
createdAtrequired | string (date-time) | |
customFieldsrequired | object | |
descriptionrequired | string | |
hostname | string | |
lastPublicReplyAt | string (date-time) or null | |
linksrequired | array of TicketLinkView | |
links[].kindrequired | string | |
links[].otherPublicIdrequired | string | |
links[].otherReferencerequired | string | |
links[].otherStatusrequired | string | |
links[].otherStatusCategoryrequired | string | |
links[].otherSubjectrequired | string | |
links[].publicIdrequired | string | |
mergedIntoPublicId | string | |
messageCountrequired | integer | |
numberrequired | integer | int64. |
parent | TicketParentView | ticketParentView is the parent breadcrumb on a child's detail. |
parent.publicIdrequired | string | |
parent.referencerequired | string | |
parent.statusCategoryrequired | string | |
parent.subjectrequired | string | |
parentId | string | |
participantsrequired | array of TicketParticipantView | |
participants[].email | string | |
participants[].namerequired | string | |
participants[].rolerequired | string | |
participants[].userPublicId | string | |
priorityrequired | string | |
projectLinksrequired | array of TicketProjectLinkView | |
projectLinks[].kindrequired | string | |
projectLinks[].projectNamerequired | string | |
projectLinks[].projectPublicIdrequired | string | |
projectLinks[].projectReferencerequired | string | |
projectLinks[].publicIdrequired | string | |
projectLinks[].taskPublicId | string | |
publicIdrequired | string | |
queueId | string | |
queueName | string | |
referencerequired | string | |
requesterConfidencerequired | string | |
requesterEmail | string | |
requesterId | string | |
requesterNamerequired | string | |
siteName | string | |
slaBreachedrequired | boolean | |
slaNextEventAt | string (date-time) or null | |
slaReason | string | |
statusrequired | string | |
statusCategoryrequired | string | |
statusNamerequired | string | |
subcategory | string | |
subjectrequired | string | |
tagsrequired | array of string | |
typerequired | string | |
unreadrequired | boolean | |
updatedAtrequired | string (date-time) |
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 PATCH 'https://depot.example.com/api/v1/tickets/<ticketID>' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}'# 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' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}'@
$response = Invoke-RestMethod ` -Method Patch ` -Uri 'https://depot.example.com/api/v1/tickets/<ticketID>' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$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/tickets/<ticketID>"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string", ], "type": "string",}
response = requests.patch(url, headers=headers, cookies=cookies, json=payload, 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 ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}`)
req, err := http.NewRequest(http.MethodPatch, "https://depot.example.com/api/v1/tickets/<ticketID>", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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/tickets/<ticketID>";
const response = await fetch(url, { method: "PATCH", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string" }),});
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 System.Text;
using var client = new HttpClient();
const string body = """{ "assigneeId": "string", "priority": "string", "queueId": "string", "status": "string", "statusCategory": "string", "subcategory": "string", "subject": "string", "tags": [ "string" ], "type": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Patch, "https://depot.example.com/api/v1/tickets/<ticketID>");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());GET /api/v1/tickets/{ticketID}/activity
Section titled “GET /api/v1/tickets/{ticketID}/activity”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
listTicketActivity returns the ticket’s audit trail.
IT IS BACKED BY THE TICKET’S SYSTEM MESSAGES, which is what the schema has: a system message is a row in the conversation that describes something that happened TO the ticket (“assigned to Dana Reyes”, “merged into OUT-1042”), and the merge rules already treat them as the ticket’s own history by leaving them behind rather than moving them.
ponytail: the console’s TicketEvent carries field/from/to for a structured diff, and a system message has only prose, so those three are left absent and the console falls back to rendering the kind. The upgrade path is a “TicketActivity” table with Field/OldValue/NewValue columns written by the same code that writes the system message; do it when a writer actually has a field diff to record, not before, because a table nobody fills is worse than no table.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
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, PagedResultTicketEventView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket: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 TicketEventView | |
items[].actorNamerequired | string | |
items[].createdAtrequired | string (date-time) | |
items[].field | string | |
items[].from | string | |
items[].kindrequired | string | |
items[].publicIdrequired | string | |
items[].ruleName | string | |
items[].to | 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/tickets/<ticketID>/activity?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/tickets/<ticketID>/activity?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/tickets/<ticketID>/activity"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/tickets/<ticketID>/activity?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/tickets/<ticketID>/activity");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/tickets/<ticketID>/activity?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/tickets/{ticketID}/messages
Section titled “GET /api/v1/tickets/{ticketID}/messages”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
List ticket messages
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
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, PagedResultTicketMessageView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket: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 TicketMessageView | |
items[].attachmentsrequired | array of TicketAttachmentView | |
items[].attachments[].contentTyperequired | string | |
items[].attachments[].downloadUrlrequired | string | |
items[].attachments[].fileNamerequired | string | |
items[].attachments[].idrequired | string | |
items[].attachments[].sizeBytesrequired | integer | int64. |
items[].authorKindrequired | string | |
items[].authorNamerequired | string | |
items[].bodyrequired | string | |
items[].createdAtrequired | string (date-time) | |
items[].idrequired | 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/tickets/<ticketID>/messages?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/tickets/<ticketID>/messages?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/tickets/<ticketID>/messages"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/tickets/<ticketID>/messages?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/tickets/<ticketID>/messages");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/tickets/<ticketID>/messages?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/tickets/{ticketID}/messages
Section titled “POST /api/v1/tickets/{ticketID}/messages”POSTticket:writetenant facehosteditmspremote
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
Create ticket message
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
bodyrequired | string | |
internalrequired | boolean |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
201 | application/json, TicketMessageView | Created. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | That message cannot be saved as written: an internal note can never be queued for delivery. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
201 response body
| Field | Type | Description |
|---|---|---|
attachmentsrequired | array of TicketAttachmentView | |
attachments[].contentTyperequired | string | |
attachments[].downloadUrlrequired | string | |
attachments[].fileNamerequired | string | |
attachments[].idrequired | string | |
attachments[].sizeBytesrequired | integer | int64. |
authorKindrequired | string | |
authorNamerequired | string | |
bodyrequired | string | |
createdAtrequired | string (date-time) | |
idrequired | string |
Request samples
Section titled “Request samples”# Sign in first. outpost_console is a session cookie, so send it with every request.curl -X POST 'https://depot.example.com/api/v1/tickets/<ticketID>/messages' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "body": "string", "internal": false}'# Sign in first. outpost_console is a session cookie, so send it with every request.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "body": "string", "internal": false}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/tickets/<ticketID>/messages' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$response | ConvertTo-Json -Depth 10# Sign in first. outpost_console is a session cookie, so send it with every request.
import requests
url = "https://depot.example.com/api/v1/tickets/<ticketID>/messages"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "body": "string", "internal": False,}
response = requests.post(url, headers=headers, cookies=cookies, json=payload, timeout=30)response.raise_for_status()print(response.json())// Sign in first. outpost_console is a session cookie, so send it with every request.package main
import ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "body": "string", "internal": false}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/tickets/<ticketID>/messages", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/tickets/<ticketID>/messages";
const response = await fetch(url, { method: "POST", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "body": "string", "internal": false }),});
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.
using System;using System.Net.Http;using System.Text;
using var client = new HttpClient();
const string body = """{ "body": "string", "internal": false}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/tickets/<ticketID>/messages");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());POST /api/v1/tickets/{ticketID}/read
Section titled “POST /api/v1/tickets/{ticketID}/read”POSTticket:readtenant facehosteditmspremote
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
markTicketRead records how far the signed-in technician has read.
It notifies the tray, which the four automation hooks’ sites do not, because unread is what drives the tray’s badge and the count on its Tickets tab - the one number a user reads without opening anything.
ponytail: KNOWN, and stated here rather than discovered later: today this push is always suppressed by the hash, because trayTickets in grpcserver/ticket.go does not fill UserTicket.unread or unread_count yet, so the recomputed panel is byte-identical and nothing goes out. The read position this route writes is also the TECHNICIAN’s (TicketRead is per console user), not the requester’s, so filling the tray’s badge needs a requester-side read marker that does not exist yet. The call is here so that when either lands the badge moves on its own; it costs one recomputation of a panel that was going to be recomputed on the next reply anyway.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
lastMessageIdrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
204 | None | Success, with no body. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Authentication is required. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:read. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
Request samples
Section titled “Request samples”# Sign in first. outpost_console is a session cookie, so send it with every request.curl -X POST 'https://depot.example.com/api/v1/tickets/<ticketID>/read' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "lastMessageId": "string"}'# Sign in first. outpost_console is a session cookie, so send it with every request.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "lastMessageId": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/tickets/<ticketID>/read' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$response | ConvertTo-Json -Depth 10# Sign in first. outpost_console is a session cookie, so send it with every request.
import requests
url = "https://depot.example.com/api/v1/tickets/<ticketID>/read"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "lastMessageId": "string",}
response = requests.post(url, headers=headers, cookies=cookies, json=payload, timeout=30)response.raise_for_status()print(response.json())// Sign in first. outpost_console is a session cookie, so send it with every request.package main
import ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "lastMessageId": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/tickets/<ticketID>/read", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/tickets/<ticketID>/read";
const response = await fetch(url, { method: "POST", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "lastMessageId": "string" }),});
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.
using System;using System.Net.Http;using System.Text;
using var client = new HttpClient();
const string body = """{ "lastMessageId": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/tickets/<ticketID>/read");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());GET /api/v1/tickets/{ticketID}/time
Section titled “GET /api/v1/tickets/{ticketID}/time”GETticket:readtenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
List ticket time entries
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
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, PagedResultTicketTimeEntryView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket: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 TicketTimeEntryView | |
items[].amountCents | integer | int64. |
items[].billablerequired | boolean | |
items[].chargeTypeCode | string | |
items[].classifiedAt | string (date-time) or null | |
items[].invoicePublicId | string or null | |
items[].invoicedrequired | boolean | |
items[].locked | boolean | |
items[].messagePublicId | string | |
items[].minutesrequired | integer | |
items[].noterequired | string | |
items[].occurredAtrequired | string (date-time) | |
items[].outcome | string | |
items[].publicIdrequired | string | |
items[].rateCentsSnapshot | integer or null | int64. |
items[].technicianNamerequired | 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/tickets/<ticketID>/time?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/tickets/<ticketID>/time?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/tickets/<ticketID>/time"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/tickets/<ticketID>/time?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/tickets/<ticketID>/time");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/tickets/<ticketID>/time?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/tickets/{ticketID}/time
Section titled “POST /api/v1/tickets/{ticketID}/time”POSTticket:writetenant facehosteditmspremote
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
createTicketTimeEntry logs a technician’s worked minutes against a ticket.
NO TRAY NOTIFICATION FOR THE TIME ITSELF, DELIBERATELY; only a public note logged with it repaints the tray. Logged time is desk-internal billing material: it is not on UserTicket, it is not on any panel the tray renders, and it does not move the ticket’s status, priority or activity. A push would recompute a panel that is byte-identical, be suppressed by the hash, and have cost a read per timesheet entry. Add one here only if a time entry ever becomes something the user sees.
IT TAKES THE HOOKS FOR ONE FIELD. The cost-rate snapshot lives in the control database and this route mounts on every face, so the read goes through TicketHooks.CostRateFor, which main.go supplies in msp mode only. Everywhere else the entry is stored with a null snapshot, which is the honest answer for a deployment that has no cost rates.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
billablerequired | boolean | |
chargeTypeCoderequired | string | |
message | TimeEntryMessageRequest | |
message.bodyrequired | string | |
message.internal | boolean or null | |
minutesrequired | integer | |
noterequired | string | |
occurredAtrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
201 | application/json, TicketTimeEntryView | Created. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Logging time requires a signed-in technician. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
503 | application/problem+json, ProblemDetails | Could not check whether this week’s timesheet is approved. Nothing was changed; try again in a moment. |
201 response body
| Field | Type | Description |
|---|---|---|
amountCents | integer | int64. |
billablerequired | boolean | |
chargeTypeCode | string | |
classifiedAt | string (date-time) or null | |
invoicePublicId | string or null | |
invoicedrequired | boolean | |
locked | boolean | |
messagePublicId | string | |
minutesrequired | integer | |
noterequired | string | |
occurredAtrequired | string (date-time) | |
outcome | string | |
publicIdrequired | string | |
rateCentsSnapshot | integer or null | int64. |
technicianNamerequired | string |
Request samples
Section titled “Request samples”# Sign in first. outpost_console is a session cookie, so send it with every request.curl -X POST 'https://depot.example.com/api/v1/tickets/<ticketID>/time' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "billable": false, "chargeTypeCode": "string", "message": { "body": "string", "internal": false }, "minutes": 0, "note": "string", "occurredAt": "string"}'# Sign in first. outpost_console is a session cookie, so send it with every request.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "billable": false, "chargeTypeCode": "string", "message": { "body": "string", "internal": false }, "minutes": 0, "note": "string", "occurredAt": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/tickets/<ticketID>/time' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$response | ConvertTo-Json -Depth 10# Sign in first. outpost_console is a session cookie, so send it with every request.
import requests
url = "https://depot.example.com/api/v1/tickets/<ticketID>/time"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "billable": False, "chargeTypeCode": "string", "message": { "body": "string", "internal": False, }, "minutes": 0, "note": "string", "occurredAt": "string",}
response = requests.post(url, headers=headers, cookies=cookies, json=payload, timeout=30)response.raise_for_status()print(response.json())// Sign in first. outpost_console is a session cookie, so send it with every request.package main
import ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "billable": false, "chargeTypeCode": "string", "message": { "body": "string", "internal": false }, "minutes": 0, "note": "string", "occurredAt": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/tickets/<ticketID>/time", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/tickets/<ticketID>/time";
const response = await fetch(url, { method: "POST", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "billable": false, "chargeTypeCode": "string", "message": { "body": "string", "internal": false }, "minutes": 0, "note": "string", "occurredAt": "string" }),});
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.
using System;using System.Net.Http;using System.Text;
using var client = new HttpClient();
const string body = """{ "billable": false, "chargeTypeCode": "string", "message": { "body": "string", "internal": false }, "minutes": 0, "note": "string", "occurredAt": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/tickets/<ticketID>/time");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());PATCH /api/v1/tickets/{ticketID}/time/{entryID}
Section titled “PATCH /api/v1/tickets/{ticketID}/time/{entryID}”PATCHticket:writetenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
patchTicketTimeEntry corrects what a technician logged.
409 ONCE THE ENTRY IS INVOICED, and the check is the store’s under a row lock rather than a status read here: a check in the handler would race a concurrent finalize and let an edit land on work that had already been billed, which makes a sent invoice disagree with the database.
THE WIRE FIELDS ARE THE ONES THE POST AND THE GET ON THIS RESOURCE ALREADY USE: minutes and occurredAt, converted to seconds and StartedAt here exactly as createTicketTimeEntry converts them. One resource with three verbs that name the same value two different ways is a resource whose forms have to know which verb they are about to use, and the first person to get that wrong logs ninety seconds where they meant ninety minutes.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
entryID | path | string | Yes | A uuid. |
ticketID | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
billable | boolean or null | |
chargeTypeCode | string or null | |
minutes | integer or null | |
note | string or null | |
occurredAt | string or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TicketTimeEntryView | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | This time entry is on an invoice and can no longer be edited. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
503 | application/problem+json, ProblemDetails | Could not check whether this week’s timesheet is approved. Nothing was changed; try again in a moment. |
200 response body
| Field | Type | Description |
|---|---|---|
amountCents | integer | int64. |
billablerequired | boolean | |
chargeTypeCode | string | |
classifiedAt | string (date-time) or null | |
invoicePublicId | string or null | |
invoicedrequired | boolean | |
locked | boolean | |
messagePublicId | string | |
minutesrequired | integer | |
noterequired | string | |
occurredAtrequired | string (date-time) | |
outcome | string | |
publicIdrequired | string | |
rateCentsSnapshot | integer or null | int64. |
technicianNamerequired | 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 PATCH 'https://depot.example.com/api/v1/tickets/<ticketID>/time/<entryID>' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "billable": false, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string"}'# 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' 'Content-Type' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$body = @'{ "billable": false, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string"}'@
$response = Invoke-RestMethod ` -Method Patch ` -Uri 'https://depot.example.com/api/v1/tickets/<ticketID>/time/<entryID>' ` -Headers $headers ` -ContentType 'application/json' ` -Body $body
$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/tickets/<ticketID>/time/<entryID>"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "billable": False, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string",}
response = requests.patch(url, headers=headers, cookies=cookies, json=payload, 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 ( "bytes" "fmt" "io" "log" "net/http")
func main() { body := []byte(`{ "billable": false, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string"}`)
req, err := http.NewRequest(http.MethodPatch, "https://depot.example.com/api/v1/tickets/<ticketID>/time/<entryID>", bytes.NewReader(body)) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "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/tickets/<ticketID>/time/<entryID>";
const response = await fetch(url, { method: "PATCH", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "billable": false, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string" }),});
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 System.Text;
using var client = new HttpClient();
const string body = """{ "billable": false, "chargeTypeCode": "string", "minutes": 0, "note": "string", "occurredAt": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Patch, "https://depot.example.com/api/v1/tickets/<ticketID>/time/<entryID>");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");request.Content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());DELETE /api/v1/tickets/{ticketID}/time/{entryID}
Section titled “DELETE /api/v1/tickets/{ticketID}/time/{entryID}”DELETEticket:writetenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
deleteTicketTimeEntry removes one logged entry, under the same invoiced guard.
That guard is not new: DeleteTicketTimeEntry has refused an invoiced row since 0018_client.sql, at a time when nothing could set InvoicedAt. This route is what finally reaches it.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
entryID | path | string | Yes | A uuid. |
ticketID | path | string | Yes | A uuid. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
204 | None | Success, with no body. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | This time entry is on an invoice and can no longer be deleted. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
503 | application/problem+json, ProblemDetails | Could not check whether this week’s timesheet is approved. Nothing was changed; try again in a moment. |
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/tickets/<ticketID>/time/<entryID>' \ -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/tickets/<ticketID>/time/<entryID>' ` -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/tickets/<ticketID>/time/<entryID>"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/tickets/<ticketID>/time/<entryID>", 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/tickets/<ticketID>/time/<entryID>";
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/tickets/<ticketID>/time/<entryID>");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/tickets/{ticketID}/verify-sender
Section titled “POST /api/v1/tickets/{ticketID}/verify-sender”POSTticket:writetenant facehosteditmspremoteIdempotent
From an MSP console, prefix the path with /api/v1/clients/{clientID} to reach one client.
Source: [object Object]
verifyTicketSender confirms who sent an email ticket, so its replies are emailed.
Mail from a sender nothing vouches for (no allow rule, known contact, DMARC pass or trust-all) opens a ticket with an unverified requester and sends no email from it, to the requester or to anyone they copied, because its From may be forged (EMAIL_CONTRACTS.md R22). A technician who knows the person verifies them here. Only an email ticket qualifies: an endpoint’s unclaimed requester is resolved through the people merge queue instead. 409 when the ticket’s sender needs no verifying.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
ticketID | path | string | Yes | A uuid. |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TicketDetailView | Success. |
401 | application/problem+json, ProblemDetails | No signed-in identity. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | This ticket was merged into another; verify the sender there. |
500 | application/problem+json, ProblemDetails | No client store in request context. |
507 | application/problem+json, ProblemDetails | The storage profile for this client is over its configured quota. Raise the quota or remove attachments. |
200 response body
| Field | Type | Description |
|---|---|---|
agentId | string | |
assigneeId | string | |
assigneeName | string | |
channelrequired | string | |
childCountrequired | integer | |
contactAlertsrequired | array of ContactAlertView | |
contactAlerts[].colorrequired | string | |
contactAlerts[].descriptionrequired | string | |
contactAlerts[].displayNamerequired | string | |
contactAlerts[].labelrequired | string | |
contactAlerts[].namedUserIdrequired | string | |
contactAlerts[].tagCoderequired | string | |
createdAtrequired | string (date-time) | |
customFieldsrequired | object | |
descriptionrequired | string | |
hostname | string | |
lastPublicReplyAt | string (date-time) or null | |
linksrequired | array of TicketLinkView | |
links[].kindrequired | string | |
links[].otherPublicIdrequired | string | |
links[].otherReferencerequired | string | |
links[].otherStatusrequired | string | |
links[].otherStatusCategoryrequired | string | |
links[].otherSubjectrequired | string | |
links[].publicIdrequired | string | |
mergedIntoPublicId | string | |
messageCountrequired | integer | |
numberrequired | integer | int64. |
parent | TicketParentView | ticketParentView is the parent breadcrumb on a child's detail. |
parent.publicIdrequired | string | |
parent.referencerequired | string | |
parent.statusCategoryrequired | string | |
parent.subjectrequired | string | |
parentId | string | |
participantsrequired | array of TicketParticipantView | |
participants[].email | string | |
participants[].namerequired | string | |
participants[].rolerequired | string | |
participants[].userPublicId | string | |
priorityrequired | string | |
projectLinksrequired | array of TicketProjectLinkView | |
projectLinks[].kindrequired | string | |
projectLinks[].projectNamerequired | string | |
projectLinks[].projectPublicIdrequired | string | |
projectLinks[].projectReferencerequired | string | |
projectLinks[].publicIdrequired | string | |
projectLinks[].taskPublicId | string | |
publicIdrequired | string | |
queueId | string | |
queueName | string | |
referencerequired | string | |
requesterConfidencerequired | string | |
requesterEmail | string | |
requesterId | string | |
requesterNamerequired | string | |
siteName | string | |
slaBreachedrequired | boolean | |
slaNextEventAt | string (date-time) or null | |
slaReason | string | |
statusrequired | string | |
statusCategoryrequired | string | |
statusNamerequired | string | |
subcategory | string | |
subjectrequired | string | |
tagsrequired | array of string | |
typerequired | string | |
unreadrequired | boolean | |
updatedAtrequired | string (date-time) |
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/tickets/<ticketID>/verify-sender' \ -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/tickets/<ticketID>/verify-sender' ` -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/tickets/<ticketID>/verify-sender"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/tickets/<ticketID>/verify-sender", 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/tickets/<ticketID>/verify-sender";
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/tickets/<ticketID>/verify-sender");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.