Organization

Your organization's structural hierarchy.

Structures & Hierarchy

POST /departments

Create a new structure (Area, Department, or Unit)

User key

Request body

FieldTypeFlagsRequiredNotes
level integer Required 1 (Area), 2 (Department), or 3 (Unit).
title string Required The new structure's display name.
name string Required The short code — auto-uppercased, spaces stripped. Must be unique in the tenant.
description string Optional A longer, free-text description of what this structure covers.
parent_acronym string Optional Required for level 2 or 3 — the direct parent structure's acronym, one level up.
leader_user_id integer Optional Defaults to a tenant-level fallback if omitted.

Example request

curl -X POST "https://api.openstudio.one/v1/departments" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"level":123,"title":"...","name":"...","description":"...","parent_acronym":"...","leader_user_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/departments');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'level' => 123,
    'title' => '...',
    'name' => '...',
    'description' => '...',
    'parent_acronym' => '...',
    'leader_user_id' => 123,
]));
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 = {
    'level': 123,
    'title': '...',
    'name': '...',
    'description': '...',
    'parent_acronym': '...',
    'leader_user_id': 123,
}
response = requests.post("https://api.openstudio.one/v1/departments", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/departments', {
  method: 'POST',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'level': 123,
    'title': '...',
    'name': '...',
    'description': '...',
    'parent_acronym': '...',
    'leader_user_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
department object

Example response

{
    "success": true,
    "data": {
        "department": {
            "id": 42,
            "acronym": "MKT",
            "title": "Marketing",
            "description": "Empty on creation unless one was sent.",
            "level": 1,
            "leader_user_id": 88
        }
    },
    "error": null
}

GET /departments

List organizational structures (Areas, Departments, Units)

User key Paginated
Query parameters (7)

Filtering

ParameterTypeRequiredNotes
?filter[level]integerOptionalFilter by structure level.
1 = Area
2 = Department
3 = Unit
?filter[parent_name]stringOptionalFilter by the direct parent structure's code.
?filter[acronym]stringOptionalReturn only the department matching this exact acronym.
?filter[title][like]stringOptionalSubstring match on the department's title.

Sorting

ParameterTypeRequiredNotes
?sortstringOptionalComma-separated sort fields: id, level, acronym, title, created_at, updated_at. Prefix with - for descending, e.g. sort=-created_at. See the "Filtering & sorting" guide.

Pagination

ParameterTypeRequiredNotes
?pageintegerOptionalPage number, starting at 1. Defaults to 1.
?limitintegerOptionalRows per page, 1-200. Defaults to 50.

Example request

curl -X GET "https://api.openstudio.one/v1/departments?filter%5Blevel%5D=123&filter%5Bparent_name%5D=...&filter%5Bacronym%5D=...&filter%5Btitle%5D%5Blike%5D=...&sort=...&page=123&limit=123" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/departments?filter%5Blevel%5D=123&filter%5Bparent_name%5D=...&filter%5Bacronym%5D=...&filter%5Btitle%5D%5Blike%5D=...&sort=...&page=123&limit=123');
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/departments?filter%5Blevel%5D=123&filter%5Bparent_name%5D=...&filter%5Bacronym%5D=...&filter%5Btitle%5D%5Blike%5D=...&sort=...&page=123&limit=123", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/departments?filter%5Blevel%5D=123&filter%5Bparent_name%5D=...&filter%5Bacronym%5D=...&filter%5Btitle%5D%5Blike%5D=...&sort=...&page=123&limit=123', {
  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 departments. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
departments array of objects Array of department objects, ordered by creation order within the tenant.
id integer Tenant-scoped structure ID (stable, used in dashboard URLs).
acronym string Short uppercase identifier, e.g. "ADMIN". Immutable after creation.
title string Full display name.
description string Free-text description. May be empty.
level integer Structure level.
1 = Area
2 = Department
3 = Unit
area string The top-level Area code this structure belongs to. Null for L1 Areas themselves.
area_title string Display title of area, resolved server-side so it's available even if that Area itself isn't in this caller's own visible list (scope: "own"). Null exactly when area is null.
parent_name string Direct parent structure code. Null only for L1 Areas.
parent_title string Display title of parent_name, resolved server-side for the same reason as area_title. Null exactly when parent_name is null.
leader_user_id integer The account id of the structure's leader/manager, if assigned.
member_count integer Distinct active members of this structure AND every structure beneath it (same "active" definition as GET /users/{id}/memberships: until IS NULL OR until >= today) — an Area's count includes everyone assigned to one of its Departments/Units, not just people assigned directly to the Area itself. Someone assigned at more than one level in the same lineage is only counted once.
created_at string Creation timestamp, YYYY-MM-DD HH:MM:SS.
updated_at string Last update timestamp. Null if never updated since creation.
scope string full if the caller (founder or any manage_personal tier > 0) sees every structure in the tenant; own if the list was narrowed to structures they lead, co-manage, or hold an active membership in.
full
own
general_director object The tenant's current General Director, if one resolves (an active departments_directors row, or the tenant's founder as a fallback). Null if neither exists. Tenant name/logo/structure-level labels moved to their own GET /tenant/profile — see that route.
user_id integer The user currently holding this role — either an explicit appointment, or the tenant's founder via the fallback.
username string Login username — always present, regardless of privacy mode (see display_name).
display_name string The name to actually show in UI. Real first+last name from the person's identity data when available and they're not in privacy mode; falls back to username otherwise.
avatar_url string Always a real, loadable URL — a shared blank-avatar placeholder when there's no real photo on file, or when the person is in privacy mode.
from_date string Null when resolved via the founder fallback (no formal appointment record).
appointed_by_user_id integer The id of whoever made the appointment. Null via the founder fallback, or if the appointment itself never recorded one.
is_interim boolean True when resolved via the founder fallback rather than an explicit departments_directors appointment.

