Reference
Utility endpoints for health checks, batching, reference data, and platform status.
General
GET /ping
Health check
User keyExample request
curl -X GET "https://api.openstudio.one/v1/ping" \
-H "X-Api-User-Key: YOUR_USER_KEY"<?php
$ch = curl_init('https://api.openstudio.one/v1/ping');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
response = requests.get("https://api.openstudio.one/v1/ping", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/ping', {
method: 'GET',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY'
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to ping. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| message | string | — | Always the literal string "pong" — confirms the API is reachable and your key(s) authenticated successfully. |
| brand_id | integer | — | Your tenant's brand_id, resolved from whichever key(s) you sent — a quick way to confirm you're authenticated as the account you expect. |
| user_id | integer | Resolved from your X-Api-User-Key, if you sent one. |
Example response
{
"success": true,
"data": {
"message": "pong",
"brand_id": 42,
"user_id": 7
},
"error": null
}POST /batch
Bundle up to 20 sub-requests into one HTTP call
User keyRequest body
| Field | Type | Flags | Required | Notes |
|---|---|---|---|---|
| requests | array of objects | — | Required | At most 20 items. Each is dispatched exactly as if you'd called it directly — same auth, same rate-limit accounting, same everything — just combined into one round trip for you. |
| ↳id | string | — | Optional | Your own label for matching a response back to its request. Defaults to the item's position in the array (as a string) if omitted. |
| ↳method | string | — | Optional | The HTTP method for this sub-request.GETPOSTPUTPATCHDELETE |
| ↳url | string | — | Optional | Path relative to /v1, e.g. /tickets/123 or /tickets/123/replies. Cannot itself be /batch — no nesting. |
| ↳body | object | — | Optional | Only used for POST/PUT/PATCH. Same shape as that endpoint's own documented request body. |
| ↳idempotency_key | string | — | Optional | Forwarded as this ONE sub-request's own Idempotency-Key header — retrying the same batch with the same keys makes each write-endpoint sub-request safe to repeat, exactly like sending that header on a direct call. Only has an effect on endpoints that already support it (currently POST /tickets and POST /tickets/{id}/replies) — harmless, silently ignored on any other endpoint. Each sub-request needs its own key; there's no single idempotency key for the batch call as a whole. |
Example request
curl -X POST "https://api.openstudio.one/v1/batch" \
-H "X-Api-User-Key: YOUR_USER_KEY" \
-H "Content-Type: application/json" \
-d '{"requests":[{"id":"...","method":"...","url":"...","body":{},"idempotency_key":"..."}]}'<?php
$ch = curl_init('https://api.openstudio.one/v1/batch');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'requests' => [
'0' => [
'id' => '...',
'method' => '...',
'url' => '...',
'body' => [
],
'idempotency_key' => '...',
],
],
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
body = {
'requests': [
{
'id': '...',
'method': '...',
'url': '...',
'body': {
},
'idempotency_key': '...',
},
],
}
response = requests.post("https://api.openstudio.one/v1/batch", headers=headers, json=body)
data = response.json()fetch('https://api.openstudio.one/v1/batch', {
method: 'POST',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
'requests': [
{
'id': '...',
'method': '...',
'url': '...',
'body': {
},
'idempotency_key': '...',
},
],
})
})
.then(res => res.json())
.then(data => console.log(data));Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| responses | array of objects | — | Same order as your requests array (not completion order, even though sub-requests run in parallel). One failed sub-request does not affect the others — check each one's own status/body. |
| ↳id | string | — | Echoes that sub-request's id (or its array position, if you didn't supply one). |
| ↳status | integer | — | That sub-request's own HTTP status code — exactly what you'd have gotten calling it directly. 502 specifically means the sub-request itself couldn't be completed (a transport-level failure), not that the target endpoint returned 502. |
| ↳body | object | — | That sub-request's own full response envelope (success/data/error) — identical to what a direct call to that endpoint would return. |
Example response
{
"success": true,
"data": {
"responses": [
{
"id": "1",
"status": 200,
"body": {
"success": true,
"data": {
"id": 123,
"status": 1
},
"error": null
}
},
{
"id": "2",
"status": 404,
"body": {
"success": false,
"data": null,
"error": {
"code": "not_found",
"message": "Ticket not found."
}
}
}
]
},
"error": null
}Locale & Static Reference Data
GET /reference/timezones
List every valid timezone value
No key requiredExample request
curl -X GET "https://api.openstudio.one/v1/reference/timezones"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/timezones');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/timezones", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/timezones', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/timezones. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| timezones | array of objects | — | Every valid timezone value, grouped by region. |
| ↳group_name | string | — | Region grouping, e.g. "Europe". |
| ↳label | string | — | Human-readable city/zone name, e.g. "Amsterdam". |
| ↳value | string | — | The IANA timezone value to send, e.g. "Europe/Amsterdam". |
Example response
{
"success": true,
"data": {
"timezones": [
{
"group_name": "Europe",
"label": "Amsterdam",
"value": "Europe/Amsterdam"
},
{
"group_name": "Europe",
"label": "London",
"value": "Europe/London"
}
]
},
"error": null
}GET /reference/countries
List every country, for a geo cascade picker
No key requiredExample request
curl -X GET "https://api.openstudio.one/v1/reference/countries"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/countries');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/countries", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/countries', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/countries. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| countries | array of objects | — | — |
| ↳id | integer | — | — |
| ↳name | string | — | — |
Example response
{
"success": true,
"data": {
"countries": [
{
"id": 1,
"name": "Italy"
},
{
"id": 2,
"name": "France"
}
]
},
"error": null
}GET /reference/states
List a country's states/provinces, for a geo cascade picker
No key requiredQuery parameters (1)
Other
| Parameter | Type | Required | Notes |
|---|---|---|---|
| ?country_id | integer | Optional | A GET /reference/countries' own id. Required. |
Example request
curl -X GET "https://api.openstudio.one/v1/reference/states?country_id=123"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/states?country_id=123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/states?country_id=123", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/states?country_id=123', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/states. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| states | array of objects | — | — |
| ↳id | integer | — | — |
| ↳name | string | — | — |
Example response
{
"success": true,
"data": {
"states": [
{
"id": 10,
"name": "Lazio"
},
{
"id": 11,
"name": "Lombardy"
}
]
},
"error": null
}GET /reference/cities
List a state's cities, for a geo cascade picker
No key requiredQuery parameters (1)
Other
| Parameter | Type | Required | Notes |
|---|---|---|---|
| ?state_id | integer | Optional | A GET /reference/states' own id. Required. |
Example request
curl -X GET "https://api.openstudio.one/v1/reference/cities?state_id=123"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/cities?state_id=123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/cities?state_id=123", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/cities?state_id=123', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/cities. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| cities | array of objects | — | — |
| ↳id | integer | — | — |
| ↳name | string | — | — |
Example response
{
"success": true,
"data": {
"cities": [
{
"id": 100,
"name": "Rome"
},
{
"id": 101,
"name": "Milan"
}
]
},
"error": null
}GET /reference/nationalities
List every valid nationality/citizenship value
No key requiredExample request
curl -X GET "https://api.openstudio.one/v1/reference/nationalities"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/nationalities');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/nationalities", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/nationalities', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/nationalities. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| nationalities | array of objects | — | — |
| ↳id | integer | — | — |
| ↳name | string | — | — |
Example response
{
"success": true,
"data": {
"nationalities": [
{
"id": 1,
"name": "Italian"
},
{
"id": 2,
"name": "French"
}
]
},
"error": null
}GET /reference/languages
List every valid language value
No key requiredQuery parameters (1)
Other
| Parameter | Type | Required | Notes |
|---|---|---|---|
| ?all | boolean | Optional | Include every locale the platform has (even partially-translated/legacy ones not offered anywhere in the product). Defaults to false — only languages the dashboard's own language switcher actually offers. |
Example request
curl -X GET "https://api.openstudio.one/v1/reference/languages?all=true"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/languages?all=true');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, []);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
}
response = requests.get("https://api.openstudio.one/v1/reference/languages?all=true", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/languages?all=true', {
method: 'GET',
headers: {
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/languages. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| languages | array of objects | — | Each item has lang, language, native_name. Limited to languages actually offered in the product (matches the dashboard's own language switcher) — not every locale the platform has ever had partial translations for. |
| ↳lang | string | — | Short code, e.g. "en", "it". This is the value consumers like PATCH /tenant/settings's default_language field expect. |
| ↳language | string | — | English name of the language, e.g. "Italian". |
| ↳native_name | string | — | Language name in its own script, e.g. "Italiano", "日本語". |
Example response
{
"success": true,
"data": {
"languages": [
{
"lang": "en",
"language": "English",
"native_name": "English"
},
{
"lang": "it",
"language": "Italian",
"native_name": "Italiano"
}
]
},
"error": null
}Infrastructure & Platform
GET /alerts
Active system status alerts
User keyExample request
curl -X GET "https://api.openstudio.one/v1/alerts" \
-H "X-Api-User-Key: YOUR_USER_KEY"<?php
$ch = curl_init('https://api.openstudio.one/v1/alerts');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
response = requests.get("https://api.openstudio.one/v1/alerts", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/alerts', {
method: 'GET',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY'
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to alerts. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| alerts | array of objects | — | Active system-wide status/maintenance alerts, most recent first. |
| ↳id | integer | — | This alert's own id. |
| ↳type | string | — | How prominently this alert should be shown.infowarningcriticalmaintenance |
| ↳title | string | — | Short headline. |
| ↳message | string | — | The full alert text. |
| ↳impact_scope | string | — | e.g. "global" or "minor" — see the web status page for the full set of values. |
| ↳color | string | — | A suggested UI color keyword (e.g. "danger", "warning", "info") — same mapping the web dashboard's own widgets use for this type. |
| ↳icon | string | — | A suggested icon identifier (Font Awesome class name, e.g. "fa-exclamation-triangle") — the mobile app maps this to its own icon set rather than rendering it directly. |
| ↳created_at | string | — | UTC timestamp (YYYY-MM-DD HH:MM:SS). |
Example response
{
"success": true,
"data": {
"alerts": [
{
"id": 12,
"type": "maintenance",
"title": "Scheduled maintenance",
"message": "Brief downtime expected around 02:00 UTC.",
"impact_scope": "global",
"color": "primary",
"icon": "fa-tools",
"created_at": "2026-08-23 01:00:00"
}
]
},
"error": null
}GET /service-status
Full platform status page
User keyExample request
curl -X GET "https://api.openstudio.one/v1/service-status" \
-H "X-Api-User-Key: YOUR_USER_KEY"<?php
$ch = curl_init('https://api.openstudio.one/v1/service-status');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
response = requests.get("https://api.openstudio.one/v1/service-status", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/service-status', {
method: 'GET',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY'
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to service-status. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| overall_status | string | — | The single worst GLOBAL-impact incident currently visible to this caller — a minor (non-global) incident never escalates this.operationalmaintenancedegradedoutage |
| checked_at | string | — | UTC timestamp (YYYY-MM-DD HH:MM:SS) this response was generated at. |
| groups | array of objects | — | Always all 6 fixed groups, even when empty (an empty incidents array means that group is fully operational). |
| ↳key | string | — | Which part of the platform this status group covers.administrationdatacloudsbenefitssupportother |
| ↳title | string | — | Display title for this status group. |
| ↳icon | string | — | A suggested Font Awesome icon name (no "fa-" prefix), e.g. "cogs". |
| ↳status | string | — | "notice" only ever comes from a non-global (minor) incident with nothing more severe already present in the same group.operationalnoticemaintenancewarningcritical |
| ↳color | string | — | A suggested UI color keyword, same mapping as GET /alerts's own color field. |
| ↳incidents | array of objects | — | Open incidents/maintenance windows currently affecting this group, if any. |
| ↳id | integer | — | This incident's own id. |
| ↳app_name | string | — | The linked app's translated name, or "System Infrastructure" for an incident with no linked app. |
| ↳title | string | — | Short headline. |
| ↳message | string | — | The full incident text. |
| ↳type | string | — | How prominently this incident should be shown.infowarningcriticalmaintenance |
| ↳color | string | — | A hex color for a status indicator, matching this incident's own severity. |
| ↳icon | string | — | An icon name for a status indicator, matching this incident's own severity. |
| ↳impact_scope | string | — | e.g. "global" or "minor". |
| ↳created_at | string | — | UTC timestamp (YYYY-MM-DD HH:MM:SS). |
| ↳history | array of objects | — | Timeline updates, newest first. |
| ↳status_label | string | — | Human-readable status for this group as a whole (e.g. Operational, Degraded). |
| ↳message | string | — | A one-line summary of this group's current status. |
| ↳created_at | string | — | UTC timestamp (YYYY-MM-DD HH:MM:SS). |
Example response
{
"success": true,
"data": {
"overall_status": "maintenance",
"checked_at": "2026-08-26 13:40:00",
"groups": [
{
"key": "administration",
"title": "Administration",
"icon": "cogs",
"status": "maintenance",
"color": "primary",
"incidents": [
{
"id": 12,
"app_name": "Admin Console",
"title": "Scheduled maintenance",
"message": "Brief downtime expected around 02:00 UTC.",
"type": "maintenance",
"color": "primary",
"icon": "fa-tools",
"impact_scope": "global",
"created_at": "2026-08-26 01:00:00",
"history": []
}
]
},
{
"key": "data",
"title": "Data & Storage",
"icon": "database",
"status": "operational",
"color": "success",
"incidents": []
}
]
},
"error": null
}POST /reference/translations
Get this tenant's translated UI copy for one language
User keyRequest body
| Field | Type | Flags | Required | Notes |
|---|---|---|---|---|
| lang | string | — | Optional | ISO language code, e.g. "en", "it" -- see GET /reference/languages for the valid set. Defaults to "en". |
Example request
curl -X POST "https://api.openstudio.one/v1/reference/translations" \
-H "X-Api-User-Key: YOUR_USER_KEY" \
-H "Content-Type: application/json" \
-d '{"lang":"..."}'<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/translations');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'lang' => '...',
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY', 'Content-Type: application/json']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
body = {
'lang': '...',
}
response = requests.post("https://api.openstudio.one/v1/reference/translations", headers=headers, json=body)
data = response.json()fetch('https://api.openstudio.one/v1/reference/translations', {
method: 'POST',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
'lang': '...',
})
})
.then(res => res.json())
.then(data => console.log(data));Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| lang | string | — | The language actually returned (after sanitization) -- echoes back lang, or "en" if it was omitted/invalid. |
| strings | object | — | variable -> content dictionary. Most values are strings; a few are objects (multi-value translations) -- see this endpoint's own description. |
Example response
{
"success": true,
"data": {
"lang": "it",
"strings": {
"dashboard": "Pannello di controllo",
"logout": "Esci",
"save": "Salva"
}
},
"error": null
}User Categories
GET /reference/categories
List categories of USERS for queue-routing rules (not app/ticket categories)
User keyExample request
curl -X GET "https://api.openstudio.one/v1/reference/categories" \
-H "X-Api-User-Key: YOUR_USER_KEY"<?php
$ch = curl_init('https://api.openstudio.one/v1/reference/categories');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-User-Key: YOUR_USER_KEY']);
$response = curl_exec($ch);
$data = json_decode($response, true);import requests
headers = {
"X-Api-User-Key": "YOUR_USER_KEY",
}
response = requests.get("https://api.openstudio.one/v1/reference/categories", headers=headers)
data = response.json()fetch('https://api.openstudio.one/v1/reference/categories', {
method: 'GET',
headers: {
'X-Api-User-Key': 'YOUR_USER_KEY'
}
})
.then(res => res.json())
.then(data => console.log(data));ⓘRuns a real request from your browser directly to reference/categories. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.
Response fields
| Field | Type | Flags | Notes |
|---|---|---|---|
| categories | array of objects | — | Every selectable category. |
| ↳code | string | — | The value to send as a rule's categories:<code> value. |
| ↳title | string | — | Human-readable category name. |
Example response
{
"success": true,
"data": {
"categories": [
{
"code": "staff",
"title": "Staff members"
},
{
"code": "external",
"title": "External collaborators"
}
]
},
"error": null
}