Create or update staff membership
curl --request POST \
--url http://localhost:3000/api/staff \
--header 'Content-Type: application/json' \
--cookie __Host-argus-session= \
--data '
{
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"roleIds": [
"cmg5x0aaa0003l508role0001"
]
}
'import requests
url = "http://localhost:3000/api/staff"
payload = {
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"roleIds": ["cmg5x0aaa0003l508role0001"]
}
headers = {
"cookie": "__Host-argus-session=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: '__Host-argus-session=', 'Content-Type': 'application/json'},
body: JSON.stringify({userId: 'cmg5x1k2a0000l508a1b2c3d4', roleIds: ['cmg5x0aaa0003l508role0001']})
};
fetch('http://localhost:3000/api/staff', 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/staff",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'userId' => 'cmg5x1k2a0000l508a1b2c3d4',
'roleIds' => [
'cmg5x0aaa0003l508role0001'
]
]),
CURLOPT_COOKIE => "__Host-argus-session=",
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:3000/api/staff"
payload := strings.NewReader("{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("cookie", "__Host-argus-session=")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:3000/api/staff")
.header("cookie", "__Host-argus-session=")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/api/staff")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["cookie"] = '__Host-argus-session='
request["Content-Type"] = 'application/json'
request.body = "{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "cmg5x1k2a0001l5089f8e7d6c",
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"active": true,
"createdAt": "2026-10-06T19:30:00.000Z",
"updatedAt": "2026-10-06T19:30:00.000Z"
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Request validation failed.",
"details": [
{
"path": [
"userId"
],
"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: admin.manage."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "SELF_CHANGE",
"message": "Administrators cannot change their own staff membership."
},
"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"
}Staff
Create or update staff membership
Permission: admin.manage.
Access: Browser session only.
Creates the user’s staff profile if needed, sets whether it is active, and replaces its roles with roleIds, all in one transaction. Audited as staff.membership.changed.
Administrators cannot change their own membership.
POST
/
staff
Create or update staff membership
curl --request POST \
--url http://localhost:3000/api/staff \
--header 'Content-Type: application/json' \
--cookie __Host-argus-session= \
--data '
{
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"roleIds": [
"cmg5x0aaa0003l508role0001"
]
}
'import requests
url = "http://localhost:3000/api/staff"
payload = {
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"roleIds": ["cmg5x0aaa0003l508role0001"]
}
headers = {
"cookie": "__Host-argus-session=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: '__Host-argus-session=', 'Content-Type': 'application/json'},
body: JSON.stringify({userId: 'cmg5x1k2a0000l508a1b2c3d4', roleIds: ['cmg5x0aaa0003l508role0001']})
};
fetch('http://localhost:3000/api/staff', 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/staff",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'userId' => 'cmg5x1k2a0000l508a1b2c3d4',
'roleIds' => [
'cmg5x0aaa0003l508role0001'
]
]),
CURLOPT_COOKIE => "__Host-argus-session=",
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:3000/api/staff"
payload := strings.NewReader("{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("cookie", "__Host-argus-session=")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:3000/api/staff")
.header("cookie", "__Host-argus-session=")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:3000/api/staff")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["cookie"] = '__Host-argus-session='
request["Content-Type"] = 'application/json'
request.body = "{\n \"userId\": \"cmg5x1k2a0000l508a1b2c3d4\",\n \"roleIds\": [\n \"cmg5x0aaa0003l508role0001\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "cmg5x1k2a0001l5089f8e7d6c",
"userId": "cmg5x1k2a0000l508a1b2c3d4",
"active": true,
"createdAt": "2026-10-06T19:30:00.000Z",
"updatedAt": "2026-10-06T19:30:00.000Z"
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Request validation failed.",
"details": [
{
"path": [
"userId"
],
"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: admin.manage."
},
"requestId": "3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70"
}{
"error": {
"code": "SELF_CHANGE",
"message": "Administrators cannot change their own staff membership."
},
"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.
Body
application/json
Response
Success.
Show child attributes
Show child attributes