curl --request GET \
--url http://localhost:3000/api/shifts \
--cookie __Host-argus-session=import requests
url = "http://localhost:3000/api/shifts"
headers = {"cookie": "__Host-argus-session="}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {cookie: '__Host-argus-session='}};
fetch('http://localhost:3000/api/shifts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "3000",
CURLOPT_URL => "http://localhost:3000/api/shifts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_COOKIE => "__Host-argus-session=",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "http://localhost:3000/api/shifts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("cookie", "__Host-argus-session=")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("http://localhost:3000/api/shifts")
.header("cookie", "__Host-argus-session=")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/api/shifts")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request["cookie"] = '__Host-argus-session='
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "cmg5y3shf0006l508shf00001",
"staffId": "cmg5x1k2a0001l5089f8e7d6c",
"type": "MODERATION",
"source": "MANUAL",
"startedAt": "2026-10-06T19:30:00.000Z",
"endedAt": null,
"status": "ACTIVE",
"durationSeconds": 730
}
],
"meta": {
"limit": 25,
"offset": 0,
"hasMore": false
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Request validation failed.",
"details": [
{
"path": [
"staffId"
],
"message": "Invalid input"
}
]
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "Sign in to continue."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "FORBIDDEN",
"message": "Permission required: shifts.view."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "The request could not be completed."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}List shifts
Permission: Active staff may read their own shifts. Reading anyone else’s, or calling without an active staff profile, needs shifts.view.
Access: Browser session, or a service credential holding the permission as a scope.
Shifts, newest first. Without shifts.view the result is always limited to the caller’s own profile.
Unknown query parameters are rejected with 400.
curl --request GET \
--url http://localhost:3000/api/shifts \
--cookie __Host-argus-session=import requests
url = "http://localhost:3000/api/shifts"
headers = {"cookie": "__Host-argus-session="}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {cookie: '__Host-argus-session='}};
fetch('http://localhost:3000/api/shifts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "3000",
CURLOPT_URL => "http://localhost:3000/api/shifts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_COOKIE => "__Host-argus-session=",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "http://localhost:3000/api/shifts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("cookie", "__Host-argus-session=")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("http://localhost:3000/api/shifts")
.header("cookie", "__Host-argus-session=")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/api/shifts")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request["cookie"] = '__Host-argus-session='
response = http.request(request)
puts response.read_body{
"data": [
{
"id": "cmg5y3shf0006l508shf00001",
"staffId": "cmg5x1k2a0001l5089f8e7d6c",
"type": "MODERATION",
"source": "MANUAL",
"startedAt": "2026-10-06T19:30:00.000Z",
"endedAt": null,
"status": "ACTIVE",
"durationSeconds": 730
}
],
"meta": {
"limit": 25,
"offset": 0,
"hasMore": false
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Request validation failed.",
"details": [
{
"path": [
"staffId"
],
"message": "Invalid input"
}
]
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "Sign in to continue."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "FORBIDDEN",
"message": "Permission required: shifts.view."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "The request could not be completed."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}Authorizations
The opaque session cookie set by Discord sign-in. Named argus-session outside production. HttpOnly, so scripts cannot read it; same-origin requests send it automatically. Requests other than GET must also carry an Origin header equal to the application's own origin.
Query Parameters
Staff profile to read. Needs shifts.view unless it is the caller's own.
Argus record identifier.
1 - 64^[a-zA-Z0-9_-]+$Only running or only ended shifts.
ACTIVE, ENDED Page size.
1 <= x <= 100Number of items to skip.
0 <= x <= 10000