Pagination

FieldTypeNotes
pageintegerCurrent page number.
limitintegerRows per page.
totalintegerTotal matching rows across all pages.
total_pagesintegerTotal number of pages.
next_page_urlstringReady-to-call URL for the next page, same filters applied. Null on the last page.
prev_page_urlstringReady-to-call URL for the previous page, same filters applied. Null on the first page.

Example response

{
    "success": true,
    "data": {
        "departments": [
            {
                "id": 2,
                "acronym": "ADMIN",
                "title": "Administration",
                "description": "This is the first structure of your organization...",
                "level": 2,
                "area": "MAIN",
                "area_title": "Main Area",
                "parent_name": "MAIN",
                "parent_title": "Main Area",
                "leader_user_id": 2371,
                "member_count": 14,
                "created_at": "2023-06-18 09:17:39",
                "updated_at": null
            },
            {
                "id": 1,
                "acronym": "MAIN",
                "title": "Main Area",
                "description": "This is the main Area in your organization...",
                "level": 1,
                "area": null,
                "area_title": null,
                "parent_name": null,
                "parent_title": null,
                "leader_user_id": 2371,
                "member_count": 32,
                "created_at": "2023-06-18 09:17:39",
                "updated_at": null
            }
        ],
        "scope": "full",
        "general_director": {
            "user_id": 2371,
            "username": "jane.doe",
            "display_name": "Jane Doe",
            "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg",
            "from_date": "2023-06-18",
            "appointed_by_user_id": null,
            "is_interim": false
        }
    },
    "error": null,
    "pagination": {
        "page": 1,
        "limit": 50,
        "total": 134,
        "total_pages": 3,
        "next_page_url": "https://api.openstudio.one/v1/departments?page=2&limit=50",
        "prev_page_url": null
    }
}

PATCH /departments/{id}

Edit a structure's title, description, or leader

User key

Request body

FieldTypeFlagsRequiredNotes
title string Optional The structure's new display name.
description string Optional A longer, free-text description of what this structure covers.
leader_user_id integer Optional The structure's new leader, by user id.

Example request

