Depot timesheets
Registers the timesheet routes.
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/timesheets/approvals
Section titled “GET /api/v1/timesheets/approvals”GETtimesheet:approvemsp facemspIdempotent
Source: [object Object]
listApprovals is the approver’s queue: submitted sheets waiting (all weeks, or one with weekStart), or, with state=unsubmitted, every live operator holding ticket:write whose sheet for weekStart (default last week) is still draft or returned.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
state | query | string | No | |
weekStart | query | string | No |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetApprovalsView | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold timesheet:approve. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TimesheetApprovalItem | |
items[].billableMinutesrequired | integer | |
items[].leaveMinutesrequired | integer | |
items[].staterequired | string | |
items[].submittedAt | string (date-time) or null | |
items[].targetMinutesrequired | integer | |
items[].totalMinutesrequired | integer | |
items[].userIdrequired | string | |
items[].userNamerequired | string | |
items[].weekStartrequired | string | |
totalClientsrequired | integer | |
unavailableClientsrequired | array of 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 GET 'https://depot.example.com/api/v1/timesheets/approvals?state=<state>&weekStart=<weekStart>' \ -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/timesheets/approvals?state=<state>&weekStart=<weekStart>' ` -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/timesheets/approvals"params = { "state": "<state>", "weekStart": "<weekStart>",}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/timesheets/approvals?state=<state>&weekStart=<weekStart>", 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/timesheets/approvals");url.searchParams.set("state", "<state>");url.searchParams.set("weekStart", "<weekStart>");
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/timesheets/approvals?state=<state>&weekStart=<weekStart>");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/timesheets/categories
Section titled “GET /api/v1/timesheets/categories”GETmsp facemspIdempotent
Source: [object Object]
listCategories lists the time categories, live ones only unless includeArchived is true.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
includeArchived | query | string | No |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, ItemsEnvelopeTimeCategoryView | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TimeCategoryView | |
items[].archivedrequired | boolean | |
items[].idrequired | string | |
items[].kindrequired | string | |
items[].namerequired | string | |
items[].sortOrderrequired | 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/timesheets/categories?includeArchived=<includeArchived>' \ -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/timesheets/categories?includeArchived=<includeArchived>' ` -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/timesheets/categories"params = { "includeArchived": "<includeArchived>",}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/timesheets/categories?includeArchived=<includeArchived>", 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/timesheets/categories");url.searchParams.set("includeArchived", "<includeArchived>");
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/timesheets/categories?includeArchived=<includeArchived>");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/timesheets/categories
Section titled “POST /api/v1/timesheets/categories”POSTpsa:adminmsp facemsp
Source: [object Object]
createCategory adds a time category.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
archived | boolean or null | |
kind | string or null | |
name | string or null | |
sortOrder | integer or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
201 | application/json, TimeCategoryView | 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 psa:admin. |
404 | application/problem+json, ProblemDetails | No resource matches. |
409 | application/problem+json, ProblemDetails | A time category with that name already exists. |
500 | application/problem+json, ProblemDetails | Could not save the time category. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
201 response body
| Field | Type | Description |
|---|---|---|
archivedrequired | boolean | |
idrequired | string | |
kindrequired | string | |
namerequired | string | |
sortOrderrequired | integer |
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/timesheets/categories' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}'# 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 = @'{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/categories' ` -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/timesheets/categories"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "archived": False, "kind": "string", "name": "string", "sortOrder": 0,}
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(`{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/categories", 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/timesheets/categories";
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({ "archived": false, "kind": "string", "name": "string", "sortOrder": 0 }),});
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 = """{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/categories");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/timesheets/categories/{categoryId}
Section titled “PATCH /api/v1/timesheets/categories/{categoryId}”PATCHpsa:adminmsp facemspIdempotent
Source: [object Object]
patchCategory renames, re-kinds, reorders, archives or restores a category.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
categoryId | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
archived | boolean or null | |
kind | string or null | |
name | string or null | |
sortOrder | integer or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimeCategoryView | 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 psa:admin. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | A time category with that name already exists. |
500 | application/problem+json, ProblemDetails | Could not save the time category. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
archivedrequired | boolean | |
idrequired | string | |
kindrequired | string | |
namerequired | string | |
sortOrderrequired | 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 PATCH 'https://depot.example.com/api/v1/timesheets/categories/<categoryId>' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}'# 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 = @'{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}'@
$response = Invoke-RestMethod ` -Method Patch ` -Uri 'https://depot.example.com/api/v1/timesheets/categories/<categoryId>' ` -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/timesheets/categories/<categoryId>"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "archived": False, "kind": "string", "name": "string", "sortOrder": 0,}
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(`{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}`)
req, err := http.NewRequest(http.MethodPatch, "https://depot.example.com/api/v1/timesheets/categories/<categoryId>", 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/timesheets/categories/<categoryId>";
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({ "archived": false, "kind": "string", "name": "string", "sortOrder": 0 }),});
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 = """{ "archived": false, "kind": "string", "name": "string", "sortOrder": 0}""";
var request = new HttpRequestMessage(HttpMethod.Patch, "https://depot.example.com/api/v1/timesheets/categories/<categoryId>");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/timesheets/entries
Section titled “POST /api/v1/timesheets/entries”POSTmsp facemsp
Source: [object Object]
createEntry logs time against a category (PTO, admin, training and the like) on one local date, for the caller or, as an approver, for someone else.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
categoryId | string or null | |
date | string or null | |
minutes | integer or null | |
note | string or null | |
userId | string or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
201 | application/json, TimesheetEntryResult | Created. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | You can only work on your own timesheet. |
404 | application/problem+json, ProblemDetails | Time category not found. |
409 | application/problem+json, ProblemDetails | Logged time is between one minute and 24 hours. |
500 | application/problem+json, ProblemDetails | The time could not be saved. Nothing was logged; try again in a moment. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
201 response body
| Field | Type | Description |
|---|---|---|
billablerequired | boolean | |
categoryIdrequired | string | |
daterequired | string | |
idrequired | string | |
invoicedrequired | boolean | |
minutesrequired | integer | |
noterequired | string | |
startedAt | string (date-time) or null |
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/timesheets/entries' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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 = @'{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/entries' ` -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/timesheets/entries"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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(`{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/entries", 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/timesheets/entries";
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({ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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 = """{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/entries");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/timesheets/entries/{entryId}
Section titled “PATCH /api/v1/timesheets/entries/{entryId}”PATCHmsp facemspIdempotent
Source: [object Object]
patchEntry corrects category time.
Moving it to another date checks the lock on both weeks.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
entryId | path | string | Yes | A uuid. |
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
categoryId | string or null | |
date | string or null | |
minutes | integer or null | |
note | string or null | |
userId | string or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetEntryResult | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | You can only work on your own timesheet. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
409 | application/problem+json, ProblemDetails | Logged time is between one minute and 24 hours. |
500 | application/problem+json, ProblemDetails | Could not read the time entry. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
billablerequired | boolean | |
categoryIdrequired | string | |
daterequired | string | |
idrequired | string | |
invoicedrequired | boolean | |
minutesrequired | integer | |
noterequired | string | |
startedAt | string (date-time) or null |
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/timesheets/entries/<entryId>' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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 = @'{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}'@
$response = Invoke-RestMethod ` -Method Patch ` -Uri 'https://depot.example.com/api/v1/timesheets/entries/<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/timesheets/entries/<entryId>"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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(`{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}`)
req, err := http.NewRequest(http.MethodPatch, "https://depot.example.com/api/v1/timesheets/entries/<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/timesheets/entries/<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({ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "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 = """{ "categoryId": "string", "date": "string", "minutes": 0, "note": "string", "userId": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Patch, "https://depot.example.com/api/v1/timesheets/entries/<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/timesheets/entries/{entryId}
Section titled “DELETE /api/v1/timesheets/entries/{entryId}”DELETEmsp facemspIdempotent
Source: [object Object]
deleteEntry removes category time, unless its week is approved.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
entryId | 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 | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | You can only work on your own timesheet. |
404 | application/problem+json, ProblemDetails | No resource matches that id. |
500 | application/problem+json, ProblemDetails | Could not read the time entry. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
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/timesheets/entries/<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/timesheets/entries/<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/timesheets/entries/<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/timesheets/entries/<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/timesheets/entries/<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/timesheets/entries/<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());GET /api/v1/timesheets/targets
Section titled “GET /api/v1/timesheets/targets”GETpsa:adminmsp facemspIdempotent
Source: [object Object]
listTargets lists every live operator’s expected minutes per weekday.
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, ItemsEnvelopeDailyTargetView | 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 psa:admin. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
itemsrequired | array of DailyTargetView | |
items[].dailyTargetMinutesrequired | integer | |
items[].userIdrequired | string | |
items[].userNamerequired | 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 GET 'https://depot.example.com/api/v1/timesheets/targets' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -b 'outpost_console=<console-session>'# Sign in first. outpost_console is a session cookie, so send it with every request.# This operation is idempotent. Repeating it does not repeat its effect.
$headers = @{ 'X-CSRF-Token' = '<csrf-token>' 'Accept' = 'application/json' 'Cookie' = 'outpost_console=<console-session>'}
$response = Invoke-RestMethod ` -Method Get ` -Uri 'https://depot.example.com/api/v1/timesheets/targets' ` -Headers $headers
$response | ConvertTo-Json -Depth 10# Sign in first. outpost_console is a session cookie, so send it with every request.# This operation is idempotent. Repeating it does not repeat its effect.
import requests
url = "https://depot.example.com/api/v1/timesheets/targets"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json",}cookies = { "outpost_console": "<console-session>",}
response = requests.get(url, headers=headers, cookies=cookies, timeout=30)response.raise_for_status()print(response.json())// Sign in first. outpost_console is a session cookie, so send it with every request.// This operation is idempotent. Repeating it does not repeat its effect.package main
import ( "fmt" "io" "log" "net/http")
func main() { req, err := http.NewRequest(http.MethodGet, "https://depot.example.com/api/v1/timesheets/targets", nil) if err != nil { log.Fatal(err) }
req.Header.Set("X-CSRF-Token", "<csrf-token>") req.Header.Set("Accept", "application/json") req.AddCookie(&http.Cookie{Name: "outpost_console", Value: "<console-session>"})
resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()
out, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(resp.Status, string(out))}// Sign in first. outpost_console is a session cookie, so send it with every request.// This operation is idempotent. Repeating it does not repeat its effect.// The session cookie is set by signing in. A script cannot set it itself.
const url = "https://depot.example.com/api/v1/timesheets/targets";
const response = await fetch(url, { method: "GET", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", }, credentials: "include",});
if (!response.ok) { throw new Error(`Request failed with status ${response.status}`);}
const data = await response.json();console.log(data);// Sign in first. outpost_console is a session cookie, so send it with every request.// This operation is idempotent. Repeating it does not repeat its effect.
using System;using System.Net.Http;
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://depot.example.com/api/v1/timesheets/targets");request.Headers.TryAddWithoutValidation("X-CSRF-Token", "<csrf-token>");request.Headers.TryAddWithoutValidation("Accept", "application/json");request.Headers.TryAddWithoutValidation("Cookie", "outpost_console=<console-session>");
var response = await client.SendAsync(request);response.EnsureSuccessStatusCode();Console.WriteLine(await response.Content.ReadAsStringAsync());PUT /api/v1/timesheets/targets
Section titled “PUT /api/v1/timesheets/targets”PUTpsa:adminmsp facemspIdempotent
Source: [object Object]
putTarget sets one operator’s expected minutes per weekday, Monday to Friday.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
dailyTargetMinutes | integer or null | |
userIdrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, DailyTargetView | 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 psa:admin. |
404 | application/problem+json, ProblemDetails | Operator not found. |
409 | application/problem+json, ProblemDetails | A daily target is 0 to 1440 minutes. |
500 | application/problem+json, ProblemDetails | Could not save the daily target. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
dailyTargetMinutesrequired | integer | |
userIdrequired | string | |
userNamerequired | 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 PUT 'https://depot.example.com/api/v1/timesheets/targets' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "dailyTargetMinutes": 0, "userId": "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 = @'{ "dailyTargetMinutes": 0, "userId": "string"}'@
$response = Invoke-RestMethod ` -Method Put ` -Uri 'https://depot.example.com/api/v1/timesheets/targets' ` -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/timesheets/targets"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "dailyTargetMinutes": 0, "userId": "string",}
response = requests.put(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(`{ "dailyTargetMinutes": 0, "userId": "string"}`)
req, err := http.NewRequest(http.MethodPut, "https://depot.example.com/api/v1/timesheets/targets", 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/timesheets/targets";
const response = await fetch(url, { method: "PUT", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "dailyTargetMinutes": 0, "userId": "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 = """{ "dailyTargetMinutes": 0, "userId": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Put, "https://depot.example.com/api/v1/timesheets/targets");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/timesheets/timer
Section titled “GET /api/v1/timesheets/timer”GETmsp facemspIdempotent
Source: [object Object]
getTimer answers the caller’s running timer, or null.
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TechTimerEnvelope | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
timer | TechTimerView | |
timer.categoryId | string or null | |
timer.clientId | string or null | |
timer.kindrequired | string | |
timer.labelrequired | string | |
timer.noterequired | string | |
timer.startedAtrequired | string (date-time) | |
timer.taskId | string or null | |
timer.ticketId | string or null | |
timer.warning | string or null |
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/timesheets/timer' \ -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/timesheets/timer' ` -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/timesheets/timer"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/timesheets/timer", 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/timesheets/timer";
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/timesheets/timer");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());PUT /api/v1/timesheets/timer
Section titled “PUT /api/v1/timesheets/timer”PUTticket:writemsp facemspIdempotent
Source: [object Object]
startTimer starts the caller’s one timer on a ticket, a task or a category.
The server sets the label and the start; a second start answers 409 timer_running with the timer that is already going.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
categoryIdrequired | string | |
clientIdrequired | string | |
kindrequired | string | |
noterequired | string | |
taskIdrequired | string | |
ticketIdrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TechTimerEnvelope | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | Client not found. |
500 | application/problem+json, ProblemDetails | Could not read the ticket. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
timer | TechTimerView | |
timer.categoryId | string or null | |
timer.clientId | string or null | |
timer.kindrequired | string | |
timer.labelrequired | string | |
timer.noterequired | string | |
timer.startedAtrequired | string (date-time) | |
timer.taskId | string or null | |
timer.ticketId | string or null | |
timer.warning | string or null |
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 PUT 'https://depot.example.com/api/v1/timesheets/timer' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "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 = @'{ "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "string"}'@
$response = Invoke-RestMethod ` -Method Put ` -Uri 'https://depot.example.com/api/v1/timesheets/timer' ` -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/timesheets/timer"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "string",}
response = requests.put(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(`{ "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "string"}`)
req, err := http.NewRequest(http.MethodPut, "https://depot.example.com/api/v1/timesheets/timer", 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/timesheets/timer";
const response = await fetch(url, { method: "PUT", headers: { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json", }, credentials: "include", body: JSON.stringify({ "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "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 = """{ "categoryId": "string", "clientId": "string", "kind": "string", "note": "string", "taskId": "string", "ticketId": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Put, "https://depot.example.com/api/v1/timesheets/timer");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/timesheets/timer
Section titled “DELETE /api/v1/timesheets/timer”DELETEticket:writemsp facemspIdempotent
Source: [object Object]
discardTimer removes the caller’s timer without logging anything.
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TechTimerEnvelope | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
timer | TechTimerView | |
timer.categoryId | string or null | |
timer.clientId | string or null | |
timer.kindrequired | string | |
timer.labelrequired | string | |
timer.noterequired | string | |
timer.startedAtrequired | string (date-time) | |
timer.taskId | string or null | |
timer.ticketId | string or null | |
timer.warning | string or null |
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/timesheets/timer' \ -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/timesheets/timer' ` -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/timesheets/timer"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/timesheets/timer", 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/timesheets/timer";
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/timesheets/timer");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/timesheets/timer/stop
Section titled “POST /api/v1/timesheets/timer/stop”POSTticket:writemsp facemspIdempotent
Source: [object Object]
stopTimer logs the running timer as time on its subject, through the same write the ticket, task and category routes use, and only then removes it.
Minutes default to the elapsed time, rounded, at least one.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
billable | boolean or null | |
minutes | integer or null | |
note | string or null |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TechTimerEnvelope | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
404 | application/problem+json, ProblemDetails | No timer is running. |
409 | application/problem+json, ProblemDetails | Logged time is between one minute and 24 hours. |
500 | application/problem+json, ProblemDetails | Could not read the ticket. |
503 | application/problem+json, ProblemDetails | Timesheets live in this practice’s own client database, which is not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
timer | TechTimerView | |
timer.categoryId | string or null | |
timer.clientId | string or null | |
timer.kindrequired | string | |
timer.labelrequired | string | |
timer.noterequired | string | |
timer.startedAtrequired | string (date-time) | |
timer.taskId | string or null | |
timer.ticketId | string or null | |
timer.warning | string or null |
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/timesheets/timer/stop' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "billable": false, "minutes": 0, "note": "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, "minutes": 0, "note": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/timer/stop' ` -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/timesheets/timer/stop"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "billable": False, "minutes": 0, "note": "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.// 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, "minutes": 0, "note": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/timer/stop", 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/timesheets/timer/stop";
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, "minutes": 0, "note": "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, "minutes": 0, "note": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/timer/stop");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/timesheets/week
Section titled “GET /api/v1/timesheets/week”GETmsp facemspIdempotent
Source: [object Object]
getWeek is one technician’s week across every client: ticket, task and category time by day, the sheet’s state and the week’s totals.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
userId | query | string | No | |
weekStart | query | string | No |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetWeekView | Success. |
400 | application/problem+json, ProblemDetails | One or more validation errors occurred. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | You can only work on your own timesheet. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
daysrequired | array of TimesheetDayView | |
days[].daterequired | string | |
days[].leaveMinutesrequired | integer | |
days[].targetMinutesrequired | integer | |
days[].timeOff | string or null | |
days[].totalMinutesrequired | integer | |
days[].workMinutesrequired | integer | |
returnNoterequired | string | |
reviewedAt | string (date-time) or null | |
reviewedByName | string or null | |
rowsrequired | array of TimesheetRowView | |
rows[].billableMinutesrequired | integer | |
rows[].categoryId | string or null | |
rows[].categoryKind | string or null | |
rows[].clientId | string or null | |
rows[].clientName | string or null | |
rows[].entriesrequired | array of TimesheetEntryView | |
rows[].entries[].billablerequired | boolean | |
rows[].entries[].daterequired | string | |
rows[].entries[].idrequired | string | |
rows[].entries[].invoicedrequired | boolean | |
rows[].entries[].minutesrequired | integer | |
rows[].entries[].noterequired | string | |
rows[].entries[].startedAt | string (date-time) or null | |
rows[].keyrequired | string | |
rows[].kindrequired | string | |
rows[].labelrequired | string | |
rows[].minutesByDayrequired | array of integer | |
rows[].projectId | string or null | |
rows[].taskId | string or null | |
rows[].ticketId | string or null | |
rows[].totalMinutesrequired | integer | |
staterequired | string | |
submittedAt | string (date-time) or null | |
timeZonerequired | string | |
totalClientsrequired | integer | |
totalsrequired | TimesheetTotalsView | |
totals.billableMinutesrequired | integer | |
totals.leaveMinutesrequired | integer | |
totals.targetMinutesrequired | integer | |
totals.totalMinutesrequired | integer | |
unavailableClientsrequired | array of string | |
userIdrequired | string | |
userNamerequired | string | |
userStartedOnrequired | string | |
weekStartrequired | 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 GET 'https://depot.example.com/api/v1/timesheets/week?userId=<userId>&weekStart=<weekStart>' \ -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/timesheets/week?userId=<userId>&weekStart=<weekStart>' ` -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/timesheets/week"params = { "userId": "<userId>", "weekStart": "<weekStart>",}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/timesheets/week?userId=<userId>&weekStart=<weekStart>", 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/timesheets/week");url.searchParams.set("userId", "<userId>");url.searchParams.set("weekStart", "<weekStart>");
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/timesheets/week?userId=<userId>&weekStart=<weekStart>");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/timesheets/week/approve
Section titled “POST /api/v1/timesheets/week/approve”POSTtimesheet:approvemsp facemsp
Source: [object Object]
approveWeeks approves submitted weeks, each on its own.
An item whose live total is not the totalMinutes the approver saw fails with timesheet_changed, so nobody signs off on hours they did not look at.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TimesheetWeekRequest | |
items[].reasonrequired | string | |
items[].totalMinutes | integer or null | |
items[].userIdrequired | string | |
items[].weekStartrequired | string | |
noterequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetBulkResponse | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold timesheet:approve. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
resultsrequired | array of TimesheetBulkResult | |
results[].error | string | |
results[].okrequired | boolean | |
results[].userIdrequired | string | |
results[].weekStartrequired | 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/timesheets/week/approve' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "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 = @'{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/week/approve' ` -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/timesheets/week/approve"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string", }, ], "note": "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(`{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/week/approve", 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/timesheets/week/approve";
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({ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "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 = """{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/week/approve");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/timesheets/week/recall
Section titled “POST /api/v1/timesheets/week/recall”POSTticket:writemsp facemsp
Source: [object Object]
recallWeek takes the caller’s submitted week back to draft.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
reasonrequired | string | |
totalMinutes | integer or null | |
userIdrequired | string | |
weekStartrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetWeekView | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
daysrequired | array of TimesheetDayView | |
days[].daterequired | string | |
days[].leaveMinutesrequired | integer | |
days[].targetMinutesrequired | integer | |
days[].timeOff | string or null | |
days[].totalMinutesrequired | integer | |
days[].workMinutesrequired | integer | |
returnNoterequired | string | |
reviewedAt | string (date-time) or null | |
reviewedByName | string or null | |
rowsrequired | array of TimesheetRowView | |
rows[].billableMinutesrequired | integer | |
rows[].categoryId | string or null | |
rows[].categoryKind | string or null | |
rows[].clientId | string or null | |
rows[].clientName | string or null | |
rows[].entriesrequired | array of TimesheetEntryView | |
rows[].entries[].billablerequired | boolean | |
rows[].entries[].daterequired | string | |
rows[].entries[].idrequired | string | |
rows[].entries[].invoicedrequired | boolean | |
rows[].entries[].minutesrequired | integer | |
rows[].entries[].noterequired | string | |
rows[].entries[].startedAt | string (date-time) or null | |
rows[].keyrequired | string | |
rows[].kindrequired | string | |
rows[].labelrequired | string | |
rows[].minutesByDayrequired | array of integer | |
rows[].projectId | string or null | |
rows[].taskId | string or null | |
rows[].ticketId | string or null | |
rows[].totalMinutesrequired | integer | |
staterequired | string | |
submittedAt | string (date-time) or null | |
timeZonerequired | string | |
totalClientsrequired | integer | |
totalsrequired | TimesheetTotalsView | |
totals.billableMinutesrequired | integer | |
totals.leaveMinutesrequired | integer | |
totals.targetMinutesrequired | integer | |
totals.totalMinutesrequired | integer | |
unavailableClientsrequired | array of string | |
userIdrequired | string | |
userNamerequired | string | |
userStartedOnrequired | string | |
weekStartrequired | 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/timesheets/week/recall' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = @'{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/week/recall' ` -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/timesheets/week/recall"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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(`{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/week/recall", 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/timesheets/week/recall";
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({ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = """{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/week/recall");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/timesheets/week/reopen
Section titled “POST /api/v1/timesheets/week/reopen”POSTtimesheet:approvemsp facemsp
Source: [object Object]
reopenWeek takes an approved week back to returned, with the reason, which unlocks its time.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
reasonrequired | string | |
totalMinutes | integer or null | |
userIdrequired | string | |
weekStartrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetWeekView | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold timesheet:approve. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
daysrequired | array of TimesheetDayView | |
days[].daterequired | string | |
days[].leaveMinutesrequired | integer | |
days[].targetMinutesrequired | integer | |
days[].timeOff | string or null | |
days[].totalMinutesrequired | integer | |
days[].workMinutesrequired | integer | |
returnNoterequired | string | |
reviewedAt | string (date-time) or null | |
reviewedByName | string or null | |
rowsrequired | array of TimesheetRowView | |
rows[].billableMinutesrequired | integer | |
rows[].categoryId | string or null | |
rows[].categoryKind | string or null | |
rows[].clientId | string or null | |
rows[].clientName | string or null | |
rows[].entriesrequired | array of TimesheetEntryView | |
rows[].entries[].billablerequired | boolean | |
rows[].entries[].daterequired | string | |
rows[].entries[].idrequired | string | |
rows[].entries[].invoicedrequired | boolean | |
rows[].entries[].minutesrequired | integer | |
rows[].entries[].noterequired | string | |
rows[].entries[].startedAt | string (date-time) or null | |
rows[].keyrequired | string | |
rows[].kindrequired | string | |
rows[].labelrequired | string | |
rows[].minutesByDayrequired | array of integer | |
rows[].projectId | string or null | |
rows[].taskId | string or null | |
rows[].ticketId | string or null | |
rows[].totalMinutesrequired | integer | |
staterequired | string | |
submittedAt | string (date-time) or null | |
timeZonerequired | string | |
totalClientsrequired | integer | |
totalsrequired | TimesheetTotalsView | |
totals.billableMinutesrequired | integer | |
totals.leaveMinutesrequired | integer | |
totals.targetMinutesrequired | integer | |
totals.totalMinutesrequired | integer | |
unavailableClientsrequired | array of string | |
userIdrequired | string | |
userNamerequired | string | |
userStartedOnrequired | string | |
weekStartrequired | 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/timesheets/week/reopen' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = @'{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/week/reopen' ` -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/timesheets/week/reopen"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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(`{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/week/reopen", 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/timesheets/week/reopen";
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({ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = """{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/week/reopen");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/timesheets/week/return
Section titled “POST /api/v1/timesheets/week/return”POSTtimesheet:approvemsp facemsp
Source: [object Object]
returnWeeks sends submitted weeks back to their technicians with a note, each on its own.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
itemsrequired | array of TimesheetWeekRequest | |
items[].reasonrequired | string | |
items[].totalMinutes | integer or null | |
items[].userIdrequired | string | |
items[].weekStartrequired | string | |
noterequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetBulkResponse | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold timesheet:approve. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
resultsrequired | array of TimesheetBulkResult | |
results[].error | string | |
results[].okrequired | boolean | |
results[].userIdrequired | string | |
results[].weekStartrequired | 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/timesheets/week/return' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "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 = @'{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/week/return' ` -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/timesheets/week/return"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string", }, ], "note": "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(`{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/week/return", 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/timesheets/week/return";
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({ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "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 = """{ "items": [ { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string" } ], "note": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/week/return");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/timesheets/week/submit
Section titled “POST /api/v1/timesheets/week/submit”POSTticket:writemsp facemsp
Source: [object Object]
submitWeek sends the caller’s week for approval (draft or returned to submitted).
A week that has not started cannot be submitted.
Request body
Section titled “Request body”Required, sent as application/json.
| Field | Type | Description |
|---|---|---|
reasonrequired | string | |
totalMinutes | integer or null | |
userIdrequired | string | |
weekStartrequired | string |
Responses
Section titled “Responses”| Status | Body | Description |
|---|---|---|
200 | application/json, TimesheetWeekView | Success. |
400 | application/problem+json, ProblemDetails | The request body is not valid JSON. |
401 | application/problem+json, ProblemDetails | Timesheets require a signed-in operator. |
403 | application/problem+json, ProblemDetails | The identity does not hold ticket:write. |
500 | application/problem+json, ProblemDetails | The request failed. |
503 | application/problem+json, ProblemDetails | Timesheets are not available on this server. |
200 response body
| Field | Type | Description |
|---|---|---|
daysrequired | array of TimesheetDayView | |
days[].daterequired | string | |
days[].leaveMinutesrequired | integer | |
days[].targetMinutesrequired | integer | |
days[].timeOff | string or null | |
days[].totalMinutesrequired | integer | |
days[].workMinutesrequired | integer | |
returnNoterequired | string | |
reviewedAt | string (date-time) or null | |
reviewedByName | string or null | |
rowsrequired | array of TimesheetRowView | |
rows[].billableMinutesrequired | integer | |
rows[].categoryId | string or null | |
rows[].categoryKind | string or null | |
rows[].clientId | string or null | |
rows[].clientName | string or null | |
rows[].entriesrequired | array of TimesheetEntryView | |
rows[].entries[].billablerequired | boolean | |
rows[].entries[].daterequired | string | |
rows[].entries[].idrequired | string | |
rows[].entries[].invoicedrequired | boolean | |
rows[].entries[].minutesrequired | integer | |
rows[].entries[].noterequired | string | |
rows[].entries[].startedAt | string (date-time) or null | |
rows[].keyrequired | string | |
rows[].kindrequired | string | |
rows[].labelrequired | string | |
rows[].minutesByDayrequired | array of integer | |
rows[].projectId | string or null | |
rows[].taskId | string or null | |
rows[].ticketId | string or null | |
rows[].totalMinutesrequired | integer | |
staterequired | string | |
submittedAt | string (date-time) or null | |
timeZonerequired | string | |
totalClientsrequired | integer | |
totalsrequired | TimesheetTotalsView | |
totals.billableMinutesrequired | integer | |
totals.leaveMinutesrequired | integer | |
totals.targetMinutesrequired | integer | |
totals.totalMinutesrequired | integer | |
unavailableClientsrequired | array of string | |
userIdrequired | string | |
userNamerequired | string | |
userStartedOnrequired | string | |
weekStartrequired | 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/timesheets/week/submit' \ -H 'X-CSRF-Token: <csrf-token>' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -b 'outpost_console=<console-session>' \ --data '{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = @'{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}'@
$response = Invoke-RestMethod ` -Method Post ` -Uri 'https://depot.example.com/api/v1/timesheets/week/submit' ` -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/timesheets/week/submit"headers = { "X-CSRF-Token": "<csrf-token>", "Accept": "application/json", "Content-Type": "application/json",}cookies = { "outpost_console": "<console-session>",}payload = { "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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(`{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}`)
req, err := http.NewRequest(http.MethodPost, "https://depot.example.com/api/v1/timesheets/week/submit", 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/timesheets/week/submit";
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({ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "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 = """{ "reason": "string", "totalMinutes": 0, "userId": "string", "weekStart": "string"}""";
var request = new HttpRequestMessage(HttpMethod.Post, "https://depot.example.com/api/v1/timesheets/week/submit");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());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.