Skip to main content
Quick Summary: Org structure is two unrelated things. Eleven flat dimensions — businessUnits, divisions, businessRegions, countries, states, cities, sites, buildings, departments, teams, shifts — say where someone sits; the manager hierarchy says who they report to. They share nothing, and the dimensions have no parent-child structure between them.

Dimension values

Every dimension behaves identically. A value is { id, name, isActive }:
  • GET /api/v1/org/dimensions — the eleven keys.
  • GET /api/v1/org/{dimension} — every value, deactivated ones included.
  • POST /api/v1/org/{dimension} — create (name only; no ordering exists).
  • PATCH /api/v1/org/{dimension}/{id} — rename, or isActive: false to deactivate; isActive: true reactivates.
  • DELETE /api/v1/org/{dimension}/{id} — deactivates the value. Org values are retired, never removed, exactly as in the app: DELETE and PATCH { "isActive": false } are the same operation. It is idempotent (an already-inactive value returns 204) and needs no confirmation; the confirm query parameter is deprecated and ignored.
  • GET /api/v1/org/{dimension}/{id}/usage — how many people hold the value, before deactivating it.
  • GET /api/v1/org/{dimension}/{id}/people — everyone holding the value.

What deactivation does

Deactivating a value through the API does what deactivating it in Settings > Org Schema does:
  • The value leaves every person’s profile — its membership rows are removed, so GET .../usage reports peopleCount: 0 and GET .../people is empty.
  • Draft surveys and draft assessments that targeted the value drop it. Launched ones are untouched.
  • The value stays readable with isActive: false and reappears in GET /api/v1/org/{dimension} as inactive. PATCH { "isActive": true } brings it back.
  • The dimension’s history records who deactivated it (the key’s acting person).
Buildings are the app’s one exception: deactivating a building only flips its flag (no membership removal, no history), and the API mirrors that. One legacy edge case, also inherited from the app: a value whose active flag was never set reads as active, but deactivating it only sets the flag. The app runs its cleanup only when the flag was explicitly true, so such a value keeps its memberships. GET .../usage shows whether that happened. Deactivation never clears the legacy single-value columns on the person record (departments and businessRegions); usage.personRecordCount keeps that drift visible.

A person’s placement

Placement is many-to-many — someone can belong to two sites or three teams. It lives on the Person resource: GET|POST|DELETE /api/v1/people/{id}/org-schema (additive attach / explicit detach) and PUT /api/v1/people/{id}/org-schema/{dimension} to replace one dimension exactly.
Countries come from a fixed list. POST /api/v1/org/countries takes a name that must match a country exactly as GET /api/v1/countries lists it (the same global list the app offers); any other name is a 400 on name. The other ten dimensions accept any name.One representation is published. Internally five org facts also exist in a second, legacy form on the person record (single-value department and business-region columns, free-text city/state/country strings). The API reads and writes the membership form only; the usage read reports legacy-column references for departments and businessRegions so any drift is visible.

Manager hierarchy

  • GET /api/v1/org/manager-tree — the company’s reporting hierarchy as flat parent-pointer rows ordered by depth (roots at level 0), company-scoped, paginated.
  • GET /api/v1/people/{id}/span-of-control — one person’s subtree, subject included at level 0.
Setting a person’s manager is PATCH /api/v1/people/{id}/manager on the Person resource.