curl -X PATCH "https://api.openstudio.one/v1/departments/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"...","description":"...","leader_user_id":123}'
<?php
$ch = curl_init('https://api.openstudio.one/v1/departments/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'title' => '...',
    'description' => '...',
    'leader_user_id' => 123,
]));
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 = {
    'title': '...',
    'description': '...',
    'leader_user_id': 123,
}
response = requests.patch("https://api.openstudio.one/v1/departments/{id}", headers=headers, json=body)
data = response.json()
fetch('https://api.openstudio.one/v1/departments/{id}', {
  method: 'PATCH',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'title': '...',
    'description': '...',
    'leader_user_id': 123,
  })
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
department object

Example response

{
    "success": true,
    "data": {
        "department": {
            "id": 42,
            "acronym": "MKT",
            "title": "Marketing",
            "description": "Empty here unless a description was actually sent in this call.",
            "level": 1,
            "leader_user_id": 88
        }
    },
    "error": null
}

DELETE /departments/{id}

Delete a structure — only when it is currently empty

User key

Example request

curl -X DELETE "https://api.openstudio.one/v1/departments/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/departments/{id}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
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.delete("https://api.openstudio.one/v1/departments/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/departments/{id}', {
  method: 'DELETE',
  headers: {
    'X-Api-User-Key': 'YOUR_USER_KEY'
  }
})
  .then(res => res.json())
  .then(data => console.log(data));

Response fields

FieldTypeFlagsNotes
deleted boolean

Example response

{
    "success": true,
    "data": {
        "deleted": true
    },
    "error": null
}

GET /departments/{acronym}/members

Real name/photo for a structure's leader and active members

User key Paginated
Query parameters (2)

Pagination

ParameterTypeRequiredNotes
?pageintegerOptionalPage number, starting at 1. Defaults to 1. Applies to members only.
?limitintegerOptionalRows per page, 1-200. Defaults to 50.

Example request

curl -X GET "https://api.openstudio.one/v1/departments/{acronym}/members?page=123&limit=123" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/departments/{acronym}/members?page=123&limit=123');
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/departments/{acronym}/members?page=123&limit=123", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/departments/{acronym}/members?page=123&limit=123', {
  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 departments/{acronym}/members. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
department object The structure this route was called for, echoed back for convenience.
id integer Tenant-scoped structure ID.
acronym string Short uppercase identifier — the same value passed in the URL.
title string Full display name.
leader object Null if the structure has no leader assigned. Not paginated — a structure has at most one.
user_id integer Matches the leader's user_id on GET /departments.
username string Login username — always present, regardless of privacy mode (see display_name).
display_name string The name to actually show in UI. Real first+last name from the person's identity data when available and they're not in privacy mode; falls back to username otherwise (privacy mode, or no identity data on file yet).
avatar_url string Always a real, loadable URL — a shared blank-avatar placeholder when there's no real photo on file, or when the person is in privacy mode (their real photo, if any, is withheld the same way their real name is).
members array of objects Everyone with an active (non-expired) membership in this structure, primary members first, then by user id.
user_id integer Usable with GET /users/{id} if the caller separately has manage_personal access.
username string Login username — always present, regardless of privacy mode (see display_name).
display_name string The name to actually show in UI. Real first+last name from the person's identity data when available and they're not in privacy mode; falls back to username otherwise (privacy mode, or no identity data on file yet).
avatar_url string Always a real, loadable URL — a shared blank-avatar placeholder when there's no real photo on file, or when the person is in privacy mode.
is_primary boolean Whether this structure is the member's PRIMARY assignment — see the /me memberships list for the same flag from the member's own point of view.

Pagination

FieldTypeNotes
pageintegerCurrent page number.
limitintegerRows per page.
totalintegerTotal matching rows across all pages.
total_pagesintegerTotal number of pages.
next_page_urlstringReady-to-call URL for the next page, same filters applied. Null on the last page.
prev_page_urlstringReady-to-call URL for the previous page, same filters applied. Null on the first page.

Example response

