Documentation
API v1

Profiles

Your org directory and org chart, with cursor pagination and incremental sync. Names, titles, departments, teams, locations, start dates, and manager relationships.

Working with an AI agent?or point it at the Profiles markdown or the full-API markdown.
List profiles
GET
/api/v1/profiles
Your org directory and org chart as a paginated table: names, titles, departments, teams, locations, employment start dates, and manager relationships. Returns only current, non-hidden people, and defaults to Active so a COUNT is a true headcount (pass ?status=Active,Pending to include people who have been invited but have not joined). Requires profile:read (or profile:write). Account state (type, status, invited, joined) lives on /api/v1/users; the two join on userId.
ParameterTypeDescription
cursor
string
optional
Opaque cursor from a previous response's "nextCursor". Omit for the first page.
limit
number
optional
Rows per page, 1-500. Defaults to 100.
updatedSince
string
optional
ISO 8601 timestamp (or epoch milliseconds). Returns only profiles changed since this time, and populates "removed" with anyone who left the directory. Pass back the "syncedThrough" value from your previous run.
type
User | Agent | Pet | all
optional
Profile type, or a comma-separated list, or "all". One of: User, Agent, Pet. Defaults to User so a COUNT of the response is a true headcount and never includes AI agent or pet profiles.
status
Active | Pending
optional
Account status, or a comma-separated list. One of: Active, Pending. Defaults to Active — the common case is a headcount of people who are actually here, so someone invited but not yet joined is excluded. Pass "Active,Pending" for the full directory. Suspended and inactive people are never in this resource; they are on /api/v1/users.
Response:
{ data: { id: number; // stable key; managerId points into this same namespace userId: number; // join key to GET /api/v1/users email: string; firstName: string | null; lastName: string | null; displayName: string; avatarUrl: string | null; pronouns: string | null; pronunciation: string | null; type: 'User' | 'Agent' | 'Pet'; title: string | null; department: string | null; team: string | null; division: string | null; organization: string | null; costCenter: string | null; orgUnit: string | null; employeeId: string | null; startDate: string | null; // EMPLOYMENT start, ISO 8601. Not account creation. seniority: number | null; // tenure percentile location: string | null; city: string | null; state: string | null; country: string | null; timezone: string | null; tagline: string | null; status: string | null; phone: string | null; birthday: string | null; socialUrls: object | null; managerId: number | null; // self-join: managerId = id managerEmail: string | null; updated: string | null; // ISO 8601 }[]; removed: number[]; // ids that left the directory; only when updatedSince is set nextCursor: string | null; hasMore: boolean; syncedThrough: string; // ISO 8601; pass back as updatedSince }
Get a profile
GET
/api/v1/profiles/get
One profile by id or email, with its full upward manager chain and the values of its trading card and custom fields. Unlike the list, this returns deactivated and hidden people too, so it can be used to reconcile a departure. Requires profile:read.
ParameterTypeDescription
id
number
optional
The profile id. Either "id" or "email" is required.
email
string
optional
The profile email. Either "id" or "email" is required.
Response:
{ // every field from GET /api/v1/profiles, plus: managerChain: { id: number; email: string; displayName: string; depth: number }[]; // The trading card and custom field values, by field name ("field_<id>"). // An empty value or a disabled field is absent. fields: Record<string, string>; }
List profile fields
GET
/api/v1/profiles/fields
Your org's profile fields: the built-in fields, the trading card fields, and the custom fields, in one list, as the profile settings page shows them. Use it to discover which fields exist before writing to them. Requires profile:read.
Response:
{ data: { // The key in "fields" of POST /api/v1/profiles/update: a built-in name // such as "city", or "field_<id>" for a trading card or custom field. name: string; label: string; type: string; // For example "basics", "tradingCardFront", "tradingCardBack", "custom". group: string; groupLabel: string; kind: 'BuiltIn' | 'Org'; enabled: boolean; userEditable: boolean; }[]; }
Update a profile
POST
/api/v1/profiles/update
Update profile fields for one person. Requires profile:write, which only an Administrator or Owner can grant, or profile:write:self, which any member can grant and which updates only the token owner's profile. A token whose owner is not an admin updates only its owner's profile, and only the fields with "userEditable" true.
ParameterTypeDescription
email
string
required
The email of the person to update.
fields
object
required
Map of profile field name to value (see GET /api/v1/profiles/fields for valid names). A trading card or custom field is "field_<id>", and its value is a string. An empty string clears it.
Response:
{ id: number; email: string; updated: boolean; }