Change a member's seat class
curl --request POST \
--url https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "seat-class-changes",
"attributes": {
"seat_class": "field",
"email": "pat.jones@example.com"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes"
payload = { "data": {
"type": "seat-class-changes",
"attributes": {
"seat_class": "field",
"email": "pat.jones@example.com"
},
"relationships": { "organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
} } }
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'seat-class-changes',
attributes: {seat_class: 'field', email: 'pat.jones@example.com'},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'organisations'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes",
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([
'data' => [
'type' => 'seat-class-changes',
'attributes' => [
'seat_class' => 'field',
'email' => 'pat.jones@example.com'
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'organisations'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$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 := "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"type": "users",
"attributes": {
"email": "john.doe@example.com",
"profile": {
"work": {
"occupation": "Site Manager",
"cscs": "CSC123456",
"eusr": "EUR789123",
"start_date": "2020-03-01T00:00:00.000Z"
},
"personal": {
"first_name": "John",
"last_name": "Doe",
"dob": "1985-06-15T00:00:00.000Z",
"username": "johndoe"
},
"contact": {
"mobile": "+44 7700 900123",
"landline": "+44 20 7946 0958"
},
"address": {
"name": "Tech Tower",
"number": "42",
"street": "High Street",
"area": "Westminster",
"town": "London",
"county": "Greater London",
"postcode": "SW1A 1AA",
"country_code": "GB",
"what3words": "filled.count.soap"
},
"settings": {
"preferred_language": "en-GB",
"timezone": "Europe/London"
}
},
"status": "active",
"seat_class": "full",
"memberships": [
{
"organisation": "2f1e5a4c-8b7d-4c3e-9a1f-6d5b4c3a2e10",
"status": "active",
"seat_class": "record",
"external_reference": "GR-0042"
}
],
"password_set_at": "2026-09-25T10:15:00.000Z",
"mfa_enabled_at": "2026-10-06T09:30:00.000Z",
"identities": [
{
"id": "39ce13b8-1116-416a-ad5f-3c5edfd44f53",
"platform": "multi_tenant",
"meta": {}
}
]
},
"meta": {
"managed_type": "none",
"withheld_organisations": [
"c000c344-8847-47da-a091-32e75902d3b1"
],
"reach": "direct"
},
"relationships": {
"organisations": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"managing_organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
}
}
},
"jsonapi": {
"version": "1.0"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations",
"attributes": {
"name": "Acme Construction Ltd",
"slug": "acme-construction",
"sandbox": false,
"description": "Leading construction company specializing in infrastructure projects",
"settings": {
"teams": {
"customer_representatives": [
"b234c567-8901-2345-6789-abcdef012345"
]
},
"security": {
"require_mfa": false
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-01-15T10:30:00.000Z",
"updated_at": "2023-02-20T14:45:00.000Z",
"features": [
{
"name": "advanced_reporting",
"enabled": true,
"limit": 1000
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "service-accounts"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "groups"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "nomenclature"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"errors": [
{
"id": "1b3f2c30-2d56-4d3a-9c44-9be9c2cbf2f0",
"status": "403",
"title": "Forbidden",
"detail": "You do not hold the grant required for this action.",
"code": "AUTH.002"
}
]
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Users
Change a seat class
Change a member’s seat class in the organisation the body names. The caller needs permission to update users across that organisation. Only an active or inactive member’s class can be changed. A caller cannot change their own class, and is refused with 403.
- Between
fieldandfull, only the class changes. - From
recordtofieldorfull, a member who has never had a login gets one, and is sent the setup email that leads them to set a password. That needs an email: sendemail, or the member’s stored email is used. Without either the request is refused with 400. An email another user holds is refused with 409. - To
record, the member loses access to the organisation within about a minute. A member whose every active membership isrecordcan no longer sign in to anything.
Each change is recorded in the member’s history and the audit log. The
response is the member, carrying the new class in memberships.
POST
/
v3
/
users
/
{user_id}
/
seat-class-changes
Change a member's seat class
curl --request POST \
--url https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "seat-class-changes",
"attributes": {
"seat_class": "field",
"email": "pat.jones@example.com"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes"
payload = { "data": {
"type": "seat-class-changes",
"attributes": {
"seat_class": "field",
"email": "pat.jones@example.com"
},
"relationships": { "organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
} } }
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: 'seat-class-changes',
attributes: {seat_class: 'field', email: 'pat.jones@example.com'},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: 'organisations'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes",
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([
'data' => [
'type' => 'seat-class-changes',
'attributes' => [
'seat_class' => 'field',
'email' => 'pat.jones@example.com'
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => 'organisations'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$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 := "https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/users/{user_id}/seat-class-changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"seat-class-changes\",\n \"attributes\": {\n \"seat_class\": \"field\",\n \"email\": \"pat.jones@example.com\"\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"organisations\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"type": "users",
"attributes": {
"email": "john.doe@example.com",
"profile": {
"work": {
"occupation": "Site Manager",
"cscs": "CSC123456",
"eusr": "EUR789123",
"start_date": "2020-03-01T00:00:00.000Z"
},
"personal": {
"first_name": "John",
"last_name": "Doe",
"dob": "1985-06-15T00:00:00.000Z",
"username": "johndoe"
},
"contact": {
"mobile": "+44 7700 900123",
"landline": "+44 20 7946 0958"
},
"address": {
"name": "Tech Tower",
"number": "42",
"street": "High Street",
"area": "Westminster",
"town": "London",
"county": "Greater London",
"postcode": "SW1A 1AA",
"country_code": "GB",
"what3words": "filled.count.soap"
},
"settings": {
"preferred_language": "en-GB",
"timezone": "Europe/London"
}
},
"status": "active",
"seat_class": "full",
"memberships": [
{
"organisation": "2f1e5a4c-8b7d-4c3e-9a1f-6d5b4c3a2e10",
"status": "active",
"seat_class": "record",
"external_reference": "GR-0042"
}
],
"password_set_at": "2026-09-25T10:15:00.000Z",
"mfa_enabled_at": "2026-10-06T09:30:00.000Z",
"identities": [
{
"id": "39ce13b8-1116-416a-ad5f-3c5edfd44f53",
"platform": "multi_tenant",
"meta": {}
}
]
},
"meta": {
"managed_type": "none",
"withheld_organisations": [
"c000c344-8847-47da-a091-32e75902d3b1"
],
"reach": "direct"
},
"relationships": {
"organisations": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"managing_organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations"
}
}
}
},
"jsonapi": {
"version": "1.0"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "organisations",
"attributes": {
"name": "Acme Construction Ltd",
"slug": "acme-construction",
"sandbox": false,
"description": "Leading construction company specializing in infrastructure projects",
"settings": {
"teams": {
"customer_representatives": [
"b234c567-8901-2345-6789-abcdef012345"
]
},
"security": {
"require_mfa": false
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-01-15T10:30:00.000Z",
"updated_at": "2023-02-20T14:45:00.000Z",
"features": [
{
"name": "advanced_reporting",
"enabled": true,
"limit": 1000
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "users"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "service-accounts"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "groups"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "teams"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "nomenclature"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"errors": [
{
"id": "1b3f2c30-2d56-4d3a-9c44-9be9c2cbf2f0",
"status": "403",
"title": "Forbidden",
"detail": "You do not hold the grant required for this action.",
"code": "AUTH.002"
}
]
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Authorizations
SessionOAuth2Cookie
Session token for authentication.
Path Parameters
The unique identifier for the user.
Body
application/vnd.api+json
The seat class to move the member to, and the organisation it applies in.
Show child attributes
Show child attributes