{
    "success": true,
    "data": {
        "department": {
            "id": 2,
            "acronym": "ADMIN",
            "title": "Administration"
        },
        "leader": {
            "user_id": 2371,
            "username": "jane.doe",
            "display_name": "Jane Doe",
            "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg"
        },
        "members": [
            {
                "user_id": 2371,
                "username": "jane.doe",
                "display_name": "Jane Doe",
                "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg",
                "is_primary": true
            },
            {
                "user_id": 2455,
                "username": "john.smith",
                "display_name": "John Smith",
                "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg",
                "is_primary": false
            }
        ]
    },
    "error": null,
    "pagination": {
        "page": 1,
        "limit": 50,
        "total": 134,
        "total_pages": 3,
        "next_page_url": "https://api.openstudio.one/v1/departments?page=2&limit=50",
        "prev_page_url": null
    }
}

Directory

GET /directory

Find a colleague — search the tenant's user directory

User key Paginated
Query parameters (12)

Pagination

ParameterTypeRequiredNotes
?pageintegerOptionalPage number, starting at 1. Defaults to 1.
?limitintegerOptionalRows per page, 1-50. Defaults to 20.

Other

ParameterTypeRequiredNotes
?qstringOptionalCombined name/username search term, minimum 2 characters. Required unless structure, q_name, q_surname, q_email, or q_number is given instead.
?q_namestringOptionalFirst-name-only search (separate from q, matches address_book.php's own q_name field). Combinable with q/q_surname/others.
?q_surnamestringOptionalLast-name-only search (separate from q, matches address_book.php's own q_surname field).
?structurestringOptionalRestrict results to active members of this structure acronym (matches GET /departments' own acronym).
?include_subbooleanOptionalWith structure, also include that structure's sub-departments/units (one/two levels down).
?include_leadersbooleanOptionalWith structure, also include that structure's leader even if they are not formally an active member of it.
?dutystringOptionalFilter by organizational role: dept_leader (leads any department/unit) or area_head (leads an area). Matches address_book.php's own duty filter (FIX #21).
?q_emailstringOptionalSubstring match against work contact records of type email (contacts.data).
?q_numberstringOptionalSubstring match against work contact records of type phone/extension (contacts.data).
?q_typestringOptionalRestrict q_email/q_number matching (or standalone) to one contact-channel type, e.g. business_email, telephone_short, service_phone.

Example request

curl -X GET "https://api.openstudio.one/v1/directory?q=...&q_name=...&q_surname=...&structure=...&include_sub=true&include_leaders=true&duty=...&q_email=...&q_number=...&q_type=...&page=123&limit=123" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/directory?q=...&q_name=...&q_surname=...&structure=...&include_sub=true&include_leaders=true&duty=...&q_email=...&q_number=...&q_type=...&page=123&limit=123');
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/directory?q=...&q_name=...&q_surname=...&structure=...&include_sub=true&include_leaders=true&duty=...&q_email=...&q_number=...&q_type=...&page=123&limit=123", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/directory?q=...&q_name=...&q_surname=...&structure=...&include_sub=true&include_leaders=true&duty=...&q_email=...&q_number=...&q_type=...&page=123&limit=123', {
  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 directory. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
results array of objects Matching users, same shape as the top-level fields of GET /directory/{id} (no memberships/staff_details — fetch those separately per result if the caller taps into one).
user_id integer
username string
display_name string
avatar_url string
primary_structure_title string The person's primary active structure, if any — included specifically to disambiguate homonyms in a results list without opening each profile.

Pagination

FieldTypeNotes
pageintegerCurrent page number.
limitintegerRows per page.
totalintegerTotal matching rows across all pages.
total_pagesintegerTotal number of pages.
next_page_urlstringReady-to-call URL for the next page, same filters applied. Null on the last page.
prev_page_urlstringReady-to-call URL for the previous page, same filters applied. Null on the first page.

Example response

{
    "success": true,
    "data": {
        "results": [
            {
                "user_id": 2455,
                "username": "john.smith",
                "display_name": "John Smith",
                "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg",
                "primary_structure_title": "Administration Finance & Accounting"
            }
        ]
    },
    "error": null,
    "pagination": {
        "page": 1,
        "limit": 50,
        "total": 134,
        "total_pages": 3,
        "next_page_url": "https://api.openstudio.one/v1/departments?page=2&limit=50",
        "prev_page_url": null
    }
}

GET /directory/{id}

Clickable-profile view of another user

User key

Example request

curl -X GET "https://api.openstudio.one/v1/directory/{id}" \
  -H "X-Api-User-Key: YOUR_USER_KEY"
<?php
$ch = curl_init('https://api.openstudio.one/v1/directory/{id}');
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/directory/{id}", headers=headers)
data = response.json()
fetch('https://api.openstudio.one/v1/directory/{id}', {
  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 directory/{id}. Keys are only held in this page's memory while you're here — never stored, never sent anywhere else.

Response fields

FieldTypeFlagsNotes
user_id integer The user's unique numeric ID.
username string Login username — always present, regardless of privacy mode (see display_name).
display_name string The name to actually show in UI. Real first+last name when available and the person isn't in privacy mode; falls back to username otherwise.
avatar_url string Always a real, loadable URL — a shared blank-avatar placeholder when there's no real photo on file, or when the person is in privacy mode.
memberships array of objects Currently active organizational structure assignments, primary first — identical shape to GET /users/{id}/memberships.
id integer This assignment's own id. null if this row exists ONLY because the person leads or manages this structure without actually being a member of it (is_leader/is_manager) — there's no departments_users row to reference in that case.
structure_acronym string Matches the acronym field on GET /departments.
structure_title string Full display name of the structure.
level integer Structure level.
1 = Area
2 = Department
3 = Unit
parent_title string Display title of the structure's immediate parent, resolved server-side (same as parent_title on GET /departments). Null only for an L1 Area.
area_title string Display title of the structure's top-level Area (same as area_title on GET /departments) — for an L3 Unit this differs from parent_title (its immediate L2 parent); for an L2 Department the two are equal. Null only for an L1 Area.
is_primary boolean At most one primary assignment per user at a time. Always false on a leadership-only row (no actual membership).
is_leader boolean Whether this person is this structure's leader (matches leader_user_id on GET /departments) — independent of whether they're also a member of it.
is_manager boolean Whether this person is one of this structure's co-managers — independent of whether they're also a member of it.
since string When this assignment started. null on a leadership-only row.
until string null = open-ended (also always null on a leadership-only row).
notes string Free-text note attached when this assignment was created, if any.
staff_details object Present only when the CALLER is a STRUCTURED_USERS member or founder. null for every other caller — its absence of data, not the target's, so a null here says nothing about the target themselves.
email string The target's account email.
phone_number string Work phone, if on file.
mobile_number string Work mobile, if on file.
contact_channels array of objects Every other active, visible contact entry on file for this person (institutional email, internal extension, service mobile, fax, ...) — a person can have several of the same type (e.g. two internal extensions in different structures), so this is a list alongside (not a replacement for) email/phone_number/mobile_number above.
type string Internal channel type key, e.g. business_email, telephone_short, service_phone, fax.
label string Human-readable label for type, already translated/humanized server-side.
value string The actual email address, phone number, or extension.
structure string The structure acronym this specific entry is scoped to, if any (e.g. a department-specific extension). Null for a person-level entry not tied to any one structure.
director object Present only if the TARGET currently holds the tenant's General Director role — same shape as /me's own director field.
role string
general_director
from_date string
to_date string Always null — only the current directorship is ever represented here.
appointed_by_user_id integer
is_interim boolean

Example response

{
    "success": true,
    "data": {
        "user_id": 2455,
        "username": "john.smith",
        "display_name": "John Smith",
        "avatar_url": "https://www.openstudio.one/assets/img/avatars/blank_avatar.jpg",
        "memberships": [
            {
                "id": 41,
                "structure_acronym": "AFA",
                "structure_title": "Administration Finance & Accounting",
                "level": 2,
                "parent_title": "Main Area",
                "area_title": "Main Area",
                "is_primary": true,
                "is_leader": false,
                "is_manager": false,
                "since": "2019-08-19",
                "until": null,
                "notes": null
            }
        ],
        "staff_details": {
            "email": "john.smith@example.com",
            "phone_number": null,
            "mobile_number": null,
            "contact_channels": [
                {
                    "type": "telephone_short",
                    "label": "Internal Extension",
                    "value": "204",
                    "structure": "AFA"
                }
            ],
            "director": null
        }
    },
    "error": null
}
ESC