openapi: 3.0.3
info:
title: 'Orgonaut API Reference'
description: ''
version: 1.0.0
servers:
-
url: 'https://app.orgonaut.co'
tags:
-
name: 'AI Tooling Usage'
description: ''
-
name: Actors
description: ''
-
name: Aggregates
description: ''
-
name: Astro
description: ''
-
name: Auth/Tokens
description: ''
-
name: Batch
description: ''
-
name: 'Capability Studio'
description: ''
-
name: Costs
description: ''
-
name: 'Department Types'
description: ''
-
name: Departments
description: ''
-
name: Initiatives
description: ''
-
name: Integrations
description: ''
-
name: Lineage
description: ''
-
name: 'Org Placements'
description: ''
-
name: 'Org Units'
description: ''
-
name: 'Org Units — Metrics'
description: ''
-
name: 'Org Units — Structure'
description: ''
-
name: 'Org Units — Velocity'
description: ''
-
name: 'Organisation Accounts'
description: "\nAPI descriptions intentionally use “Organisation Account” wording for user-facing clarity."
-
name: Positions
description: 'Manage effective-dated team positions, linking actors, teams, and compensation within each scenario.'
-
name: 'Role Types'
description: ''
-
name: 'Scenario Tasks'
description: ''
-
name: Scenarios
description: ''
-
name: Snapshots
description: ''
-
name: 'Team Types'
description: ''
-
name: Teams
description: ''
-
name: 'Teams — Velocity'
description: ''
-
name: 'Tenant Invitations'
description: ''
-
name: 'Tenant Members'
description: ''
-
name: 'Work Catalog'
description: ''
components:
securitySchemes:
default:
type: http
scheme: bearer
description: 'You can retrieve your token by visiting your dashboard and clicking Generate API token.'
bearerAuth:
type: http
scheme: bearer
parameters:
X-Tenant:
name: X-Tenant
in: header
required: true
schema:
type: string
description: 'Tenant slug; required on the root domain and optional when using a tenant subdomain.'
security:
-
default: []
bearerAuth: []
paths:
/api/v1/ai-tooling/usage:
get:
summary: 'AI Tooling — List daily usage records'
operationId: aIToolingListDailyUsageRecords
description: "Returns a paginated list of daily usage records across all matched and unmatched actors.\nRecords are ordered by `usage_date` descending (most recent first). Each record represents\none actor's usage of one AI tooling provider on a single day.\n\nSupports filtering by actor, provider, and date range. Unmatched records (where the\nsource email could not be resolved to an Orgonaut actor) have `actor_id: null`.\n\nRequires `ai-tooling.manage` ability."
parameters:
-
in: query
name: actor_id
description: 'Filter by actor ID. Only returns records matched to this actor.'
example: 42
required: false
schema:
type: integer
description: 'Filter by actor ID. Only returns records matched to this actor.'
example: 42
-
in: query
name: provider
description: 'Filter by provider slug (e.g. "claude").'
example: claude
required: false
schema:
type: string
description: 'Filter by provider slug (e.g. "claude").'
example: claude
-
in: query
name: from
description: 'date Start of date range (inclusive, YYYY-MM-DD).'
example: '2026-03-01'
required: false
schema:
type: string
description: 'date Start of date range (inclusive, YYYY-MM-DD).'
example: '2026-03-01'
-
in: query
name: to
description: 'date End of date range (inclusive, YYYY-MM-DD). Must be on or after `from`.'
example: '2026-03-25'
required: false
schema:
type: string
description: 'date End of date range (inclusive, YYYY-MM-DD). Must be on or after `from`.'
example: '2026-03-25'
-
in: query
name: per_page
description: 'Results per page. Min 1, max 100. Defaults to 25.'
example: 25
required: false
schema:
type: integer
description: 'Results per page. Min 1, max 100. Defaults to 25.'
example: 25
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 128
actor_id: 42
provider: claude
source_email: aoife.ryan@example.com
usage_date: '2026-03-24'
sessions_count: 5
lines_added: 320
lines_removed: 85
commits_count: 4
pull_requests_count: 1
total_input_tokens: 125000
total_output_tokens: 48000
total_cache_read_tokens: 32000
total_cache_creation_tokens: 8000
total_cost_cents: 245
currency: USD
tool_actions:
edit_tool:
accepted: 18
rejected: 2
bash_tool:
accepted: 12
rejected: 0
model_breakdown:
-
model: claude-opus-4-6
input_tokens: 80000
output_tokens: 30000
-
model: claude-sonnet-4-6
input_tokens: 45000
output_tokens: 18000
matched_at: '2026-03-24T03:15:42+00:00'
actor:
id: 42
name: 'Aoife Ryan'
email: aoife.ryan@example.com
links:
first: '/?page=1'
last: '/?page=3'
prev: null
next: '/?page=2'
meta:
current_page: 1
last_page: 3
per_page: 25
total: 72
properties:
data:
type: array
example:
-
id: 128
actor_id: 42
provider: claude
source_email: aoife.ryan@example.com
usage_date: '2026-03-24'
sessions_count: 5
lines_added: 320
lines_removed: 85
commits_count: 4
pull_requests_count: 1
total_input_tokens: 125000
total_output_tokens: 48000
total_cache_read_tokens: 32000
total_cache_creation_tokens: 8000
total_cost_cents: 245
currency: USD
tool_actions:
edit_tool:
accepted: 18
rejected: 2
bash_tool:
accepted: 12
rejected: 0
model_breakdown:
-
model: claude-opus-4-6
input_tokens: 80000
output_tokens: 30000
-
model: claude-sonnet-4-6
input_tokens: 45000
output_tokens: 18000
matched_at: '2026-03-24T03:15:42+00:00'
actor:
id: 42
name: 'Aoife Ryan'
email: aoife.ryan@example.com
items:
type: object
properties:
id:
type: integer
example: 128
actor_id:
type: integer
example: 42
provider:
type: string
example: claude
source_email:
type: string
example: aoife.ryan@example.com
usage_date:
type: string
example: '2026-03-24'
sessions_count:
type: integer
example: 5
lines_added:
type: integer
example: 320
lines_removed:
type: integer
example: 85
commits_count:
type: integer
example: 4
pull_requests_count:
type: integer
example: 1
total_input_tokens:
type: integer
example: 125000
total_output_tokens:
type: integer
example: 48000
total_cache_read_tokens:
type: integer
example: 32000
total_cache_creation_tokens:
type: integer
example: 8000
total_cost_cents:
type: integer
example: 245
currency:
type: string
example: USD
tool_actions:
type: object
properties:
edit_tool:
type: object
properties:
accepted:
type: integer
example: 18
rejected:
type: integer
example: 2
bash_tool:
type: object
properties:
accepted:
type: integer
example: 12
rejected:
type: integer
example: 0
model_breakdown:
type: array
example:
-
model: claude-opus-4-6
input_tokens: 80000
output_tokens: 30000
-
model: claude-sonnet-4-6
input_tokens: 45000
output_tokens: 18000
items:
type: object
properties:
model:
type: string
example: claude-opus-4-6
input_tokens:
type: integer
example: 80000
output_tokens:
type: integer
example: 30000
matched_at:
type: string
example: '2026-03-24T03:15:42+00:00'
actor:
type: object
properties:
id:
type: integer
example: 42
name:
type: string
example: 'Aoife Ryan'
email:
type: string
example: aoife.ryan@example.com
links:
type: object
properties:
first:
type: string
example: '/?page=1'
last:
type: string
example: '/?page=3'
prev:
type: string
example: null
nullable: true
next:
type: string
example: '/?page=2'
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 3
per_page:
type: integer
example: 25
total:
type: integer
example: 72
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
to:
- 'The to field must be a date after or equal to from.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
to:
type: array
example:
- 'The to field must be a date after or equal to from.'
items:
type: string
tags:
- 'AI Tooling Usage'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
actor_id:
type: integer
description: ''
example: 11
provider:
type: string
description: 'Must not be greater than 50 characters.'
example: pzdszigdqrrkthqp
from:
type: string
description: 'Must be a valid date.'
example: '2026-10-11T21:57:38'
to:
type: string
description: 'Must be a valid date. Must be a date after or equal to from.'
example: '2069-11-01'
per_page:
type: integer
description: 'Must be at least 1. Must not be greater than 100.'
example: 4
'/api/v1/ai-tooling/actors/{actor_id}/summary':
get:
summary: 'AI Tooling — Actor summary'
operationId: aIToolingActorSummary
description: "Returns aggregated AI tooling cost and usage totals for a single actor. Includes the\nlast full calendar month total, month-to-date total, and a per-provider breakdown.\n\nUseful for actor profile cards and dashboards.\n\nRequires `ai-tooling.manage` ability."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
actor_id: 42
has_data: true
monthly_cost_cents: 850
mtd_cost_cents: 320
sessions: 15
commits: 8
prs: 2
lines_added: 450
lines_removed: 120
by_provider:
claude:
cost_cents: 850
mtd_cost_cents: 320
sessions: 15
properties:
data:
type: object
properties:
actor_id:
type: integer
example: 42
has_data:
type: boolean
example: true
monthly_cost_cents:
type: integer
example: 850
mtd_cost_cents:
type: integer
example: 320
sessions:
type: integer
example: 15
commits:
type: integer
example: 8
prs:
type: integer
example: 2
lines_added:
type: integer
example: 450
lines_removed:
type: integer
example: 120
by_provider:
type: object
properties:
claude:
type: object
properties:
cost_cents:
type: integer
example: 850
mtd_cost_cents:
type: integer
example: 320
sessions:
type: integer
example: 15
tags:
- 'AI Tooling Usage'
parameters:
-
in: path
name: actor_id
description: 'The ID of the actor.'
example: 11
required: true
schema:
type: integer
-
in: path
name: actor
description: 'The actor ID.'
example: 42
required: true
schema:
type: integer
'/api/v1/ai-tooling/actors/{actor_id}/series':
get:
summary: 'AI Tooling — Actor daily series'
operationId: aIToolingActorDailySeries
description: "Returns a daily time series of AI tooling usage for a single actor. Each data point\ncontains cost, token consumption, session count, and code-change metrics for one day.\nDesigned for rendering cost trend and activity charts on actor profile pages.\n\nDefaults to the last 6 months when `from`/`to` are omitted.\n\nRequires `ai-tooling.manage` ability."
parameters:
-
in: query
name: from
description: 'date Start of date range (YYYY-MM-DD). Defaults to 6 months ago (start of month).'
example: '2025-10-01'
required: false
schema:
type: string
description: 'date Start of date range (YYYY-MM-DD). Defaults to 6 months ago (start of month).'
example: '2025-10-01'
-
in: query
name: to
description: 'date End of date range (YYYY-MM-DD). Must be on or after `from`. Defaults to today.'
example: '2026-03-25'
required: false
schema:
type: string
description: 'date End of date range (YYYY-MM-DD). Must be on or after `from`. Defaults to today.'
example: '2026-03-25'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
date: '2026-03-23'
cost_cents: 120
sessions: 3
commits: 2
prs: 0
lines_added: 180
lines_removed: 45
input_tokens: 52000
output_tokens: 19000
-
date: '2026-03-24'
cost_cents: 245
sessions: 5
commits: 4
prs: 1
lines_added: 320
lines_removed: 85
input_tokens: 125000
output_tokens: 48000
properties:
data:
type: array
example:
-
date: '2026-03-23'
cost_cents: 120
sessions: 3
commits: 2
prs: 0
lines_added: 180
lines_removed: 45
input_tokens: 52000
output_tokens: 19000
-
date: '2026-03-24'
cost_cents: 245
sessions: 5
commits: 4
prs: 1
lines_added: 320
lines_removed: 85
input_tokens: 125000
output_tokens: 48000
description: 'Array of daily data points, ordered by date ascending.'
items:
type: object
properties:
date:
type: string
example: '2026-03-23'
cost_cents:
type: integer
example: 120
sessions:
type: integer
example: 3
commits:
type: integer
example: 2
prs:
type: integer
example: 0
lines_added:
type: integer
example: 180
lines_removed:
type: integer
example: 45
input_tokens:
type: integer
example: 52000
output_tokens:
type: integer
example: 19000
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
to:
- 'The to field must be a date after or equal to from.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
to:
type: array
example:
- 'The to field must be a date after or equal to from.'
items:
type: string
tags:
- 'AI Tooling Usage'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
from:
type: string
description: 'Must be a valid date.'
example: '2026-10-11T21:57:38'
to:
type: string
description: 'Must be a valid date. Must be a date after or equal to from.'
example: '2069-11-01'
parameters:
-
in: path
name: actor_id
description: 'The ID of the actor.'
example: 11
required: true
schema:
type: integer
-
in: path
name: actor
description: 'The actor ID.'
example: 42
required: true
schema:
type: integer
'/api/v1/ai-tooling/teams/{team_id}/summary':
get:
summary: 'AI Tooling — Team summary'
operationId: aIToolingTeamSummary
description: "Returns aggregated AI tooling cost and usage totals for all actors placed in the team's\norg unit. Covers the last full calendar month and month-to-date period.\n\nIf the team has no associated org unit, zeroed metrics are returned.\n\nRequires `ai-tooling.manage` ability."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
team_id: 7
monthly_cost_cents: 2500
mtd_cost_cents: 1200
sessions: 45
commits: 22
prs: 6
lines_added: 1800
lines_removed: 400
properties:
data:
type: object
properties:
team_id:
type: integer
example: 7
monthly_cost_cents:
type: integer
example: 2500
mtd_cost_cents:
type: integer
example: 1200
sessions:
type: integer
example: 45
commits:
type: integer
example: 22
prs:
type: integer
example: 6
lines_added:
type: integer
example: 1800
lines_removed:
type: integer
example: 400
tags:
- 'AI Tooling Usage'
parameters:
-
in: path
name: team_id
description: 'The ID of the team.'
example: 11
required: true
schema:
type: integer
-
in: path
name: team
description: 'The team ID.'
example: 7
required: true
schema:
type: integer
'/api/v1/ai-tooling/departments/{department_id}/summary':
get:
summary: 'AI Tooling — Department summary'
operationId: aIToolingDepartmentSummary
description: "Returns aggregated AI tooling cost and usage totals for a department. By default,\naggregates across the entire department subtree (all descendant org units). Pass\n`scope=direct` to limit to actors placed directly in the department's own org unit.\n\nIf the department has no associated org unit, zeroed metrics are returned.\n\nRequires `ai-tooling.manage` ability."
parameters:
-
in: query
name: scope
description: 'Aggregation scope: "direct" (department org unit only) or "subtree" (all descendants). Defaults to "subtree".'
example: subtree
required: false
schema:
type: string
description: 'Aggregation scope: "direct" (department org unit only) or "subtree" (all descendants). Defaults to "subtree".'
example: subtree
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
department_id: 3
scope: subtree
monthly_cost_cents: 8500
mtd_cost_cents: 3200
sessions: 120
commits: 55
prs: 12
lines_added: 5000
lines_removed: 1200
properties:
data:
type: object
properties:
department_id:
type: integer
example: 3
scope:
type: string
example: subtree
monthly_cost_cents:
type: integer
example: 8500
mtd_cost_cents:
type: integer
example: 3200
sessions:
type: integer
example: 120
commits:
type: integer
example: 55
prs:
type: integer
example: 12
lines_added:
type: integer
example: 5000
lines_removed:
type: integer
example: 1200
tags:
- 'AI Tooling Usage'
parameters:
-
in: path
name: department_id
description: 'The ID of the department.'
example: 11
required: true
schema:
type: integer
-
in: path
name: department
description: 'The department ID.'
example: 3
required: true
schema:
type: integer
/api/v1/actors:
get:
summary: 'Actors — List'
operationId: actorsList
description: "Returns actors with their primary team resolved from primary org-unit placements (primary=true) inside\nthe active scenario context.\n\nRequires `actors.read` ability."
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: scenario
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
required: false
schema:
type: string
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
-
in: query
name: 'filter[scenario_id]'
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
required: false
schema:
type: string
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
-
in: query
name: 'filter[scenario]'
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
required: false
schema:
type: string
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
-
in: query
name: 'filter[status]'
description: 'Filter by status.'
example: active
required: false
schema:
type: string
description: 'Filter by status.'
example: active
-
in: query
name: 'filter[department_id]'
description: 'Filter by department id. Uses the department org unit mapping derived from `org_unit_actor`.'
example: 5
required: false
schema:
type: integer
description: 'Filter by department id. Uses the department org unit mapping derived from `org_unit_actor`.'
example: 5
-
in: query
name: 'filter[org_unit_id]'
description: 'Filter by org unit id (department or team subtree).'
example: 10
required: false
schema:
type: integer
description: 'Filter by org unit id (department or team subtree).'
example: 10
-
in: query
name: 'fields[actors]'
description: 'Sparse fields for actors.'
example: 'id,first_name,last_name'
required: false
schema:
type: string
description: 'Sparse fields for actors.'
example: 'id,first_name,last_name'
-
in: query
name: include
description: 'Comma-separated expansions. Allowed: manager,org_units,team,department. The `team`/`department` flags surface computed placement data.'
example: 'manager,team'
required: false
schema:
type: string
description: 'Comma-separated expansions. Allowed: manager,org_units,team,department. The `team`/`department` flags surface computed placement data.'
example: 'manager,team'
-
in: query
name: as_of
description: 'The date/datetime used for time-window checks. Defaults to now.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'The date/datetime used for time-window checks. Defaults to now.'
example: '2025-09-01'
-
in: query
name: scenario_id
description: 'The scenario ID to scope results. Omit or pass `scenario_id=null` for baseline data.'
example: 4
required: false
schema:
type: integer
description: 'The scenario ID to scope results. Omit or pass `scenario_id=null` for baseline data.'
example: 4
-
in: query
name: with_counts
description: 'Comma-separated relationship counts. Allowed: reports.'
example: reports
required: false
schema:
type: string
description: 'Comma-separated relationship counts. Allowed: reports.'
example: reports
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 44
first_name: Aoife
last_name: Ryan
name: 'Aoife Ryan'
email: aoife.ryan@example.com
fte: 1.0
manager_id: 2
team:
id: 15
name: 'Team CúChulainn'
team_type:
id: 3
name: 'Product Squad'
slug: product-squad
department:
id: 3
name: Engineering
properties:
data:
type: array
example:
-
id: 44
first_name: Aoife
last_name: Ryan
name: 'Aoife Ryan'
email: aoife.ryan@example.com
fte: 1
manager_id: 2
team:
id: 15
name: 'Team CúChulainn'
team_type:
id: 3
name: 'Product Squad'
slug: product-squad
department:
id: 3
name: Engineering
items:
type: object
properties:
id:
type: integer
example: 44
first_name:
type: string
example: Aoife
last_name:
type: string
example: Ryan
name:
type: string
example: 'Aoife Ryan'
email:
type: string
example: aoife.ryan@example.com
fte:
type: number
example: 1.0
manager_id:
type: integer
example: 2
team:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: 'Product Squad'
slug:
type: string
example: product-squad
department:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- name
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- name
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- Actors
post:
summary: 'Store a newly created actor.'
operationId: storeANewlyCreatedActor
description: "Requires `actors.create` ability.\nManager must belong to the same tenant and cannot reference the actor themselves."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 44
first_name: Aoife
last_name: Ryan
name: 'Aoife Ryan'
email: aoife.ryan@example.com
kind: human
status: active
contract_type: perm
fte: 1.0
manager_id: 2
start_date: '2025-09-01'
end_date: '2025-09-30'
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 44
first_name:
type: string
example: Aoife
last_name:
type: string
example: Ryan
name:
type: string
example: 'Aoife Ryan'
email:
type: string
example: aoife.ryan@example.com
kind:
type: string
example: human
status:
type: string
example: active
contract_type:
type: string
example: perm
fte:
type: number
example: 1.0
manager_id:
type: integer
example: 2
start_date:
type: string
example: '2025-09-01'
end_date:
type: string
example: '2025-09-30'
created_at:
type: string
example: '2025-01-10T09:00:00Z'
429:
description: ''
content:
application/json:
schema:
type: object
example:
code: limit.actors
message: 'Actor plan limit reached (250/250). Upgrade your plan to add more people.'
limit: 250
current: 250
properties:
code:
type: string
example: limit.actors
message:
type: string
example: 'Actor plan limit reached (250/250). Upgrade your plan to add more people.'
limit:
type: integer
example: 250
current:
type: integer
example: 250
tags:
- Actors
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
first_name:
type: string
description: "The actor's first name."
example: Aoife
last_name:
type: string
description: "The actor's last name."
example: Ryan
email:
type: string
description: 'Optional contact email for the actor. Human actors can be created without email.'
example: aoife.ryan@example.com
nullable: true
external_uid:
type: string
description: 'Durable Orgonaut actor identifier. If omitted, API generates a ULID.'
example: 01J9ZQ4J6W2Q0WJ9V6YV5NPQ4W
nullable: true
source_hris:
type: string
description: ''
example: null
source_hris_id:
type: string
description: ''
example: null
kind:
type: string
description: 'The actor kind (human, agent, robot). Defaults to human when omitted.'
example: human
status:
type: string
description: 'Employment status.'
example: active
enum:
- active
- inactive
nullable: true
fte:
type: number
description: 'Contractual FTE (0.01–3.00). 1.00 = full-time, 0.50 = half-time.'
example: 1.0
position_id:
type: integer
description: 'ID of an existing position to assign. Must exist in positions table for this tenant.'
example: 42
nullable: true
create_placement:
type: boolean
description: 'Whether to automatically create an org unit placement.'
example: true
nullable: true
location:
type: string
description: "The actor's location."
example: 'Dublin, IE'
nullable: true
start_date:
type: string
description: 'The start date. Format: YYYY-MM-DD.'
example: '2025-09-01'
nullable: true
end_date:
type: string
description: 'The end date. Format: YYYY-MM-DD.'
example: '2025-09-30'
nullable: true
manager_id:
type: integer
description: 'nullable The ID of the manager within this tenant.'
example: 2
nullable: true
agent_profile:
type: object
description: 'Agent profile payload (required when kind=agent).'
example:
provider: openai
properties:
provider:
type: string
description: 'Agent provider (openai, anthropic, azure_openai, custom).'
example: openai
nullable: true
orchestrator:
type: string
description: 'Optional orchestrator identifier.'
example: langgraph
nullable: true
meta:
type: object
description: 'Optional structured metadata payload.'
example:
capabilities:
- search
properties: { }
nullable: true
endpoint_base_url:
type: string
description: 'Optional base URL for provider API.'
example: 'https://api.openai.com'
model_default:
type: string
description: 'Default model identifier.'
example: gpt-4.1
nullable: true
required:
- first_name
- last_name
- fte
'/api/v1/actors/{id}':
get:
summary: 'Actors — Show'
operationId: actorsShow
description: "Returns an actor with their primary team resolved from primary org-unit placement (primary=true) within\nthe active scenario context.\n\nRequires a Sanctum token with the `actors.read` ability and an `X-Tenant` header."
parameters:
-
in: query
name: include
description: 'Comma-separated expansions. Allowed: manager,org_units,team,department. The `team`/`department` flags surface computed placement data.'
example: 'manager,team'
required: false
schema:
type: string
description: 'Comma-separated expansions. Allowed: manager,org_units,team,department. The `team`/`department` flags surface computed placement data.'
example: 'manager,team'
-
in: query
name: as_of
description: 'The date/datetime used for time-window checks. Defaults to now.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'The date/datetime used for time-window checks. Defaults to now.'
example: '2025-09-01'
-
in: query
name: scenario_id
description: 'The scenario context to resolve against. Defaults to current (baseline if none).'
example: null
required: false
schema:
type: string
description: 'The scenario context to resolve against. Defaults to current (baseline if none).'
example: null
-
in: query
name: with_counts
description: 'Comma-separated relationship counts. Allowed: reports.'
example: reports
required: false
schema:
type: string
description: 'Comma-separated relationship counts. Allowed: reports.'
example: reports
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 44
first_name: Aoife
last_name: Ryan
name: 'Aoife Ryan'
email: aoife.ryan@example.com
kind: human
status: active
contract_type: perm
fte: 1.0
manager_id: 2
manager:
id: 2
first_name: Brian
last_name: "O'Neil"
name: "Brian O'Neil"
reports_count: 3
team:
id: 15
name: 'Team CúChulainn'
team_type:
id: 3
name: 'Product Squad'
slug: product-squad
department:
id: 3
name: Engineering
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 44
first_name:
type: string
example: Aoife
last_name:
type: string
example: Ryan
name:
type: string
example: 'Aoife Ryan'
email:
type: string
example: aoife.ryan@example.com
kind:
type: string
example: human
status:
type: string
example: active
contract_type:
type: string
example: perm
fte:
type: number
example: 1.0
manager_id:
type: integer
example: 2
manager:
type: object
properties:
id:
type: integer
example: 2
first_name:
type: string
example: Brian
last_name:
type: string
example: "O'Neil"
name:
type: string
example: "Brian O'Neil"
reports_count:
type: integer
example: 3
team:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: 'Product Squad'
slug:
type: string
example: product-squad
department:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Actors
put:
summary: 'Update the specified actor.'
operationId: updateTheSpecifiedActor
description: "Requires `actors.update` ability and an `X-Tenant` header.\nManager must belong to the same tenant and cannot reference the actor themselves."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 44
first_name: Aoife
last_name: Ryan
name: 'Aoife Ryan'
email: aoife.ryan@example.com
kind: human
status: active
fte: 1.0
manager_id: 2
team:
id: 15
name: 'Team CúChulainn'
department:
id: 3
name: Engineering
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 44
first_name:
type: string
example: Aoife
last_name:
type: string
example: Ryan
name:
type: string
example: 'Aoife Ryan'
email:
type: string
example: aoife.ryan@example.com
kind:
type: string
example: human
status:
type: string
example: active
fte:
type: number
example: 1.0
manager_id:
type: integer
example: 2
team:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
department:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Actors
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
first_name:
type: string
description: "The actor's first name. Required for PUT; optional for PATCH (omitted fields keep their current value)."
example: Aoife
last_name:
type: string
description: "The actor's last name. Required for PUT; optional for PATCH."
example: Ryan
email:
type: string
description: 'Optional contact email for the actor. Human actors can remain blank.'
example: aoife.ryan@example.com
nullable: true
external_uid:
type: string
description: 'Durable Orgonaut actor identifier.'
example: 01J9ZQ4J6W2Q0WJ9V6YV5NPQ4W
nullable: true
source_hris:
type: string
description: ''
example: null
source_hris_id:
type: string
description: ''
example: null
kind:
type: string
description: 'The actor kind (immutable once set; updates rejected).'
example: human
status:
type: string
description: 'Employment status.'
example: active
enum:
- active
- inactive
nullable: true
fte:
type: number
description: 'Contractual FTE (0.01–3.00). 1.00 = full-time, 0.50 = half-time. Required for PUT; optional for PATCH.'
example: 1.0
position_id:
type: integer
description: 'ID of an existing position to assign. Must exist in positions table for this tenant.'
example: 42
nullable: true
create_placement:
type: boolean
description: 'Whether to automatically create an org unit placement.'
example: true
nullable: true
location:
type: string
description: "The actor's location."
example: 'Dublin, IE'
nullable: true
start_date:
type: string
description: 'The start date. Format: YYYY-MM-DD.'
example: '2025-09-01'
nullable: true
end_date:
type: string
description: 'The end date. Format: YYYY-MM-DD.'
example: '2025-09-30'
nullable: true
manager_id:
type: integer
description: 'nullable The ID of the manager within this tenant.'
example: 2
nullable: true
agent_profile:
type: object
description: 'Agent profile payload.'
example:
provider: openai
properties:
provider:
type: string
description: 'Agent provider (openai, anthropic, azure_openai, custom).'
example: openai
enum:
- openai
- anthropic
- azure_openai
- custom
nullable: true
orchestrator:
type: string
description: 'Optional orchestrator identifier. Must not be greater than 255 characters.'
example: langgraph
nullable: true
meta:
type: object
description: 'Optional structured metadata payload.'
example:
capabilities:
- search
properties: { }
nullable: true
nullable: true
delete:
summary: 'Remove the specified actor.'
operationId: removeTheSpecifiedActor
description: 'Requires `actors.delete` ability and an `X-Tenant` header.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Actors
parameters:
-
in: path
name: id
description: 'The ID of the actor.'
example: 44
required: true
schema:
type: integer
'/api/v1/actors/{actor_id}/compensations':
get:
summary: 'Actor compensations — List'
operationId: actorCompensationsList
description: "Lists compensation slices for the given actor. When a scenario context is supplied,\nscenario slices are returned alongside baseline fallbacks, ordered with scenario data first.\n\nRequires `actors.read` and `costs.read` abilities."
parameters:
-
in: query
name: scenario_id
description: 'Scenario id to scope results; omit or pass null for baseline only.'
example: 4
required: false
schema:
type: integer
description: 'Scenario id to scope results; omit or pass null for baseline only.'
example: 4
-
in: query
name: as_of
description: 'Date used to flag current slices.'
example: '2025-03-01'
required: false
schema:
type: string
description: 'Date used to flag current slices.'
example: '2025-03-01'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
-
in: query
name: 'fields[actor_compensations]'
description: 'Sparse fieldset.'
example: 'id,currency,base_salary_cents'
required: false
schema:
type: string
description: 'Sparse fieldset.'
example: 'id,currency,base_salary_cents'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
currency: USD
base_salary_cents: 12000000
properties:
data:
type: array
example:
-
id: 1
currency: USD
base_salary_cents: 12000000
items:
type: object
properties:
id:
type: integer
example: 1
currency:
type: string
example: USD
base_salary_cents:
type: integer
example: 12000000
tags:
- Actors
post:
summary: 'Actor compensations — Create'
operationId: actorCompensationsCreate
description: "Stores a new compensation slice for the actor.\n\nRequires `actors.update` ability."
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 9
currency: EUR
daily_rate_cents: 55000
properties:
data:
type: object
properties:
id:
type: integer
example: 9
currency:
type: string
example: EUR
daily_rate_cents:
type: integer
example: 55000
tags:
- Actors
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
scenario_id:
type: integer
description: 'Scenario context; omit or null for baseline actuals. The id of an existing record in the scenarios table.'
example: 3
nullable: true
employment_type:
type: string
description: 'Employment type matching actor records.'
example: Permanent
enum:
- Permanent
- Contractor
currency:
type: string
description: 'Three-letter currency code defined in Settings → Currencies. Must contain only letters. The code of an existing record in the currencies table. Must be 3 characters.'
example: USD
base_salary_cents:
type: integer
description: 'Annual base salary in cents (for FTE). This field is required when daily_rate_cents is not present. Must be at least 0.'
example: 12000000
nullable: true
daily_rate_cents:
type: integer
description: 'Daily contractor rate in cents (for contractors). This field is required when base_salary_cents is not present. Must be at least 0.'
example: 45000
nullable: true
valid_from:
type: string
description: 'Start date for the compensation window (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-01-01'
valid_to:
type: string
description: 'Optional end date for the compensation window (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to valid_from.'
example: '2025-12-31'
nullable: true
meta:
type: object
description: 'Arbitrary metadata to persist alongside the record.'
example:
note: 'Includes sign-on bonus'
properties: { }
nullable: true
required:
- employment_type
- currency
- valid_from
parameters:
-
in: path
name: actor_id
description: 'The ID of the actor.'
example: 11
required: true
schema:
type: integer
-
in: path
name: actor
description: 'The actor identifier.'
example: 11
required: true
schema:
type: integer
'/api/v1/actors/{actor_id}/compensations/{id}':
patch:
summary: 'Actor compensations — Update'
operationId: actorCompensationsUpdate
description: "Updates an existing compensation slice for the actor.\n\nRequires `actors.update` ability."
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: scenario,actor.'
example: scenario
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 9
currency: USD
base_salary_cents: 9900000
properties:
data:
type: object
properties:
id:
type: integer
example: 9
currency:
type: string
example: USD
base_salary_cents:
type: integer
example: 9900000
tags:
- Actors
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
scenario_id:
type: integer
description: 'Scenario context; omit or null for baseline actuals. The id of an existing record in the scenarios table.'
example: 3
nullable: true
employment_type:
type: string
description: 'Employment type matching actor records.'
example: Contractor
enum:
- Permanent
- Contractor
currency:
type: string
description: 'Three-letter currency code defined in Settings → Currencies. Must contain only letters. The code of an existing record in the currencies table. Must be 3 characters.'
example: GBP
base_salary_cents:
type: integer
description: 'Annual base salary in cents (for FTE). This field is required when daily_rate_cents is not present. Must be at least 0.'
example: 9800000
nullable: true
daily_rate_cents:
type: integer
description: 'Daily contractor rate in cents (for contractors). This field is required when base_salary_cents is not present. Must be at least 0.'
example: 60000
nullable: true
valid_from:
type: string
description: 'Start date for the compensation window (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-02-01'
valid_to:
type: string
description: 'Optional end date for the compensation window (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to valid_from.'
example: '2025-09-30'
nullable: true
meta:
type: object
description: 'Arbitrary metadata to persist alongside the record.'
example:
note: 'Updated after promotion'
properties: { }
nullable: true
required:
- employment_type
- currency
- valid_from
delete:
summary: 'Actor compensations — Delete'
operationId: actorCompensationsDelete
description: "Soft deletes a compensation slice.\n\nRequires `actors.delete` ability."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Actors
parameters:
-
in: path
name: actor_id
description: 'The ID of the actor.'
example: 11
required: true
schema:
type: integer
-
in: path
name: id
description: 'The ID of the compensation.'
example: 11
required: true
schema:
type: integer
-
in: path
name: actor
description: 'The actor identifier.'
example: 11
required: true
schema:
type: integer
-
in: path
name: compensation
description: 'The compensation identifier.'
example: 11
required: true
schema:
type: integer
/api/v1/aggregates/recalculate:
post:
summary: 'Queue recalculation of cached aggregates.'
operationId: queueRecalculationOfCachedAggregates
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
status: queued
properties:
status:
type: string
example: queued
tags:
- Aggregates
/api/v1/astro/capabilities:
get:
summary: 'List Astro capabilities for the current tenant, user, and context.'
operationId: listAstroCapabilitiesForTheCurrentTenantUserAndContext
description: ''
parameters:
-
in: query
name: category
description: 'Filter by category key.'
example: work_with_scenarios
required: false
schema:
type: string
description: 'Filter by category key.'
example: work_with_scenarios
-
in: query
name: kind
description: 'Filter by capability kind.'
example: read
required: false
schema:
type: string
description: 'Filter by capability kind.'
example: read
-
in: query
name: availability
description: 'Filter by computed availability.'
example: available
required: false
schema:
type: string
description: 'Filter by computed availability.'
example: available
-
in: query
name: include_unavailable
description: 'Include capabilities that are unavailable in the current context.'
example: false
required: false
schema:
type: boolean
description: 'Include capabilities that are unavailable in the current context.'
example: false
-
in: query
name: view_mode
description: 'Override the current Astro view mode (live, scenario, snapshot).'
example: scenario
required: false
schema:
type: string
description: 'Override the current Astro view mode (live, scenario, snapshot).'
example: scenario
-
in: query
name: scenario_id
description: 'Optional scenario id used for scenario- or snapshot-scoped discovery.'
example: 7
required: false
schema:
type: integer
description: 'Optional scenario id used for scenario- or snapshot-scoped discovery.'
example: 7
-
in: query
name: focused_entity_type
description: 'Optional focused entity type (actor, ai_solution, business_capability, department, org_unit, scenario, team, transformation_case, work_activity).'
example: team
required: false
schema:
type: string
description: 'Optional focused entity type (actor, ai_solution, business_capability, department, org_unit, scenario, team, transformation_case, work_activity).'
example: team
-
in: query
name: focused_entity_id
description: 'Optional focused entity id.'
example: 12
required: false
schema:
type: integer
description: 'Optional focused entity id.'
example: 12
-
in: query
name: as_of
description: 'date Optional as-of date for scoped discovery.'
example: '2026-03-01'
required: false
schema:
type: string
description: 'date Optional as-of date for scoped discovery.'
example: '2026-03-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
key: explore_organisation
title: 'Explore organisation'
description: 'Browse the current organisation structure, departments, teams, and root summaries.'
capabilities:
-
key: explore.organisation
title: 'Explore organisation structure'
kind: read
availability_status: available
meta:
context:
view_mode: live
scope_key: baseline
counts:
available: 5
limited: 2
unavailable: 0
coming_soon: 3
properties:
data:
type: array
example:
-
key: explore_organisation
title: 'Explore organisation'
description: 'Browse the current organisation structure, departments, teams, and root summaries.'
capabilities:
-
key: explore.organisation
title: 'Explore organisation structure'
kind: read
availability_status: available
items:
type: object
properties:
key:
type: string
example: explore_organisation
title:
type: string
example: 'Explore organisation'
description:
type: string
example: 'Browse the current organisation structure, departments, teams, and root summaries.'
capabilities:
type: array
example:
-
key: explore.organisation
title: 'Explore organisation structure'
kind: read
availability_status: available
items:
type: object
properties:
key:
type: string
example: explore.organisation
title:
type: string
example: 'Explore organisation structure'
kind:
type: string
example: read
availability_status:
type: string
example: available
meta:
type: object
properties:
context:
type: object
properties:
view_mode:
type: string
example: live
scope_key:
type: string
example: baseline
counts:
type: object
properties:
available:
type: integer
example: 5
limited:
type: integer
example: 2
unavailable:
type: integer
example: 0
coming_soon:
type: integer
example: 3
tags:
- Astro
'/api/v1/astro/capabilities/{key}':
get:
summary: 'Show one Astro capability for the current tenant, user, and context.'
operationId: showOneAstroCapabilityForTheCurrentTenantUserAndContext
description: ''
parameters:
-
in: query
name: view_mode
description: 'Override the current Astro view mode (live, scenario, snapshot).'
example: scenario
required: false
schema:
type: string
description: 'Override the current Astro view mode (live, scenario, snapshot).'
example: scenario
-
in: query
name: scenario_id
description: 'Optional scenario id used for scenario- or snapshot-scoped discovery.'
example: 7
required: false
schema:
type: integer
description: 'Optional scenario id used for scenario- or snapshot-scoped discovery.'
example: 7
-
in: query
name: focused_entity_type
description: 'Optional focused entity type (actor, ai_solution, business_capability, department, org_unit, scenario, team, transformation_case, work_activity).'
example: team
required: false
schema:
type: string
description: 'Optional focused entity type (actor, ai_solution, business_capability, department, org_unit, scenario, team, transformation_case, work_activity).'
example: team
-
in: query
name: focused_entity_id
description: 'Optional focused entity id.'
example: 12
required: false
schema:
type: integer
description: 'Optional focused entity id.'
example: 12
-
in: query
name: as_of
description: 'date Optional as-of date for scoped discovery.'
example: '2026-03-01'
required: false
schema:
type: string
description: 'date Optional as-of date for scoped discovery.'
example: '2026-03-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
key: explore.organisation
title: 'Explore organisation structure'
kind: read
availability_status: available
examples:
-
prompt: 'List the departments in the current scope.'
properties:
data:
type: object
properties:
key:
type: string
example: explore.organisation
title:
type: string
example: 'Explore organisation structure'
kind:
type: string
example: read
availability_status:
type: string
example: available
examples:
type: array
example:
-
prompt: 'List the departments in the current scope.'
items:
type: object
properties:
prompt:
type: string
example: 'List the departments in the current scope.'
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Capability not found.'
properties:
message:
type: string
example: 'Capability not found.'
tags:
- Astro
parameters:
-
in: path
name: key
description: 'Capability key.'
example: explore.organisation
required: true
schema:
type: string
/api/v1/tokens:
get:
summary: "List the authenticated user's tokens."
operationId: listTheAuthenticatedUsersTokens
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: integer
example: 12
name:
type: string
example: 'CI/CD Bot'
abilities:
type: array
example:
- actors.read
- scenarios.update
items:
type: string
last_used_at:
type: string
example: '2025-08-01T09:30:12Z'
created_at:
type: string
example: '2025-07-15T12:00:00Z'
updated_at:
type: string
example: '2025-08-01T09:30:12Z'
tenant_id:
type: integer
example: 3
example:
-
id: 12
name: 'CI/CD Bot'
abilities:
- actors.read
- scenarios.update
last_used_at: '2025-08-01T09:30:12Z'
created_at: '2025-07-15T12:00:00Z'
updated_at: '2025-08-01T09:30:12Z'
tenant_id: 3
tags:
- Auth/Tokens
post:
summary: 'Issue a new actoral access token.'
operationId: issueANewActoralAccessToken
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug for token scope. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
token: 1|abcdef123456
properties:
token:
type: string
example: 1|abcdef123456
403:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.forbidden
message: Forbidden.
properties:
code:
type: string
example: auth.forbidden
message:
type: string
example: Forbidden.
429:
description: ''
content:
application/json:
schema:
type: object
example:
code: limit.api_tokens
message: 'API token plan limit reached (1/1). Revoke an existing token or upgrade your plan.'
limit: 1
current: 1
properties:
code:
type: string
example: limit.api_tokens
message:
type: string
example: 'API token plan limit reached (1/1). Revoke an existing token or upgrade your plan.'
limit:
type: integer
example: 1
current:
type: integer
example: 1
tags:
- Auth/Tokens
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: 'The email address of the user to authenticate.'
example: loma53@example.com
password:
type: string
description: 'The password of the user to authenticate.'
example: secret-password-123
name:
type: string
description: 'The human-readable label for this token (shown in your account).'
example: 'CI/CD Bot'
abilities:
type: array
description: 'Optional abilities for the token.'
example:
- actors.read
- scenarios.update
items:
type: string
security: []
'/api/v1/tokens/{id}':
delete:
summary: 'Revoke a token.'
operationId: revokeAToken
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Auth/Tokens
patch:
summary: 'Rename a token.'
operationId: renameAToken
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Auth/Tokens
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'New human‑friendly name for the token. Must not be greater than 255 characters.'
example: 'CI bot token'
required:
- name
parameters:
-
in: path
name: id
description: 'The ID of the token.'
example: ab
required: true
schema:
type: string
-
in: path
name: token
description: 'The token ID.'
example: 11
required: true
schema:
type: integer
'/api/v1/tokens/{token}/rotate':
post:
summary: 'Rotate a token.'
operationId: rotateAToken
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
token: 1|abcdef123456
properties:
token:
type: string
example: 1|abcdef123456
tags:
- Auth/Tokens
parameters:
-
in: path
name: token
description: 'The token ID.'
example: 11
required: true
schema:
type: integer
/api/v1/batch:
post:
summary: 'Run several actor, placement, compensation and position writes in one request.'
operationId: runSeveralActorPlacementCompensationAndPositionWritesInOneRequest
description: "Batchable endpoints: create/update/delete actors\n(`/api/v1/actors`, `/api/v1/actors/{id}`), create placements\n(`/api/v1/actors/{id}/placements`), update/delete placements\n(`/api/v1/placements/{id}`), create/update/delete compensations\n(`/api/v1/actors/{id}/compensations[/{id}]`), and create/update/delete\npositions (`/api/v1/positions[/{id}]`; updates must resend `title`, `fte` and\n`valid_from`). Each operation runs through\nits normal endpoint, so it needs the same token abilities, follows the\nsame validation and scenario rules, and is audited the same way. Pass the\nusual `scenario` or `scenario_id` query parameter on the batch request to\nwrite inside a scenario. A batch counts as one request toward rate limits\nand quotas.\n\nLater operations can use results of earlier ones with `{ref:index.dot.path}`,\nfor example `{ref:0.data.id}` for the id of an actor created by operation 0.\nThe path starts inside that operation's response body, so `{ref:0.data.id}`\nreads `results[0].body.data.id`; do not include `body` in the path.\n\nThe response status is 200 when every operation succeeded, 422 when an\natomic batch was rolled back, and 207 when a non-atomic batch partly failed."
parameters:
-
in: query
name: scenario
description: 'Scenario slug to write inside.'
example: fy26-restructure
required: false
schema:
type: string
description: 'Scenario slug to write inside.'
example: fy26-restructure
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
atomic: true
succeeded: 3
failed: 0
rolled_back: false
results:
-
index: 0
method: POST
path: /api/v1/actors
status: 201
body:
data:
id: 501
first_name: Agent
last_name: Triage
-
index: 1
method: POST
path: /api/v1/actors/501/placements
status: 201
body:
data:
id: 9001
org_unit_id: 12
allocation_pct: 100
-
index: 2
method: POST
path: /api/v1/positions
status: 201
body:
data:
id: 730
title: 'AI Operations Lead'
org_unit_team_id: 12
fte: 1
properties:
atomic:
type: boolean
example: true
succeeded:
type: integer
example: 3
failed:
type: integer
example: 0
rolled_back:
type: boolean
example: false
results:
type: array
example:
-
index: 0
method: POST
path: /api/v1/actors
status: 201
body:
data:
id: 501
first_name: Agent
last_name: Triage
-
index: 1
method: POST
path: /api/v1/actors/501/placements
status: 201
body:
data:
id: 9001
org_unit_id: 12
allocation_pct: 100
-
index: 2
method: POST
path: /api/v1/positions
status: 201
body:
data:
id: 730
title: 'AI Operations Lead'
org_unit_team_id: 12
fte: 1
items:
type: object
properties:
index:
type: integer
example: 0
method:
type: string
example: POST
path:
type: string
example: /api/v1/actors
status:
type: integer
example: 201
body:
type: object
properties:
data:
type: object
properties:
id:
type: integer
example: 501
first_name:
type: string
example: Agent
last_name:
type: string
example: Triage
422:
description: ''
content:
application/json:
schema:
type: object
example:
atomic: true
succeeded: 0
failed: 1
rolled_back: true
results:
-
index: 0
method: PATCH
path: /api/v1/actors/44
status: 422
body:
message: 'The fte field must not be greater than 3.'
errors:
fte:
- 'The fte field must not be greater than 3.'
properties:
atomic:
type: boolean
example: true
succeeded:
type: integer
example: 0
failed:
type: integer
example: 1
rolled_back:
type: boolean
example: true
results:
type: array
example:
-
index: 0
method: PATCH
path: /api/v1/actors/44
status: 422
body:
message: 'The fte field must not be greater than 3.'
errors:
fte:
- 'The fte field must not be greater than 3.'
items:
type: object
properties:
index:
type: integer
example: 0
method:
type: string
example: PATCH
path:
type: string
example: /api/v1/actors/44
status:
type: integer
example: 422
body:
type: object
properties:
message:
type: string
example: 'The fte field must not be greater than 3.'
errors:
type: object
properties:
fte:
type: array
example:
- 'The fte field must not be greater than 3.'
items:
type: string
tags:
- Batch
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
atomic:
type: boolean
description: 'When true (default), all operations succeed or none are kept: the first failure rolls back the batch.'
example: true
operations:
type: array
description: 'Up to 200 write operations, run in order. Supported targets: actors, placements, compensations and positions. Position updates (PUT or PATCH /api/v1/positions/{id}) must include title, fte and valid_from alongside the fields that change. Must have at least 1 items. Must not have more than 200 items.'
example:
-
method: POST
path: /api/v1/actors
body:
first_name: Triage
last_name: Agent
email: triage.agent@example.com
fte: 1
-
method: POST
path: '/api/v1/actors/{ref:0.data.id}/placements'
body:
org_unit_id: 12
allocation_pct: 100
primary: true
-
method: POST
path: /api/v1/positions
body:
title: 'AI Operations Lead'
org_unit_team_id: 12
fte: 1
valid_from: '2027-01-01'
-
method: DELETE
path: /api/v1/placements/9001
items:
type: object
properties:
method:
type: string
description: ''
example: POST
enum:
- POST
- PUT
- PATCH
- DELETE
- post
- put
- patch
- delete
path:
type: string
description: 'Must start with one of /api/v1/ Must not be greater than 500 characters.'
example: ipzdszigdqrrkthq
body:
type: object
description: ''
example: null
properties: { }
nullable: true
required:
- method
- path
required:
- operations
/api/v1/capabilities:
get:
summary: 'List capabilities for Live or the `scenario` query context.'
operationId: listCapabilitiesForLiveOrThescenarioQueryContext
description: ''
parameters:
-
in: query
name: scenario
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
required: false
schema:
type: string
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
-
in: query
name: as_of
description: 'date Effective date.'
example: '2026-09-30'
required: false
schema:
type: string
description: 'date Effective date.'
example: '2026-09-30'
-
in: query
name: page
description: 'Page number.'
example: 1
required: false
schema:
type: integer
description: 'Page number.'
example: 1
-
in: query
name: per_page
description: 'Items per page, maximum 100.'
example: 25
required: false
schema:
type: integer
description: 'Items per page, maximum 100.'
example: 25
-
in: query
name: 'fields[capabilities]'
description: 'Sparse top-level fields.'
example: 'definition,state,delta,warnings'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'definition,state,delta,warnings'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'definition,state,delta'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'definition,state,delta'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
'/api/v1/capabilities/{businessCapability_slug}':
get:
summary: 'Show one capability with state, source delta, Work, Solutions, and evidence.'
operationId: showOneCapabilityWithStateSourceDeltaWorkSolutionsAndEvidence
description: ''
parameters:
-
in: query
name: scenario
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
required: false
schema:
type: string
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
-
in: query
name: as_of
description: 'date Effective date.'
example: '2026-09-30'
required: false
schema:
type: string
description: 'date Effective date.'
example: '2026-09-30'
-
in: query
name: 'fields[capabilities]'
description: 'Sparse top-level fields.'
example: 'definition,state,delta,warnings'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'definition,state,delta,warnings'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'definition,state,delta'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'definition,state,delta'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
parameters:
-
in: path
name: businessCapability_slug
description: 'The slug of the businessCapability.'
example: ab
required: true
schema:
type: string
-
in: path
name: businessCapability
description: 'Capability slug.'
example: resolve-customer-exceptions
required: true
schema:
type: string
/api/v1/ai-solutions:
get:
summary: 'List AI solutions and deployments in Live or the `scenario` query context.'
operationId: listAISolutionsAndDeploymentsInLiveOrThescenarioQueryContext
description: 'Cost defaults and forecasts require `transformation-cases.costs.read`.'
parameters:
-
in: query
name: scenario
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
required: false
schema:
type: string
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
-
in: query
name: page
description: 'Page number.'
example: 1
required: false
schema:
type: integer
description: 'Page number.'
example: 1
-
in: query
name: per_page
description: 'Items per page, maximum 100.'
example: 25
required: false
schema:
type: integer
description: 'Items per page, maximum 100.'
example: 25
-
in: query
name: 'fields[solutions]'
description: 'Sparse top-level fields.'
example: 'id,name,lifecycle_status,deployments'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'id,name,lifecycle_status,deployments'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'name,versions,deployments'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'name,versions,deployments'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
'/api/v1/ai-solutions/{aiSolution_slug}':
get:
summary: 'Show one AI solution with governed versions and contextual deployments.'
operationId: showOneAISolutionWithGovernedVersionsAndContextualDeployments
description: ''
parameters:
-
in: query
name: scenario
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
required: false
schema:
type: string
description: 'Scenario slug; omit for Live.'
example: ai-enabled-operating-model
-
in: query
name: 'fields[solutions]'
description: 'Sparse top-level fields.'
example: 'id,name,versions,deployments'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'id,name,versions,deployments'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'name,versions,deployments'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'name,versions,deployments'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
parameters:
-
in: path
name: aiSolution_slug
description: 'The slug of the aiSolution.'
example: 11
required: true
schema:
type: integer
-
in: path
name: aiSolution
description: 'AI solution slug.'
example: customer-exception-copilot
required: true
schema:
type: string
/api/v1/transformation-cases:
get:
summary: 'List tenant-level Transformation Cases.'
operationId: listTenantLevelTransformationCases
description: 'Cost and workforce facts are independently permission-filtered.'
parameters:
-
in: query
name: page
description: 'Page number.'
example: 1
required: false
schema:
type: integer
description: 'Page number.'
example: 1
-
in: query
name: per_page
description: 'Items per page, maximum 100.'
example: 25
required: false
schema:
type: integer
description: 'Items per page, maximum 100.'
example: 25
-
in: query
name: 'fields[transformation-cases]'
description: 'Sparse top-level fields.'
example: 'id,case_key,name,status,readiness,economics'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'id,case_key,name,status,readiness,economics'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'name,readiness,economics'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'name,readiness,economics'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
'/api/v1/transformation-cases/{transformationCase_case_key}':
get:
summary: 'Show one case with readiness, readiness progress, scope, and a client-safe economics summary.'
operationId: showOneCaseWithReadinessReadinessProgressScopeAndAClientSafeEconomicsSummary
description: ''
parameters:
-
in: query
name: 'fields[transformation-cases]'
description: 'Sparse top-level fields.'
example: 'id,case_key,name,status,readiness,economics'
required: false
schema:
type: string
description: 'Sparse top-level fields.'
example: 'id,case_key,name,status,readiness,economics'
-
in: query
name: include
description: 'Comma-separated top-level fields to include.'
example: 'name,readiness,economics'
required: false
schema:
type: string
description: 'Comma-separated top-level fields to include.'
example: 'name,readiness,economics'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug. Example: volkswagen'
schema:
type: string
responses:
401:
description: ''
content:
application/json:
schema:
type: object
example:
code: auth.unauthenticated
message: Unauthenticated.
properties:
code:
type: string
example: auth.unauthenticated
message:
type: string
example: Unauthenticated.
tags:
- 'Capability Studio'
parameters:
-
in: path
name: transformationCase_case_key
description: ''
example: ab
required: true
schema:
type: string
-
in: path
name: transformationCase
description: 'Transformation Case key.'
example: TC-2026-0001
required: true
schema:
type: string
/api/v1/actor-cost-events:
post:
summary: 'Agent Cost Events — Create'
operationId: agentCostEventsCreate
description: "Ingest a machine cost event with idempotency protection. Duplicate idempotency keys\nreturn the existing event instead of creating a new row."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
actor_id: 44
actor_agent_profile_id: 9
org_unit_id: 12
scenario_id: null
occurred_at: '2025-09-01T12:00:00Z'
input_tokens: 1200000
cached_input_tokens: 250000
output_tokens: 640000
total_tokens: 2090000
amount: 18.75
currency: USD
provider: openai
model: gpt-4.1
meta:
refund: false
created_at: '2025-09-02T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 1
actor_id:
type: integer
example: 44
actor_agent_profile_id:
type: integer
example: 9
org_unit_id:
type: integer
example: 12
scenario_id:
type: string
example: null
nullable: true
occurred_at:
type: string
example: '2025-09-01T12:00:00Z'
input_tokens:
type: integer
example: 1200000
cached_input_tokens:
type: integer
example: 250000
output_tokens:
type: integer
example: 640000
total_tokens:
type: integer
example: 2090000
amount:
type: number
example: 18.75
currency:
type: string
example: USD
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1
meta:
type: object
properties:
refund:
type: boolean
example: false
created_at:
type: string
example: '2025-09-02T10:00:00Z'
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
actor_id: 44
actor_agent_profile_id: 9
org_unit_id: 12
scenario_id: null
occurred_at: '2025-09-01T12:00:00Z'
input_tokens: 1200000
cached_input_tokens: 250000
output_tokens: 640000
total_tokens: 2090000
amount: 18.75
currency: USD
provider: openai
model: gpt-4.1
meta:
refund: false
created_at: '2025-09-02T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 1
actor_id:
type: integer
example: 44
actor_agent_profile_id:
type: integer
example: 9
org_unit_id:
type: integer
example: 12
scenario_id:
type: string
example: null
nullable: true
occurred_at:
type: string
example: '2025-09-01T12:00:00Z'
input_tokens:
type: integer
example: 1200000
cached_input_tokens:
type: integer
example: 250000
output_tokens:
type: integer
example: 640000
total_tokens:
type: integer
example: 2090000
amount:
type: number
example: 18.75
currency:
type: string
example: USD
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1
meta:
type: object
properties:
refund:
type: boolean
example: false
created_at:
type: string
example: '2025-09-02T10:00:00Z'
tags:
- Costs
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
occurred_at:
type: string
description: 'Event timestamp (ISO-8601). Must be a valid date.'
example: '2025-09-01T12:00:00Z'
amount:
type: number
description: 'Cost amount in the event currency. Optional when token metrics are provided and central model pricing is configured.'
example: 42.55
nullable: true
currency:
type: string
description: 'Currency code (ISO-4217). Required when amount is provided. Must be 3 characters.'
example: USD
nullable: true
idempotency_key:
type: string
description: 'Unique idempotency key for this event. Must not be greater than 255 characters.'
example: evt_01HX...
actor_id:
type: integer
description: 'Agent actor ID (required). Provider is resolved from the actor profile. The id of an existing record in the actors table.'
example: 44
org_unit_id:
type: integer
description: 'Org unit snapshot attribution (optional). The id of an existing record in the org_units table.'
example: 12
nullable: true
scenario_id:
type: integer
description: 'Optional scenario check; must match the actor profile scenario when provided. The id of an existing record in the scenarios table.'
example: 3
nullable: true
model:
type: string
description: 'Model identifier. Optional when the actor profile has a default model. Must not be greater than 255 characters.'
example: gpt-4.1
nullable: true
input_tokens:
type: integer
description: 'Input token count for the event. Must be at least 0.'
example: 1200000
nullable: true
cached_input_tokens:
type: integer
description: 'Cached input token count for the event. Must be at least 0.'
example: 250000
nullable: true
output_tokens:
type: integer
description: 'Output token count for the event. Must be at least 0.'
example: 640000
nullable: true
meta:
type: object
description: 'Arbitrary structured metadata for the event.'
example:
refund: false
properties: { }
nullable: true
required:
- occurred_at
- idempotency_key
- actor_id
/api/v1/settings/ai/costs:
get:
summary: 'AI Model Costs — List'
operationId: aIModelCostsList
description: 'List tenant-global model pricing rows.'
parameters:
-
in: query
name: sort
description: 'Comma-separated sort list. Allowed: id,provider,model,effective_from,effective_to,created_at. Prefix with `-` for descending order.'
example: '-effective_from,provider'
required: false
schema:
type: string
description: 'Comma-separated sort list. Allowed: id,provider,model,effective_from,effective_to,created_at. Prefix with `-` for descending order.'
example: '-effective_from,provider'
-
in: query
name: 'filter[provider]'
description: 'Filter by provider slug.'
example: openai
required: false
schema:
type: string
description: 'Filter by provider slug.'
example: openai
-
in: query
name: 'filter[model]'
description: 'Filter by model identifier.'
example: gpt-4.1
required: false
schema:
type: string
description: 'Filter by model identifier.'
example: gpt-4.1
-
in: query
name: 'filter[currency]'
description: 'Filter by currency code.'
example: USD
required: false
schema:
type: string
description: 'Filter by currency code.'
example: USD
-
in: query
name: 'fields[ai_model_costs]'
description: 'Sparse fieldset for AI model costs.'
example: 'id,provider,model,currency,is_active'
required: false
schema:
type: string
description: 'Sparse fieldset for AI model costs.'
example: 'id,provider,model,currency,is_active'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 11
provider: openai
model: gpt-4.1
currency: USD
input_mtok_price: 5
cached_input_mtok_price: 0.5
output_mtok_price: 15
effective_from: '2026-01-01'
effective_to: null
is_active: true
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
links:
first: null
last: null
prev: null
next: null
meta:
current_page: 1
last_page: 1
per_page: 1
total: 1
properties:
data:
type: array
example:
-
id: 11
provider: openai
model: gpt-4.1
currency: USD
input_mtok_price: 5
cached_input_mtok_price: 0.5
output_mtok_price: 15
effective_from: '2026-01-01'
effective_to: null
is_active: true
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 11
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1
currency:
type: string
example: USD
input_mtok_price:
type: integer
example: 5
cached_input_mtok_price:
type: number
example: 0.5
output_mtok_price:
type: integer
example: 15
effective_from:
type: string
example: '2026-01-01'
effective_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T09:00:00Z'
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
current_page:
type: integer
example: 1
last_page:
type: integer
example: 1
per_page:
type: integer
example: 1
total:
type: integer
example: 1
tags:
- Costs
post:
summary: 'AI Model Costs — Create'
operationId: aIModelCostsCreate
description: 'Create a tenant-global model pricing row.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 11
provider: openai
model: gpt-4.1
currency: USD
input_mtok_price: 5
cached_input_mtok_price: 0.5
output_mtok_price: 15
effective_from: '2026-01-01'
effective_to: null
is_active: true
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 11
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1
currency:
type: string
example: USD
input_mtok_price:
type: integer
example: 5
cached_input_mtok_price:
type: number
example: 0.5
output_mtok_price:
type: integer
example: 15
effective_from:
type: string
example: '2026-01-01'
effective_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T09:00:00Z'
tags:
- Costs
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
provider:
type: string
description: 'Model provider identifier. Must not be greater than 64 characters.'
example: openai
model:
type: string
description: 'Provider model identifier. Must not be greater than 255 characters.'
example: gpt-4.1
currency:
type: string
description: 'Tenant currency code. Must contain only letters. The code of an existing record in the currencies table. Must be 3 characters.'
example: USD
input_mtok_price:
type: number
description: 'Price per 1M input tokens. Must be at least 0.'
example: 5.0
cached_input_mtok_price:
type: number
description: 'Price per 1M cached input tokens. Must be at least 0.'
example: 0.5
nullable: true
output_mtok_price:
type: number
description: 'Price per 1M output tokens. Must be at least 0.'
example: 15.0
effective_from:
type: string
description: 'Effective start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2026-01-01'
effective_to:
type: string
description: 'Optional effective end date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to effective_from.'
example: '2026-06-30'
nullable: true
required:
- provider
- model
- currency
- input_mtok_price
- output_mtok_price
- effective_from
'/api/v1/settings/ai/costs/{ai_model_cost}':
get:
summary: 'AI Model Costs — Show'
operationId: aIModelCostsShow
description: 'Return a single tenant-global model pricing row.'
parameters:
-
in: query
name: 'fields[ai_model_costs]'
description: 'Sparse fieldset for AI model costs.'
example: 'id,provider,model,currency,is_active'
required: false
schema:
type: string
description: 'Sparse fieldset for AI model costs.'
example: 'id,provider,model,currency,is_active'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 11
provider: openai
model: gpt-4.1
currency: USD
input_mtok_price: 5
cached_input_mtok_price: 0.5
output_mtok_price: 15
effective_from: '2026-01-01'
effective_to: null
is_active: true
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 11
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1
currency:
type: string
example: USD
input_mtok_price:
type: integer
example: 5
cached_input_mtok_price:
type: number
example: 0.5
output_mtok_price:
type: integer
example: 15
effective_from:
type: string
example: '2026-01-01'
effective_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T09:00:00Z'
tags:
- Costs
patch:
summary: 'AI Model Costs — Update'
operationId: aIModelCostsUpdate
description: 'Update a tenant-global model pricing row.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 11
provider: openai
model: gpt-4.1-mini
currency: USD
input_mtok_price: 0.8
cached_input_mtok_price: 0.2
output_mtok_price: 3.2
effective_from: '2026-03-01'
effective_to: null
is_active: true
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T10:15:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 11
provider:
type: string
example: openai
model:
type: string
example: gpt-4.1-mini
currency:
type: string
example: USD
input_mtok_price:
type: number
example: 0.8
cached_input_mtok_price:
type: number
example: 0.2
output_mtok_price:
type: number
example: 3.2
effective_from:
type: string
example: '2026-03-01'
effective_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T10:15:00Z'
tags:
- Costs
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
provider:
type: string
description: 'Model provider identifier. Must not be greater than 64 characters.'
example: openai
model:
type: string
description: 'Provider model identifier. Must not be greater than 255 characters.'
example: gpt-4.1
currency:
type: string
description: 'Tenant currency code. Must contain only letters. The code of an existing record in the currencies table. Must be 3 characters.'
example: USD
input_mtok_price:
type: number
description: 'Price per 1M input tokens. Must be at least 0.'
example: 5.0
cached_input_mtok_price:
type: number
description: 'Price per 1M cached input tokens. Must be at least 0.'
example: 0.5
nullable: true
output_mtok_price:
type: number
description: 'Price per 1M output tokens. Must be at least 0.'
example: 15.0
effective_from:
type: string
description: 'Effective start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2026-01-01'
effective_to:
type: string
description: 'Optional effective end date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to effective_from.'
example: '2026-06-30'
nullable: true
required:
- provider
- model
- currency
- input_mtok_price
- output_mtok_price
- effective_from
delete:
summary: 'AI Model Costs — Delete'
operationId: aIModelCostsDelete
description: 'Delete a tenant-global model pricing row.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Costs
parameters:
-
in: path
name: ai_model_cost
description: 'The AI model cost row id.'
example: 11
required: true
schema:
type: integer
/api/v1/department-types/search:
get:
summary: 'Return the top matching Department Types for the active tenant.'
operationId: returnTheTopMatchingDepartmentTypesForTheActiveTenant
description: 'Requires `departments.read` ability.'
parameters:
-
in: query
name: q
description: 'Search term applied to name and slug.'
example: ops
required: false
schema:
type: string
description: 'Search term applied to name and slug.'
example: ops
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Operations
slug:
type: string
example: operations
color:
type: string
example: '#008080'
example:
-
id: 1
name: Operations
slug: operations
color: '#008080'
tags:
- 'Department Types'
/api/v1/department-types:
post:
summary: 'Create a Department Type for the active tenant.'
operationId: createADepartmentTypeForTheActiveTenant
description: 'Requires `departments.create` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
id: 3
name: Operations
slug: operations
color: '#008080'
properties:
id:
type: integer
example: 3
name:
type: string
example: Operations
slug:
type: string
example: operations
color:
type: string
example: '#008080'
tags:
- 'Department Types'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name.'
example: Operations
slug:
type: string
description: 'Optional custom slug; defaults to a slugified name.'
example: ops
nullable: true
color:
type: string
description: 'Optional hex colour (with or without #).'
example: '#008080'
nullable: true
description:
type: string
description: 'Optional description of the classification.'
example: 'Supports company-wide services'
nullable: true
required:
- name
'/api/v1/department-types/{departmentType_id}':
get:
summary: 'Show a specific Department Type.'
operationId: showASpecificDepartmentType
description: 'Requires `departments.read` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: Operations
slug: operations
color: '#008080'
description: null
is_active: true
display_order: 0
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Operations
slug:
type: string
example: operations
color:
type: string
example: '#008080'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 0
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
tags:
- 'Department Types'
patch:
summary: 'Update a Department Type.'
operationId: updateADepartmentType
description: 'Requires `settings.manage` ability. All fields are optional for partial updates.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: Enablement
slug: enablement
color: '#008080'
description: null
is_active: true
display_order: 0
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Enablement
slug:
type: string
example: enablement
color:
type: string
example: '#008080'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 0
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The name has already been taken.'
errors:
name:
- 'The name has already been taken.'
properties:
message:
type: string
example: 'The name has already been taken.'
errors:
type: object
properties:
name:
type: array
example:
- 'The name has already been taken.'
items:
type: string
tags:
- 'Department Types'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name. Max 120 characters. Must be unique within the tenant.'
example: Enablement
slug:
type: string
description: 'URL-safe slug. Auto-derived from name if omitted on create; not auto-updated on edit. Max 120 characters. Must be unique within the tenant.'
example: enablement
nullable: true
color:
type: string
description: 'Hex colour code with or without leading `#`.'
example: '#008080'
nullable: true
description:
type: string
description: 'Optional description. Max 500 characters.'
example: 'Supports company-wide services'
nullable: true
is_active:
type: boolean
description: 'Whether the type is active.'
example: true
display_order:
type: integer
description: 'Sort order for selectors. Between 0 and 999.'
example: 1
nullable: true
delete:
summary: 'Delete a Department Type.'
operationId: deleteADepartmentType
description: "Requires `settings.manage` ability. Associated departments will have their\n`department_type_id` set to null on delete."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
tags:
- 'Department Types'
parameters:
-
in: path
name: departmentType_id
description: 'The ID of the departmentType.'
example: 11
required: true
schema:
type: integer
-
in: path
name: departmentType
description: 'The ID of the department type.'
example: 1
required: true
schema:
type: integer
/api/v1/departments:
get:
summary: 'Display a paginated listing of departments.'
operationId: displayAPaginatedListingOfDepartments
description: 'Requires `departments.read` ability.'
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: scenario
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
required: false
schema:
type: string
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
-
in: query
name: 'filter[scenario_id]'
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
required: false
schema:
type: string
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
-
in: query
name: 'filter[scenario]'
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
required: false
schema:
type: string
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
-
in: query
name: 'filter[lead_id]'
description: 'Filter by lead.'
example: 44
required: false
schema:
type: integer
description: 'Filter by lead.'
example: 44
-
in: query
name: 'fields[departments]'
description: 'Sparse fields for departments.'
example: 'id,name,department_type_id'
required: false
schema:
type: string
description: 'Sparse fields for departments.'
example: 'id,name,department_type_id'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: lead,departmentType,parentDepartment,aggregate.'
example: 'lead,departmentType'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: lead,departmentType,parentDepartment,aggregate.'
example: 'lead,departmentType'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 3
name: Engineering
lead_id: 44
cost_center: ENG-001
department_type_id: 7
department_type:
id: 7
name: Division
slug: division
color: '#0052cc'
parent_org_unit_id: 202
parent_department_id: 2
parent_department:
id: 2
name: Product
scenario_id: 1
is_active: true
description: 'Platform engineering for core services.'
created_at: '2025-01-10T09:00:00Z'
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 3
name: Engineering
lead_id: 44
cost_center: ENG-001
department_type_id: 7
department_type:
id: 7
name: Division
slug: division
color: '#0052cc'
parent_org_unit_id: 202
parent_department_id: 2
parent_department:
id: 2
name: Product
scenario_id: 1
is_active: true
description: 'Platform engineering for core services.'
created_at: '2025-01-10T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
lead_id:
type: integer
example: 44
cost_center:
type: string
example: ENG-001
department_type_id:
type: integer
example: 7
department_type:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: Division
slug:
type: string
example: division
color:
type: string
example: '#0052cc'
parent_org_unit_id:
type: integer
example: 202
parent_department_id:
type: integer
example: 2
parent_department:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Product
scenario_id:
type: integer
example: 1
is_active:
type: boolean
example: true
description:
type: string
example: 'Platform engineering for core services.'
created_at:
type: string
example: '2025-01-10T09:00:00Z'
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- name
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- name
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- Departments
post:
summary: 'Store a newly created department.'
operationId: storeANewlyCreatedDepartment
description: "Requires `departments.create` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 3
name: Engineering
lead_id: 44
cost_center: ENG-001
department_type_id: 7
department_type:
id: 7
name: Division
slug: division
color: '#0052cc'
parent_org_unit_id: 202
parent_department_id: null
parent_department: null
scenario_id: 1
is_active: true
description: 'Owns platform reliability.'
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
lead_id:
type: integer
example: 44
cost_center:
type: string
example: ENG-001
department_type_id:
type: integer
example: 7
department_type:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: Division
slug:
type: string
example: division
color:
type: string
example: '#0052cc'
parent_org_unit_id:
type: integer
example: 202
parent_department_id:
type: string
example: null
nullable: true
parent_department:
type: string
example: null
nullable: true
scenario_id:
type: integer
example: 1
is_active:
type: boolean
example: true
description:
type: string
example: 'Owns platform reliability.'
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Departments
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Department name (unique per tenant and scenario). Must not be greater than 255 characters.'
example: Engineering
department_type_id:
type: integer
description: 'Department type identifier. The id of an existing record in the department_types table.'
example: 5
parent_org_unit_id:
type: integer
description: 'Optional parent org unit id.'
example: 42
nullable: true
cost_center:
type: string
description: 'Optional cost center code. Must not be greater than 50 characters.'
example: ENG-1001
nullable: true
department_lead_id:
type: integer
description: 'Actor id of department lead.'
example: 44
nullable: true
is_active:
type: boolean
description: 'Whether the department is active.'
example: true
nullable: true
description:
type: string
description: 'Optional department description.'
example: 'Supports the full product org.'
nullable: true
required:
- name
- department_type_id
'/api/v1/departments/{id}':
get:
summary: 'Display a specific department.'
operationId: displayASpecificDepartment
description: 'Requires `departments.read` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 3
name: Engineering
lead_id: 44
cost_center: ENG-001
department_type_id: 7
department_type:
id: 7
name: Division
slug: division
color: '#0052cc'
parent_org_unit_id: 202
parent_department_id: 2
parent_department:
id: 2
name: Product
scenario_id: 1
is_active: true
description: 'Platform engineering for core services.'
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineering
lead_id:
type: integer
example: 44
cost_center:
type: string
example: ENG-001
department_type_id:
type: integer
example: 7
department_type:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: Division
slug:
type: string
example: division
color:
type: string
example: '#0052cc'
parent_org_unit_id:
type: integer
example: 202
parent_department_id:
type: integer
example: 2
parent_department:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Product
scenario_id:
type: integer
example: 1
is_active:
type: boolean
example: true
description:
type: string
example: 'Platform engineering for core services.'
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Departments
put:
summary: 'Update a department.'
operationId: updateADepartment
description: "Requires `departments.update` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 3
name: 'Engineering & Infrastructure'
lead_id: 44
cost_center: ENG-001
department_type_id: 7
department_type:
id: 7
name: Division
slug: division
color: '#0052cc'
parent_org_unit_id: 202
parent_department_id: 2
parent_department:
id: 2
name: Product
scenario_id: 1
is_active: true
description: 'Platform engineering for core services.'
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: 'Engineering & Infrastructure'
lead_id:
type: integer
example: 44
cost_center:
type: string
example: ENG-001
department_type_id:
type: integer
example: 7
department_type:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: Division
slug:
type: string
example: division
color:
type: string
example: '#0052cc'
parent_org_unit_id:
type: integer
example: 202
parent_department_id:
type: integer
example: 2
parent_department:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Product
scenario_id:
type: integer
example: 1
is_active:
type: boolean
example: true
description:
type: string
example: 'Platform engineering for core services.'
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Departments
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Department name when changing department metadata (unique per tenant and scenario). Must not be greater than 255 characters.'
example: Engineering
department_type_id:
type: integer
description: 'Department type identifier when changing department metadata. The id of an existing record in the department_types table.'
example: 5
parent_org_unit_id:
type: integer
description: 'Optional parent org unit id.'
example: 42
nullable: true
department_lead_id:
type: integer
description: 'Actor id of department lead.'
example: 44
nullable: true
cost_center:
type: string
description: 'Optional cost center code. Must not be greater than 50 characters.'
example: ENG-1001
nullable: true
is_active:
type: boolean
description: 'Whether the department is active.'
example: true
nullable: true
description:
type: string
description: 'Optional department description.'
example: 'Supports the full product org.'
nullable: true
delete:
summary: 'Delete a department.'
operationId: deleteADepartment
description: "Requires `departments.delete` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Departments
parameters:
-
in: path
name: id
description: 'The ID of the department.'
example: 11
required: true
schema:
type: integer
/api/v1/initiatives:
get:
summary: 'Display a paginated listing of initiatives.'
operationId: displayAPaginatedListingOfInitiatives
description: 'Requires `initiatives.read` ability.'
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,title,created_at.'
example: '-created_at,title'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,title,created_at.'
example: '-created_at,title'
-
in: query
name: search
description: 'Search by title or description.'
example: cost
required: false
schema:
type: string
description: 'Search by title or description.'
example: cost
-
in: query
name: 'filter[status]'
description: 'Filter by status.'
example: active
required: false
schema:
type: string
description: 'Filter by status.'
example: active
-
in: query
name: 'filter[baseline_scenario_id]'
description: 'Filter by baseline scenario.'
example: 1
required: false
schema:
type: integer
description: 'Filter by baseline scenario.'
example: 1
-
in: query
name: 'filter[target_scenario_id]'
description: 'Filter by target scenario.'
example: 2
required: false
schema:
type: integer
description: 'Filter by target scenario.'
example: 2
-
in: query
name: 'fields[initiatives]'
description: 'Sparse fields for initiatives.'
example: 'id,title'
required: false
schema:
type: string
description: 'Sparse fields for initiatives.'
example: 'id,title'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
title: 'Cost Reduction'
description: 'Reduce infrastructure spend by 15%'
status: active
baseline_scenario_id: 1
target_scenario_id: 2
created_at: '2025-01-10T09:00:00Z'
updated_at: '2025-01-10T09:00:00Z'
-
id: 2
title: 'Mobile Workforce Rollout'
description: null
status: draft
baseline_scenario_id: 1
target_scenario_id: 3
created_at: '2025-01-11T10:00:00Z'
updated_at: '2025-01-11T10:00:00Z'
links:
first: null
last: null
prev: null
next: null
meta:
total: 2
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 1
title: 'Cost Reduction'
description: 'Reduce infrastructure spend by 15%'
status: active
baseline_scenario_id: 1
target_scenario_id: 2
created_at: '2025-01-10T09:00:00Z'
updated_at: '2025-01-10T09:00:00Z'
-
id: 2
title: 'Mobile Workforce Rollout'
description: null
status: draft
baseline_scenario_id: 1
target_scenario_id: 3
created_at: '2025-01-11T10:00:00Z'
updated_at: '2025-01-11T10:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: 'Cost Reduction'
description:
type: string
example: 'Reduce infrastructure spend by 15%'
status:
type: string
example: active
baseline_scenario_id:
type: integer
example: 1
target_scenario_id:
type: integer
example: 2
created_at:
type: string
example: '2025-01-10T09:00:00Z'
updated_at:
type: string
example: '2025-01-10T09:00:00Z'
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 2
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- title
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- title
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- Initiatives
post:
summary: 'Store a newly created initiative.'
operationId: storeANewlyCreatedInitiative
description: 'Requires `initiatives.create` ability.'
parameters:
-
in: query
name: 'fields[initiatives]'
description: 'Sparse fields for initiatives.'
example: 'id,title'
required: false
schema:
type: string
description: 'Sparse fields for initiatives.'
example: 'id,title'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
title: 'Cost Reduction'
description: 'Reduce infrastructure spend by 15%'
status: active
baseline_scenario_id: 1
target_scenario_id: 2
created_at: '2025-01-10T09:00:00Z'
updated_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: 'Cost Reduction'
description:
type: string
example: 'Reduce infrastructure spend by 15%'
status:
type: string
example: active
baseline_scenario_id:
type: integer
example: 1
target_scenario_id:
type: integer
example: 2
created_at:
type: string
example: '2025-01-10T09:00:00Z'
updated_at:
type: string
example: '2025-01-10T09:00:00Z'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
title:
- 'The title field is required.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
title:
type: array
example:
- 'The title field is required.'
items:
type: string
tags:
- Initiatives
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description: 'Initiative title. Must not be greater than 255 characters.'
example: 'Reduce Cloud Spend'
description:
type: string
description: 'Optional summary/description.'
example: 'Target a 15% reduction by Q4.'
nullable: true
status:
type: string
description: 'Lifecycle status (draft, active, paused, completed).'
example: active
enum:
- draft
- active
- paused
- completed
baseline_scenario_id:
type: integer
description: 'Baseline scenario id. The id of an existing record in the scenarios table.'
example: 1
nullable: true
target_scenario_id:
type: integer
description: 'Target scenario id. The id of an existing record in the scenarios table.'
example: 2
nullable: true
required:
- title
- status
'/api/v1/initiatives/{id}':
get:
summary: 'Display a specific initiative.'
operationId: displayASpecificInitiative
description: 'Requires `initiatives.read` ability.'
parameters:
-
in: query
name: 'fields[initiatives]'
description: 'Sparse fields for initiatives.'
example: 'id,title'
required: false
schema:
type: string
description: 'Sparse fields for initiatives.'
example: 'id,title'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
title: 'Cost Reduction'
description: 'Reduce infrastructure spend by 15%'
status: active
baseline_scenario_id: 1
target_scenario_id: 2
baseline_scenario:
id: 1
name: 'Current State'
status: published
target_scenario:
id: 2
name: 'Optimized State'
status: draft
created_at: '2025-01-10T09:00:00Z'
updated_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: 'Cost Reduction'
description:
type: string
example: 'Reduce infrastructure spend by 15%'
status:
type: string
example: active
baseline_scenario_id:
type: integer
example: 1
target_scenario_id:
type: integer
example: 2
baseline_scenario:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'Current State'
status:
type: string
example: published
target_scenario:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: 'Optimized State'
status:
type: string
example: draft
created_at:
type: string
example: '2025-01-10T09:00:00Z'
updated_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Initiatives
put:
summary: 'Update a specific initiative.'
operationId: updateASpecificInitiative
description: 'Requires `initiatives.update` ability.'
parameters:
-
in: query
name: 'fields[initiatives]'
description: 'Sparse fields for initiatives.'
example: 'id,title'
required: false
schema:
type: string
description: 'Sparse fields for initiatives.'
example: 'id,title'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: baseline_scenario,target_scenario.'
example: 'baseline_scenario,target_scenario'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
title: 'Cost Optimization'
description: 'Reduce infrastructure spend by 20%'
status: active
baseline_scenario_id: 1
target_scenario_id: 2
created_at: '2025-01-10T09:00:00Z'
updated_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: 'Cost Optimization'
description:
type: string
example: 'Reduce infrastructure spend by 20%'
status:
type: string
example: active
baseline_scenario_id:
type: integer
example: 1
target_scenario_id:
type: integer
example: 2
created_at:
type: string
example: '2025-01-10T09:00:00Z'
updated_at:
type: string
example: '2025-01-10T09:00:00Z'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
status:
- 'The selected status is invalid.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
status:
type: array
example:
- 'The selected status is invalid.'
items:
type: string
tags:
- Initiatives
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description: 'Initiative title. Must not be greater than 255 characters.'
example: 'Reduce Cloud Spend'
description:
type: string
description: 'Optional summary/description.'
example: 'Target a 15% reduction by Q4.'
nullable: true
status:
type: string
description: 'Lifecycle status (draft, active, paused, completed).'
example: paused
enum:
- draft
- active
- paused
- completed
baseline_scenario_id:
type: integer
description: 'Baseline scenario id. The id of an existing record in the scenarios table.'
example: 1
nullable: true
target_scenario_id:
type: integer
description: 'Target scenario id. The id of an existing record in the scenarios table.'
example: 2
nullable: true
required:
- title
- status
delete:
summary: 'Delete a specific initiative.'
operationId: deleteASpecificInitiative
description: 'Requires `initiatives.delete` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Initiatives
parameters:
-
in: path
name: id
description: 'The ID of the initiative.'
example: 11
required: true
schema:
type: integer
'/api/v1/integrations/bamboohr/webhook/{tenant}':
post:
summary: 'Receive BambooHR webhook payload.'
operationId: receiveBambooHRWebhookPayload
description: "This endpoint always responds quickly. When the tenant is missing, the plan\ndoes not include HRIS integrations, or webhook auth fails, it still returns\n`202 Accepted` without queueing sync work."
parameters: []
responses:
202:
description: ''
content:
application/json:
schema:
type: object
example:
status: accepted
properties:
status:
type: string
example: accepted
tags:
- Integrations
security: []
parameters:
-
in: path
name: tenant
description: 'Tenant slug.'
example: demo
required: true
schema:
type: string
/api/v1/lineage:
get:
summary: 'List baseline lineage events (promotions + snapshot restores).'
operationId: listBaselineLineageEventspromotions+SnapshotRestores
description: ''
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: 'filter[type]'
description: 'Filter by lineage type (scenario_promotion, snapshot_restore).'
example: scenario_promotion
required: false
schema:
type: string
description: 'Filter by lineage type (scenario_promotion, snapshot_restore).'
example: scenario_promotion
-
in: query
name: 'filter[scenario_id]'
description: 'Filter by related scenario id (promoted/applied/archived).'
example: 42
required: false
schema:
type: integer
description: 'Filter by related scenario id (promoted/applied/archived).'
example: 42
-
in: query
name: 'filter[applied_from]'
description: 'date Filter by applied_at date (inclusive, YYYY-MM-DD).'
example: '2025-01-01'
required: false
schema:
type: string
description: 'date Filter by applied_at date (inclusive, YYYY-MM-DD).'
example: '2025-01-01'
-
in: query
name: 'filter[applied_to]'
description: 'date Filter by applied_at date (inclusive, YYYY-MM-DD).'
example: '2025-12-31'
required: false
schema:
type: string
description: 'date Filter by applied_at date (inclusive, YYYY-MM-DD).'
example: '2025-12-31'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
type: scenario_promotion
applied_at: '2026-01-30T12:00:00Z'
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 1
type: scenario_promotion
applied_at: '2026-01-30T12:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 1
type:
type: string
example: scenario_promotion
applied_at:
type: string
example: '2026-01-30T12:00:00Z'
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
tags:
- Lineage
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
page:
type: integer
description: 'Must be at least 1.'
example: 61
per_page:
type: integer
description: 'Must be at least 1. Must not be greater than 100.'
example: 7
filter:
type: object
description: ''
example: []
properties:
type:
type: string
description: ''
example: scenario_promotion
enum:
- scenario_promotion
- snapshot_restore
nullable: true
scenario_id:
type: integer
description: ''
example: 11
nullable: true
applied_from:
type: string
description: 'Must be a valid date.'
example: '2026-10-11T21:57:37'
nullable: true
applied_to:
type: string
description: 'Must be a valid date.'
example: '2026-10-11T21:57:37'
nullable: true
'/api/v1/actors/{actor_id}/placements':
get:
summary: 'Actor placements — List'
operationId: actorPlacementsList
description: "Return placements for an actor as of a date. By default only active placements\nare returned; pass `include_history=1` to include historical rows as well.\n\nRequires `placements.read` ability."
parameters:
-
in: query
name: as_of
description: 'Filter placements active on this ISO 8601 date.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Filter placements active on this ISO 8601 date.'
example: '2025-09-01'
-
in: query
name: include_history
description: 'Include historical placements in addition to the active set.'
example: true
required: false
schema:
type: boolean
description: 'Include historical placements in addition to the active set.'
example: true
-
in: query
name: scenario_id
description: 'Scenario slug or id to scope placements; omit or pass `null` for baseline.'
example: future-plan
required: false
schema:
type: string
description: 'Scenario slug or id to scope placements; omit or pass `null` for baseline.'
example: future-plan
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: 'actor,org_unit'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: 'actor,org_unit'
-
in: query
name: 'fields[placements]'
description: 'Sparse fieldset.'
example: 'id,org_unit_id,valid_from,valid_to'
required: false
schema:
type: string
description: 'Sparse fieldset.'
example: 'id,org_unit_id,valid_from,valid_to'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
actor_id: 42
org_unit_id: 10
scenario_id: null
primary: true
allocation_pct: 100
fte: 1.0
valid_from: '2025-01-01'
valid_to: null
is_active: true
properties:
data:
type: array
example:
-
id: 1
actor_id: 42
org_unit_id: 10
scenario_id: null
primary: true
allocation_pct: 100
fte: 1
valid_from: '2025-01-01'
valid_to: null
is_active: true
items:
type: object
properties:
id:
type: integer
example: 1
actor_id:
type: integer
example: 42
org_unit_id:
type: integer
example: 10
scenario_id:
type: string
example: null
nullable: true
primary:
type: boolean
example: true
allocation_pct:
type: integer
example: 100
fte:
type: number
example: 1.0
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
tags:
- 'Org Placements'
post:
summary: 'Actor placements — Create'
operationId: actorPlacementsCreate
description: "Creates a new placement for the given actor.\n\nRequires `placements.write` ability."
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: org_unit
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: org_unit
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 9
actor_id: 11
org_unit_id: 10
scenario_id: null
primary: false
allocation_pct: 60
fte: 0.6
valid_from: '2025-09-01'
valid_to: null
is_active: true
properties:
data:
type: object
properties:
id:
type: integer
example: 9
actor_id:
type: integer
example: 11
org_unit_id:
type: integer
example: 10
scenario_id:
type: string
example: null
nullable: true
primary:
type: boolean
example: false
allocation_pct:
type: integer
example: 60
fte:
type: number
example: 0.6
valid_from:
type: string
example: '2025-09-01'
valid_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
tags:
- 'Org Placements'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
org_unit_id:
type: integer
description: 'Org unit receiving the placement.'
example: 10
scenario_id:
type: integer
description: 'Scenario context for the placement; defaults to the org unit scenario.'
example: 4
nullable: true
primary:
type: boolean
description: 'Mark as the primary placement.'
example: true
allocation_pct:
type: integer
description: "Percentage of the actor's time for this team (0–300). Totals across placements may exceed 100% (over-allocation is allowed)."
example: 60
valid_from:
type: string
description: 'Start date (YYYY-MM-DD).'
example: '2025-09-01'
nullable: true
valid_to:
type: string
description: 'End date (YYYY-MM-DD).'
example: '2025-12-31'
nullable: true
source:
type: string
description: 'Source identifier for auditing.'
example: manual
nullable: true
meta:
type: object
description: 'Additional metadata payload.'
example: []
properties: { }
nullable: true
required:
- org_unit_id
- allocation_pct
parameters:
-
in: path
name: actor_id
description: 'The ID of the actor.'
example: 11
required: true
schema:
type: integer
-
in: path
name: actor
description: 'The actor identifier.'
example: 11
required: true
schema:
type: integer
'/api/v1/placements/{id}':
patch:
summary: 'Actor placements — Update'
operationId: actorPlacementsUpdate
description: "Updates an existing placement.\n\nRequires `placements.write` ability."
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: actor
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: actor
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 9
actor_id: 11
org_unit_id: 12
scenario_id: null
primary: false
allocation_pct: 50
fte: 0.5
valid_from: '2025-06-01'
valid_to: '2025-09-30'
is_active: false
properties:
data:
type: object
properties:
id:
type: integer
example: 9
actor_id:
type: integer
example: 11
org_unit_id:
type: integer
example: 12
scenario_id:
type: string
example: null
nullable: true
primary:
type: boolean
example: false
allocation_pct:
type: integer
example: 50
fte:
type: number
example: 0.5
valid_from:
type: string
example: '2025-06-01'
valid_to:
type: string
example: '2025-09-30'
is_active:
type: boolean
example: false
tags:
- 'Org Placements'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
org_unit_id:
type: integer
description: 'Org unit receiving the placement.'
example: 12
scenario_id:
type: integer
description: 'Scenario context for the placement; defaults to the current value.'
example: 4
nullable: true
primary:
type: boolean
description: 'Mark as the primary placement.'
example: false
allocation_pct:
type: integer
description: "Percentage of the actor's time for this team (0–300). Totals across placements may exceed 100% (over-allocation is allowed)."
example: 50
valid_from:
type: string
description: 'Start date (YYYY-MM-DD).'
example: '2025-06-01'
nullable: true
valid_to:
type: string
description: 'End date (YYYY-MM-DD).'
example: '2025-09-30'
nullable: true
source:
type: string
description: 'Source identifier for auditing.'
example: manual
nullable: true
meta:
type: object
description: 'Additional metadata payload.'
example: []
properties: { }
nullable: true
delete:
summary: 'Actor placements — End'
operationId: actorPlacementsEnd
description: "Ends a placement by stamping the `valid_to` date. Omitting the\n`valid_to` query parameter defaults to today.\n\nRequires `placements.delete` ability."
parameters:
-
in: query
name: valid_to
description: 'Date to end the placement on (YYYY-MM-DD). Defaults to today.'
example: '2025-10-01'
required: false
schema:
type: string
description: 'Date to end the placement on (YYYY-MM-DD). Defaults to today.'
example: '2025-10-01'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: org_unit
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: org_unit
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 9
actor_id: 11
org_unit_id: 12
scenario_id: null
primary: false
allocation_pct: 50
fte: 0.5
valid_from: '2025-06-01'
valid_to: '2025-10-01'
is_active: false
properties:
data:
type: object
properties:
id:
type: integer
example: 9
actor_id:
type: integer
example: 11
org_unit_id:
type: integer
example: 12
scenario_id:
type: string
example: null
nullable: true
primary:
type: boolean
example: false
allocation_pct:
type: integer
example: 50
fte:
type: number
example: 0.5
valid_from:
type: string
example: '2025-06-01'
valid_to:
type: string
example: '2025-10-01'
is_active:
type: boolean
example: false
tags:
- 'Org Placements'
parameters:
-
in: path
name: id
description: 'The ID of the placement.'
example: 11
required: true
schema:
type: integer
-
in: path
name: placement
description: 'Placement identifier.'
example: 11
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit_id}/actors':
get:
summary: 'Org unit roster — List'
operationId: orgUnitRosterList
description: "Lists active placements for the specified org unit. Results default to placements\nactive today but may be scoped to a different date using `as_of`.\n\nRequires `placements.read` ability."
parameters:
-
in: query
name: as_of
description: 'Date used to evaluate active placements.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Date used to evaluate active placements.'
example: '2025-09-01'
-
in: query
name: scenario_id
description: 'Scenario slug or id to scope placements; omit or pass `null` for baseline.'
example: future-plan
required: false
schema:
type: string
description: 'Scenario slug or id to scope placements; omit or pass `null` for baseline.'
example: future-plan
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: actor
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: actor,org_unit.'
example: actor
-
in: query
name: 'fields[placements]'
description: 'Sparse fieldset.'
example: 'id,actor_id,allocation_pct'
required: false
schema:
type: string
description: 'Sparse fieldset.'
example: 'id,actor_id,allocation_pct'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 7
actor:
id: 14
name: "Aisling O'Neill"
allocation_pct: 100
fte: 1
valid_from: '2025-07-01'
valid_to: null
is_active: true
properties:
data:
type: array
example:
-
id: 7
actor:
id: 14
name: "Aisling O'Neill"
allocation_pct: 100
fte: 1
valid_from: '2025-07-01'
valid_to: null
is_active: true
items:
type: object
properties:
id:
type: integer
example: 7
actor:
type: object
properties:
id:
type: integer
example: 14
name:
type: string
example: "Aisling O'Neill"
allocation_pct:
type: integer
example: 100
fte:
type: integer
example: 1
valid_from:
type: string
example: '2025-07-01'
valid_to:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
tags:
- 'Org Placements'
parameters:
-
in: path
name: org_unit_id
description: 'The ID of the org unit.'
example: 11
required: true
schema:
type: integer
-
in: path
name: org_unit
description: 'The org unit identifier.'
example: 11
required: true
schema:
type: integer
/api/v1/org-units:
get:
summary: 'Display a paginated listing of org units.'
operationId: displayAPaginatedListingOfOrgUnits
description: ''
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: scenario
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
required: false
schema:
type: string
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
-
in: query
name: 'filter[scenario_id]'
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
required: false
schema:
type: string
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
-
in: query
name: 'filter[scenario]'
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
required: false
schema:
type: string
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,label,created_at.'
example: '-created_at,label'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,label,created_at.'
example: '-created_at,label'
-
in: query
name: 'filter[type]'
description: 'Filter by the org unit type (string). Typical values include node, team, and department. Other values may appear if inserted in data.'
example: node
required: false
schema:
type: string
description: 'Filter by the org unit type (string). Typical values include node, team, and department. Other values may appear if inserted in data.'
example: node
-
in: query
name: 'filter[parent_id]'
description: 'Filter by parent org unit ID.'
example: 42
required: false
schema:
type: integer
description: 'Filter by parent org unit ID.'
example: 42
-
in: query
name: 'fields[org_units]'
description: 'Sparse fields for org units.'
example: 'id,label'
required: false
schema:
type: string
description: 'Sparse fields for org units.'
example: 'id,label'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: scenario,actors,metrics.'
example: 'scenario,actors,metrics'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: scenario,actors,metrics.'
example: 'scenario,actors,metrics'
-
in: query
name: as_of
description: 'date Filter actors memberships or metrics by date. Format: YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'date Filter actors memberships or metrics by date. Format: YYYY-MM-DD.'
example: '2025-09-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 202
type: node
entity_id: 4102
label: 'Retail – Ireland'
scenario_id: 1
parent_id: 101
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 202
type: node
entity_id: 4102
label: 'Retail – Ireland'
scenario_id: 1
parent_id: 101
items:
type: object
properties:
id:
type: integer
example: 202
type:
type: string
example: node
entity_id:
type: integer
example: 4102
label:
type: string
example: 'Retail – Ireland'
scenario_id:
type: integer
example: 1
parent_id:
type: integer
example: 101
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- label
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- label
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- 'Org Units'
post:
summary: 'Create a new org unit.'
operationId: createANewOrgUnit
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 210
type: team
entity_id: 15
label: 'Team CúChulainn'
scenario_id: 1
parent_id: 202
valid_from: '2025-01-01'
valid_to: '2025-12-31'
properties:
data:
type: object
properties:
id:
type: integer
example: 210
type:
type: string
example: team
entity_id:
type: integer
example: 15
label:
type: string
example: 'Team CúChulainn'
scenario_id:
type: integer
example: 1
parent_id:
type: integer
example: 202
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: '2025-12-31'
tags:
- 'Org Units'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
type:
type: string
description: 'Org unit type.'
example: team
entity_id:
type: integer
description: 'Linked entity ID.'
example: 15
label:
type: string
description: 'Optional display label.'
example: 'Team CúChulainn'
nullable: true
scenario_id:
type: integer
description: 'Scenario identifier.'
example: 1
nullable: true
parent_id:
type: integer
description: 'Parent org unit ID.'
example: 202
nullable: true
valid_from:
type: string
description: 'The start date. Format: YYYY-MM-DD.'
example: '2025-01-01'
valid_to:
type: string
description: 'The end date. Format: YYYY-MM-DD.'
example: '2025-12-31'
nullable: true
required:
- type
- entity_id
- scenario_id
- valid_from
/api/v1/org-units/summary:
get:
summary: 'Get a summarized charts view.'
operationId: getASummarizedChartsView
description: ''
parameters:
-
in: query
name: root_id
description: 'The ID of the root org unit.'
example: 202
required: true
schema:
type: integer
description: 'The ID of the root org unit.'
example: 202
-
in: query
name: as_of
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
nullable: true
-
in: query
name: sprint_id
description: 'The sprint for velocity metrics.'
example: 42
required: false
schema:
type: integer
description: 'The sprint for velocity metrics.'
example: 42
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 202
label: 'Retail – Ireland'
type: node
entity_id: 4102
rollup:
direct_headcount: 12
subtree_headcount: 38
direct_monthly_cost:
value: 528500
formatted: '€5,285.00'
currency: EUR
subtree_monthly_cost:
value: 1285000
formatted: '€12,850.00'
currency: EUR
direct_monthly_cost_cents: 528500
subtree_monthly_cost_cents: 1285000
velocity_sp: 35
velocity_team_count: 3
children: []
properties:
data:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
type:
type: string
example: node
entity_id:
type: integer
example: 4102
rollup:
type: object
properties:
direct_headcount:
type: integer
example: 12
subtree_headcount:
type: integer
example: 38
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 528500
formatted:
type: string
example: '€5,285.00'
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 1285000
formatted:
type: string
example: '€12,850.00'
currency:
type: string
example: EUR
direct_monthly_cost_cents:
type: integer
example: 528500
subtree_monthly_cost_cents:
type: integer
example: 1285000
velocity_sp:
type: integer
example: 35
velocity_team_count:
type: integer
example: 3
children:
type: array
example: []
tags:
- 'Org Units'
/api/v1/org-units/tree:
get:
summary: 'Get an org subtree (nested) for the current tenant.'
operationId: getAnOrgSubtreenestedForTheCurrentTenant
description: "Returns the subtree for the given root_id (or the tenant root if omitted),\nup to a maximum depth. Supports includes (members,parent,ancestors,path,metrics),\nsearch by name, and filtering by type."
parameters:
-
in: query
name: root_id
description: 'Optional root node id.'
example: 1
required: false
schema:
type: integer
description: 'Optional root node id.'
example: 1
-
in: query
name: depth
description: 'The max depth to traverse from the root. Default: 2.'
example: 3
required: false
schema:
type: integer
description: 'The max depth to traverse from the root. Default: 2.'
example: 3
-
in: query
name: include
description: 'Comma-separated includes: actors,members,parent,ancestors,path,metrics.'
example: 'actors,parent'
required: false
schema:
type: string
description: 'Comma-separated includes: actors,members,parent,ancestors,path,metrics.'
example: 'actors,parent'
-
in: query
name: filter
description: ''
example: []
required: false
schema:
type: object
description: ''
example: []
properties: { }
-
in: query
name: filter.type
description: 'Filter by org unit type.'
example: team
required: false
schema:
type: string
description: 'Filter by org unit type.'
example: team
-
in: query
name: search
description: 'Case-insensitive search on label.'
example: Apollo
required: false
schema:
type: string
description: 'Case-insensitive search on label.'
example: Apollo
-
in: query
name: sort
description: 'Sort by label asc/desc. Allowed: label, -label. Default: label.'
example: '-label'
required: false
schema:
type: string
description: 'Sort by label asc/desc. Allowed: label, -label. Default: label.'
example: '-label'
-
in: query
name: 'filter[type]'
description: 'Filter by org unit type.'
example: team
required: false
schema:
type: string
description: 'Filter by org unit type.'
example: team
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug or id.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 101
label: Engineering
code: null
type: node
entity_id: 4102
parent_id: null
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
parent: null
ancestors: []
path:
- Engineering
metrics:
as_of: '2025-01-10'
direct_headcount: 0
subtree_headcount: 0
direct_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
subtree_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
children:
-
id: 202
label: 'Team CúChulainn'
code: null
type: team
entity_id: 15
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
parent:
id: 101
label: Engineering
ancestors:
-
id: 101
label: Engineering
path:
- Engineering
- 'Team CúChulainn'
metrics:
as_of: '2025-01-10'
direct_headcount: 0
subtree_headcount: 0
direct_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
subtree_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
children: []
properties:
data:
type: object
properties:
id:
type: integer
example: 101
label:
type: string
example: Engineering
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: string
example: null
nullable: true
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: null
nullable: true
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
parent:
type: string
example: null
nullable: true
ancestors:
type: array
example: []
path:
type: array
example:
- Engineering
items:
type: string
metrics:
type: object
properties:
as_of:
type: string
example: '2025-01-10'
direct_headcount:
type: integer
example: 0
subtree_headcount:
type: integer
example: 0
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
children:
type: array
example:
-
id: 202
label: 'Team CúChulainn'
code: null
type: team
entity_id: 15
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
parent:
id: 101
label: Engineering
ancestors:
-
id: 101
label: Engineering
path:
- Engineering
- 'Team CúChulainn'
metrics:
as_of: '2025-01-10'
direct_headcount: 0
subtree_headcount: 0
direct_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
subtree_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
children: []
items:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Team CúChulainn'
code:
type: string
example: null
nullable: true
type:
type: string
example: team
entity_id:
type: integer
example: 15
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: null
nullable: true
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
parent:
type: object
properties:
id:
type: integer
example: 101
label:
type: string
example: Engineering
ancestors:
type: array
example:
-
id: 101
label: Engineering
items:
type: object
properties:
id:
type: integer
example: 101
label:
type: string
example: Engineering
path:
type: array
example:
- Engineering
- 'Team CúChulainn'
items:
type: string
metrics:
type: object
properties:
as_of:
type: string
example: '2025-01-10'
direct_headcount:
type: integer
example: 0
subtree_headcount:
type: integer
example: 0
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
children:
type: array
example: []
tags:
- 'Org Units'
'/api/v1/org-units/{id}/descendants':
get:
summary: 'Get flattened descendants with cursor pagination.'
operationId: getFlattenedDescendantsWithCursorPagination
description: ''
parameters:
-
in: query
name: depth
description: 'The max depth to traverse from the root. Default: 3.'
example: 2
required: false
schema:
type: integer
description: 'The max depth to traverse from the root. Default: 3.'
example: 2
-
in: query
name: include
description: 'Comma-separated includes: actors,members,parent,ancestors,path,metrics.'
example: parent
required: false
schema:
type: string
description: 'Comma-separated includes: actors,members,parent,ancestors,path,metrics.'
example: parent
-
in: query
name: filter
description: ''
example: []
required: false
schema:
type: object
description: ''
example: []
properties: { }
-
in: query
name: filter.type
description: 'Filter by org unit type.'
example: team
required: false
schema:
type: string
description: 'Filter by org unit type.'
example: team
-
in: query
name: search
description: 'Case-insensitive search on label.'
example: Apollo
required: false
schema:
type: string
description: 'Case-insensitive search on label.'
example: Apollo
-
in: query
name: per_page
description: 'Items per page. Max 200.'
example: 50
required: false
schema:
type: integer
description: 'Items per page. Max 200.'
example: 50
-
in: query
name: cursor
description: 'Pagination cursor'
example: ab
required: false
schema:
type: string
description: 'Pagination cursor'
example: ab
-
in: query
name: 'filter[type]'
description: 'Filter by org unit type.'
example: team
required: false
schema:
type: string
description: 'Filter by org unit type.'
example: team
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug or id.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 202
label: 'Team CúChulainn'
code: null
type: team
entity_id: 15
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
metrics:
as_of: '2025-01-10'
direct_headcount: 0
subtree_headcount: 0
direct_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
subtree_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
-
id: 203
label: 'Team Fianna'
code: null
type: team
entity_id: 16
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
links:
next: null
prev: null
meta:
per_page: 50
properties:
data:
type: array
example:
-
id: 202
label: 'Team CúChulainn'
code: null
type: team
entity_id: 15
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
metrics:
as_of: '2025-01-10'
direct_headcount: 0
subtree_headcount: 0
direct_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
subtree_monthly_cost:
value: 0
formatted: €0.00
currency: EUR
-
id: 203
label: 'Team Fianna'
code: null
type: team
entity_id: 16
parent_id: 101
scenario_id: 1
valid_from: null
valid_to: null
created_at: '2025-01-10T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Team CúChulainn'
code:
type: string
example: null
nullable: true
type:
type: string
example: team
entity_id:
type: integer
example: 15
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: null
nullable: true
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
metrics:
type: object
properties:
as_of:
type: string
example: '2025-01-10'
direct_headcount:
type: integer
example: 0
subtree_headcount:
type: integer
example: 0
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 0
formatted:
type: string
example: €0.00
currency:
type: string
example: EUR
links:
type: object
properties:
next:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
meta:
type: object
properties:
per_page:
type: integer
example: 50
tags:
- 'Org Units'
parameters:
-
in: path
name: id
description: 'The root id.'
example: 1
required: true
schema:
type: integer
'/api/v1/org-units/{id}':
get:
summary: 'Show a single org unit summary.'
operationId: showASingleOrgUnitSummary
description: ''
parameters:
-
in: query
name: as_of
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 202
label: 'Retail – Ireland'
type: node
entity_id: 4102
rollup:
direct_headcount: 12
subtree_headcount: 38
direct_monthly_cost:
value: 528500
formatted: '€5,285.00'
currency: EUR
subtree_monthly_cost:
value: 1285000
formatted: '€12,850.00'
currency: EUR
direct_monthly_cost_cents: 528500
subtree_monthly_cost_cents: 1285000
velocity_sp: 35
velocity_team_count: 3
children: []
properties:
data:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
type:
type: string
example: node
entity_id:
type: integer
example: 4102
rollup:
type: object
properties:
direct_headcount:
type: integer
example: 12
subtree_headcount:
type: integer
example: 38
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 528500
formatted:
type: string
example: '€5,285.00'
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 1285000
formatted:
type: string
example: '€12,850.00'
currency:
type: string
example: EUR
direct_monthly_cost_cents:
type: integer
example: 528500
subtree_monthly_cost_cents:
type: integer
example: 1285000
velocity_sp:
type: integer
example: 35
velocity_team_count:
type: integer
example: 3
children:
type: array
example: []
tags:
- 'Org Units'
patch:
summary: 'Update an org unit.'
operationId: updateAnOrgUnit
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 210
type: team
entity_id: 15
label: 'Team CúChulainn'
scenario_id: 1
parent_id: 202
valid_from: '2025-01-01'
valid_to: '2025-12-31'
properties:
data:
type: object
properties:
id:
type: integer
example: 210
type:
type: string
example: team
entity_id:
type: integer
example: 15
label:
type: string
example: 'Team CúChulainn'
scenario_id:
type: integer
example: 1
parent_id:
type: integer
example: 202
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: '2025-12-31'
tags:
- 'Org Units'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
type:
type: string
description: 'Org unit type.'
example: team
entity_id:
type: integer
description: 'Linked entity ID.'
example: 15
label:
type: string
description: 'Optional display label.'
example: 'Team CúChulainn'
nullable: true
scenario_id:
type: integer
description: 'Scenario identifier.'
example: 1
nullable: true
parent_id:
type: integer
description: 'Parent org unit ID.'
example: 202
nullable: true
valid_from:
type: string
description: 'The start date. Format: YYYY-MM-DD.'
example: '2025-01-01'
valid_to:
type: string
description: 'The end date. Format: YYYY-MM-DD.'
example: '2025-12-31'
nullable: true
required:
- type
- entity_id
- scenario_id
- valid_from
delete:
summary: 'Soft delete an org unit.'
operationId: softDeleteAnOrgUnit
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug.'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- 'Org Units — Structure'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
target_parent_id:
type: integer
description: 'New parent org unit id (nullable for root). The id of an existing record in the org_units table.'
example: 101
nullable: true
position:
type: integer
description: 'Desired index among siblings (0-based). Must be at least 0.'
example: 2
nullable: true
expected_updated_at:
type: string
description: 'ISO8601 timestamp.'
example: ab
required:
- expected_updated_at
parameters:
-
in: path
name: id
description: 'The ID of the org unit.'
example: 11
required: true
schema:
type: integer
-
in: path
name: org_unit
description: 'The ID of the org unit.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit}/children':
get:
summary: "List an org unit's immediate children."
operationId: listAnOrgUnitsImmediateChildren
description: ''
parameters:
-
in: query
name: as_of
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'date Format YYYY-MM-DD.'
example: '2025-09-01'
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 210
label: 'Team CúChulainn'
type: team
entity_id: 15
rollup:
direct_headcount: 8
subtree_headcount: 8
direct_monthly_cost:
value: 428500
formatted: '€4,285.00'
currency: EUR
subtree_monthly_cost:
value: 428500
formatted: '€4,285.00'
currency: EUR
direct_monthly_cost_cents: 428500
subtree_monthly_cost_cents: 428500
velocity_sp: 18
velocity_team_count: 1
children: []
properties:
data:
type: array
example:
-
id: 210
label: 'Team CúChulainn'
type: team
entity_id: 15
rollup:
direct_headcount: 8
subtree_headcount: 8
direct_monthly_cost:
value: 428500
formatted: '€4,285.00'
currency: EUR
subtree_monthly_cost:
value: 428500
formatted: '€4,285.00'
currency: EUR
direct_monthly_cost_cents: 428500
subtree_monthly_cost_cents: 428500
velocity_sp: 18
velocity_team_count: 1
children: []
items:
type: object
properties:
id:
type: integer
example: 210
label:
type: string
example: 'Team CúChulainn'
type:
type: string
example: team
entity_id:
type: integer
example: 15
rollup:
type: object
properties:
direct_headcount:
type: integer
example: 8
subtree_headcount:
type: integer
example: 8
direct_monthly_cost:
type: object
properties:
value:
type: integer
example: 428500
formatted:
type: string
example: '€4,285.00'
currency:
type: string
example: EUR
subtree_monthly_cost:
type: object
properties:
value:
type: integer
example: 428500
formatted:
type: string
example: '€4,285.00'
currency:
type: string
example: EUR
direct_monthly_cost_cents:
type: integer
example: 428500
subtree_monthly_cost_cents:
type: integer
example: 428500
velocity_sp:
type: integer
example: 18
velocity_team_count:
type: integer
example: 1
children:
type: array
example: []
tags:
- 'Org Units'
parameters:
-
in: path
name: org_unit
description: 'The ID of the org unit.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit}/metrics':
get:
summary: 'Show the cached aggregate metrics for a single org unit.'
operationId: showTheCachedAggregateMetricsForASingleOrgUnit
description: ''
parameters:
-
in: query
name: as_of
description: 'date The date to compute metrics as of. Dates after today are projected from dated placements, pay and approved deployments.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'date The date to compute metrics as of. Dates after today are projected from dated placements, pay and approved deployments.'
example: '2025-09-01'
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
as_of: '2025-09-01'
direct_headcount: 8
subtree_headcount: 37
direct_monthly_cost_cents: 1250000
subtree_monthly_cost_cents: 4185000
metrics:
span_of_control: 2
properties:
data:
type: object
properties:
as_of:
type: string
example: '2025-09-01'
direct_headcount:
type: integer
example: 8
subtree_headcount:
type: integer
example: 37
direct_monthly_cost_cents:
type: integer
example: 1250000
subtree_monthly_cost_cents:
type: integer
example: 4185000
metrics:
type: object
properties:
span_of_control:
type: integer
example: 2
tags:
- 'Org Units — Metrics'
parameters:
-
in: path
name: org_unit
description: 'The org unit id.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit_id}/move':
post:
summary: 'Move an org unit to a new parent.'
operationId: moveAnOrgUnitToANewParent
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 202
label: 'Retail – Ireland'
code: null
type: node
entity_id: 4102
parent_id: 88
scenario_id: 1
valid_from: '2025-01-01'
valid_to: null
created_at: '2025-08-20T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: integer
example: 88
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-08-20T10:00:00Z'
tags:
- 'Org Units — Structure'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
target_parent_id:
type: integer
description: 'nullable New parent org unit id.'
example: 11
nullable: true
position:
type: integer
description: 'The desired index among siblings.'
example: 11
nullable: true
expected_updated_at:
type: string
description: 'ISO8601 timestamp for optimistic concurrency.'
example: ab
required:
- expected_updated_at
parameters:
-
in: path
name: org_unit_id
description: 'The ID of the org unit.'
example: 11
required: true
schema:
type: integer
-
in: path
name: org_unit
description: 'The org unit id being moved.'
example: 202
required: true
schema:
type: integer
/api/v1/org-units/merge:
post:
summary: 'Merge two org units.'
operationId: mergeTwoOrgUnits
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 202
label: 'Retail – Ireland'
code: null
type: node
entity_id: 4102
parent_id: 101
scenario_id: 1
valid_from: '2025-01-01'
valid_to: null
created_at: '2025-08-20T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-08-20T10:00:00Z'
tags:
- 'Org Units — Structure'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
source_id:
type: integer
description: 'The source unit to merge from.'
example: 11
target_id:
type: integer
description: 'The target unit to merge into.'
example: 11
strategy:
type: string
description: 'The merge strategy.'
example: ab
nullable: true
expected_updated_at_source:
type: string
description: 'Optimistic concurrency timestamp for the source.'
example: '2025-08-29T10:00:00Z'
nullable: true
expected_updated_at_target:
type: string
description: 'Optimistic concurrency timestamp for the target.'
example: '2025-08-29T10:00:00Z'
nullable: true
required:
- source_id
- target_id
'/api/v1/org-units/{org_unit_id}/split':
post:
summary: 'Split an org unit.'
operationId: splitAnOrgUnit
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
original:
id: 202
label: 'Retail – Ireland'
code: null
type: node
entity_id: 4102
parent_id: 101
scenario_id: 1
valid_from: '2025-01-01'
valid_to: null
created_at: '2025-08-20T10:00:00Z'
created:
id: 244
label: 'Payments – Ops'
code: null
type: node
entity_id: 4102
parent_id: 101
scenario_id: 1
valid_from: '2025-01-01'
valid_to: null
created_at: '2026-03-07T10:30:00Z'
properties:
data:
type: object
properties:
original:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-08-20T10:00:00Z'
created:
type: object
properties:
id:
type: integer
example: 244
label:
type: string
example: 'Payments – Ops'
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-03-07T10:30:00Z'
tags:
- 'Org Units — Structure'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
mode:
type: string
description: 'new_sibling or new_child.'
example: ab
label:
type: string
description: 'Label for the new unit.'
example: ab
nullable: true
children_to_move:
type: array
description: 'IDs of children to move.'
example:
- ab
items:
type: string
expected_updated_at:
type: string
description: 'ISO8601 timestamp.'
example: ab
required:
- mode
- children_to_move
- expected_updated_at
parameters:
-
in: path
name: org_unit_id
description: 'The ID of the org unit.'
example: 11
required: true
schema:
type: integer
-
in: path
name: org_unit
description: 'The org unit id being split.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit_id}/restore':
post:
summary: 'Restore an org unit.'
operationId: restoreAnOrgUnit
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required The tenant slug.'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 202
label: 'Retail – Ireland'
code: null
type: node
entity_id: 4102
parent_id: 101
scenario_id: 1
valid_from: '2025-01-01'
valid_to: null
created_at: '2025-08-20T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 202
label:
type: string
example: 'Retail – Ireland'
code:
type: string
example: null
nullable: true
type:
type: string
example: node
entity_id:
type: integer
example: 4102
parent_id:
type: integer
example: 101
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-01'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-08-20T10:00:00Z'
tags:
- 'Org Units — Structure'
parameters:
-
in: path
name: org_unit_id
description: 'The ID of the org unit.'
example: 11
required: true
schema:
type: integer
-
in: path
name: org_unit
description: 'The soft-deleted org unit id.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit}/velocity':
get:
summary: 'Get velocity for an org unit.'
operationId: getVelocityForAnOrgUnit
description: ''
parameters:
-
in: query
name: sprint_id
description: 'The sprint to query.'
example: 11
required: false
schema:
type: integer
description: 'The sprint to query.'
example: 11
nullable: true
-
in: query
name: as_of
description: 'date Mutually exclusive with sprint_id.'
example: ab
required: false
schema:
type: string
description: 'date Mutually exclusive with sprint_id.'
example: ab
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
org_unit_id: 202
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
velocity_sp: 88
teams_count: 4
properties:
data:
type: object
properties:
org_unit_id:
type: integer
example: 202
sprint_id:
type: integer
example: 42
period:
type: object
properties:
label:
type: string
example: 'Sprint 18'
starts_at:
type: string
example: '2025-09-01'
ends_at:
type: string
example: '2025-09-14'
velocity_sp:
type: integer
example: 88
teams_count:
type: integer
example: 4
tags:
- 'Org Units — Velocity'
parameters:
-
in: path
name: org_unit
description: 'The org unit ID.'
example: 202
required: true
schema:
type: integer
'/api/v1/org-units/{org_unit}/velocity/series':
get:
summary: 'Get velocity series for an org unit.'
operationId: getVelocitySeriesForAnOrgUnit
description: ''
parameters:
-
in: query
name: from_sprint_id
description: 'Starting sprint ID. The id of an existing record in the sprint_periods table.'
example: 1
required: false
schema:
type: integer
description: 'Starting sprint ID. The id of an existing record in the sprint_periods table.'
example: 1
nullable: true
-
in: query
name: to_sprint_id
description: 'Ending sprint ID. The id of an existing record in the sprint_periods table.'
example: 10
required: false
schema:
type: integer
description: 'Ending sprint ID. The id of an existing record in the sprint_periods table.'
example: 10
nullable: true
-
in: query
name: from
description: 'Start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-01-01'
required: false
schema:
type: string
description: 'Start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-01-01'
nullable: true
-
in: query
name: to
description: 'End date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-06-01'
required: false
schema:
type: string
description: 'End date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-06-01'
nullable: true
-
in: query
name: limit
description: 'Maximum number of sprints to return. Must be at least 1. Must not be greater than 50.'
example: 12
required: false
schema:
type: integer
description: 'Maximum number of sprints to return. Must be at least 1. Must not be greater than 50.'
example: 12
nullable: true
-
in: query
name: order
description: 'Sort order by sprint start.'
example: asc
required: false
schema:
type: string
description: 'Sort order by sprint start.'
example: asc
enum:
- asc
- desc
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
org_unit_id: 202
sprint_id: 41
period:
label: 'Sprint 17'
starts_at: '2025-08-18'
ends_at: '2025-08-31'
velocity_sp: 81
teams_count: 4
-
org_unit_id: 202
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
velocity_sp: 88
teams_count: 4
properties:
data:
type: array
example:
-
org_unit_id: 202
sprint_id: 41
period:
label: 'Sprint 17'
starts_at: '2025-08-18'
ends_at: '2025-08-31'
velocity_sp: 81
teams_count: 4
-
org_unit_id: 202
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
velocity_sp: 88
teams_count: 4
items:
type: object
properties:
org_unit_id:
type: integer
example: 202
sprint_id:
type: integer
example: 41
period:
type: object
properties:
label:
type: string
example: 'Sprint 17'
starts_at:
type: string
example: '2025-08-18'
ends_at:
type: string
example: '2025-08-31'
velocity_sp:
type: integer
example: 81
teams_count:
type: integer
example: 4
tags:
- 'Org Units — Velocity'
parameters:
-
in: path
name: org_unit
description: 'The org unit ID.'
example: 202
required: true
schema:
type: integer
/api/v1/me/organisations:
get:
summary: 'List Organisation Accounts available to the authenticated user.'
operationId: listOrganisationAccountsAvailableToTheAuthenticatedUser
description: 'Returns the Organisation Accounts that the authenticated user can access.'
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 12
name: 'Acme Product'
slug: acme-product
plan_code: team
subscription_status: trialing
trial_ends_at: '2026-03-06T12:00:00Z'
onboarding_completed_at: null
role: owner
properties:
data:
type: array
example:
-
id: 12
name: 'Acme Product'
slug: acme-product
plan_code: team
subscription_status: trialing
trial_ends_at: '2026-03-06T12:00:00Z'
onboarding_completed_at: null
role: owner
items:
type: object
properties:
id:
type: integer
example: 12
name:
type: string
example: 'Acme Product'
slug:
type: string
example: acme-product
plan_code:
type: string
example: team
subscription_status:
type: string
example: trialing
trial_ends_at:
type: string
example: '2026-03-06T12:00:00Z'
onboarding_completed_at:
type: string
example: null
nullable: true
role:
type: string
example: owner
tags:
- 'Organisation Accounts'
/api/v1/organisations/current:
get:
summary: 'Get the current Organisation Account details.'
operationId: getTheCurrentOrganisationAccountDetails
description: 'Resolution follows the standard precedence (subdomain, last-used Organisation, session fallback).'
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 12
name: 'Acme Product'
slug: acme-product
plan_code: team
onboarding_choice: import
onboarding_completed_at: null
trial_started_at: '2026-02-21T12:00:00Z'
trial_ends_at: '2026-03-06T12:00:00Z'
subscription_status: trialing
grace_ends_at: null
locked_at: null
role: owner
saml_enabled: false
current_token:
abilities:
- cli.access
- actors.read
- scenarios.read
cli_access: true
properties:
data:
type: object
properties:
id:
type: integer
example: 12
description: 'Organisation Account identifier.'
name:
type: string
example: 'Acme Product'
description: 'Organisation Account display name.'
slug:
type: string
example: acme-product
description: 'Organisation Account slug.'
plan_code:
type: string
example: team
description: 'Active subscription plan code.'
onboarding_choice:
type: string
example: import
description: 'Selected onboarding path (`hris`, `import`, `demo`, `empty`).'
onboarding_completed_at:
type: string
example: null
description: 'ISO-8601 onboarding completion timestamp.'
trial_started_at:
type: string
example: '2026-02-21T12:00:00Z'
description: 'ISO-8601 trial start timestamp.'
trial_ends_at:
type: string
example: '2026-03-06T12:00:00Z'
description: 'ISO-8601 trial end timestamp.'
subscription_status:
type: string
example: trialing
description: 'Current lifecycle state.'
grace_ends_at:
type: string
example: null
description: 'ISO-8601 grace-period end timestamp.'
locked_at:
type: string
example: null
description: 'ISO-8601 lock timestamp.'
role:
type: string
example: owner
description: 'Membership role for the authenticated user in this Organisation Account.'
saml_enabled:
type: boolean
example: false
description: 'Included only when the user has `sso.manage` capability and the tenant plan includes tenant-managed SAML.'
current_token:
type: object
properties:
abilities:
type: array
example:
- cli.access
- actors.read
- scenarios.read
description: 'Normalized abilities/scopes declared on the current bearer token.'
items:
type: string
cli_access:
type: boolean
example: true
description: 'Whether the current bearer token explicitly includes `cli.access`.'
404:
description: ''
content:
application/json:
schema:
type: object
example:
code: tenant.not_resolved
message: 'No Organisation Account is currently selected.'
properties:
code:
type: string
example: tenant.not_resolved
message:
type: string
example: 'No Organisation Account is currently selected.'
tags:
- 'Organisation Accounts'
/api/v1/organisations/current/onboarding-choice:
post:
summary: 'Update onboarding choice for the current Organisation Account.'
operationId: updateOnboardingChoiceForTheCurrentOrganisationAccount
description: 'Persists how this Organisation Account will start onboarding.'
parameters: []
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 12
name: 'Acme Product'
slug: acme-product
onboarding_choice: import
subscription_status: trialing
properties:
data:
type: object
properties:
id:
type: integer
example: 12
description: 'Organisation Account identifier.'
name:
type: string
example: 'Acme Product'
description: 'Organisation Account display name.'
slug:
type: string
example: acme-product
description: 'Organisation Account slug.'
onboarding_choice:
type: string
example: import
description: 'Persisted onboarding choice for the current Organisation Account.'
subscription_status:
type: string
example: trialing
description: 'Current lifecycle state.'
404:
description: ''
content:
application/json:
schema:
type: object
example:
code: tenant.not_resolved
message: 'No Organisation Account is currently selected.'
properties:
code:
type: string
example: tenant.not_resolved
message:
type: string
example: 'No Organisation Account is currently selected.'
tags:
- 'Organisation Accounts'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
onboarding_choice:
type: string
description: 'How this Organisation Account will add data first.'
example: import
enum:
- hris
- import
- demo
- empty
required:
- onboarding_choice
/api/v1/positions:
get:
summary: 'List positions with pagination, filters, and search.'
operationId: listPositionsWithPaginationFiltersAndSearch
description: "Returns baseline data when no scenario filter is supplied; pass\n`filter[scenario]=current` to reflect the active scenario, or pass\na tenant scenario slug such as `sandbox`."
parameters:
-
in: query
name: page
description: 'The page number to return.'
example: 1
required: false
schema:
type: integer
description: 'The page number to return.'
example: 1
-
in: query
name: per_page
description: 'Results per page (max 100).'
example: 25
required: false
schema:
type: integer
description: 'Results per page (max 100).'
example: 25
-
in: query
name: scenario
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
required: false
schema:
type: string
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
-
in: query
name: 'filter[scenario_id]'
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
required: false
schema:
type: string
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
-
in: query
name: 'filter[scenario]'
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
required: false
schema:
type: string
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,valid_from,valid_to,fte,created_at.'
example: '-valid_from'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,valid_from,valid_to,fte,created_at.'
example: '-valid_from'
-
in: query
name: 'filter[org_unit_team_id]'
description: 'Filter by a budgeted team org unit (planning metadata only).'
example: 4201
required: false
schema:
type: integer
description: 'Filter by a budgeted team org unit (planning metadata only).'
example: 4201
-
in: query
name: 'filter[target_employment_type]'
description: 'Restrict by budgeted employment type (perm or contractor).'
example: perm
required: false
schema:
type: string
description: 'Restrict by budgeted employment type (perm or contractor).'
example: perm
-
in: query
name: 'filter[active_as_of]'
description: 'date Return positions active on this ISO date (YYYY-MM-DD).'
example: '2025-09-20'
required: false
schema:
type: string
description: 'date Return positions active on this ISO date (YYYY-MM-DD).'
example: '2025-09-20'
-
in: query
name: q
description: 'Free-text search across title, team name, and actor name.'
example: 'platform engineer'
required: false
schema:
type: string
description: 'Free-text search across title, team name, and actor name.'
example: 'platform engineer'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: team,actor.'
example: 'team,actor'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: team,actor.'
example: 'team,actor'
-
in: query
name: 'fields[positions]'
description: 'Sparse fieldset selection.'
example: 'id,title,team'
required: false
schema:
type: string
description: 'Sparse fieldset selection.'
example: 'id,title,team'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 17
org_unit_team_id: 4201
actor_id: null
title: 'Staff Platform Engineer'
target_employment_type: perm
fte: 1
target_annual_salary_cents: 11850000
target_daily_rate_cents: null
target_currency: EUR
valid_from: '2024-03-01'
valid_to: null
scenario_id: null
meta:
cost_centre: ENG-PLAT
notes: 'Supports platform migration.'
team:
id: 8
name: 'Platform Experience'
slug: platform-experience
actor: null
budget:
employment_type: perm
fte: 1
annual_salary_cents: 11850000
daily_rate_cents: null
currency: EUR
links:
self: 'https://tenant.orgonaut.test/api/v1/positions/17'
team: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor: null
created_at: '2025-09-19T09:00:00Z'
updated_at: '2025-09-19T09:00:00Z'
links:
first: 'https://tenant.orgonaut.test/api/v1/positions?page=1'
last: 'https://tenant.orgonaut.test/api/v1/positions?page=3'
prev: null
next: 'https://tenant.orgonaut.test/api/v1/positions?page=2'
meta:
current_page: 1
from: 1
last_page: 3
path: 'https://tenant.orgonaut.test/api/v1/positions'
per_page: 25
to: 25
total: 62
properties:
data:
type: array
example:
-
id: 17
org_unit_team_id: 4201
actor_id: null
title: 'Staff Platform Engineer'
target_employment_type: perm
fte: 1
target_annual_salary_cents: 11850000
target_daily_rate_cents: null
target_currency: EUR
valid_from: '2024-03-01'
valid_to: null
scenario_id: null
meta:
cost_centre: ENG-PLAT
notes: 'Supports platform migration.'
team:
id: 8
name: 'Platform Experience'
slug: platform-experience
actor: null
budget:
employment_type: perm
fte: 1
annual_salary_cents: 11850000
daily_rate_cents: null
currency: EUR
links:
self: 'https://tenant.orgonaut.test/api/v1/positions/17'
team: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor: null
created_at: '2025-09-19T09:00:00Z'
updated_at: '2025-09-19T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 17
org_unit_team_id:
type: integer
example: 4201
actor_id:
type: string
example: null
nullable: true
title:
type: string
example: 'Staff Platform Engineer'
target_employment_type:
type: string
example: perm
fte:
type: integer
example: 1
target_annual_salary_cents:
type: integer
example: 11850000
target_daily_rate_cents:
type: string
example: null
nullable: true
target_currency:
type: string
example: EUR
valid_from:
type: string
example: '2024-03-01'
valid_to:
type: string
example: null
nullable: true
scenario_id:
type: string
example: null
nullable: true
meta:
type: object
properties:
cost_centre:
type: string
example: ENG-PLAT
notes:
type: string
example: 'Supports platform migration.'
team:
type: object
properties:
id:
type: integer
example: 8
name:
type: string
example: 'Platform Experience'
slug:
type: string
example: platform-experience
actor:
type: string
example: null
nullable: true
budget:
type: object
properties:
employment_type:
type: string
example: perm
fte:
type: integer
example: 1
annual_salary_cents:
type: integer
example: 11850000
daily_rate_cents:
type: string
example: null
nullable: true
currency:
type: string
example: EUR
links:
type: object
properties:
self:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions/17'
team:
type: string
example: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-09-19T09:00:00Z'
updated_at:
type: string
example: '2025-09-19T09:00:00Z'
links:
type: object
properties:
first:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions?page=1'
last:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions?page=3'
prev:
type: string
example: null
nullable: true
next:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions?page=2'
meta:
type: object
properties:
current_page:
type: integer
example: 1
from:
type: integer
example: 1
last_page:
type: integer
example: 3
path:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions'
per_page:
type: integer
example: 25
to:
type: integer
example: 25
total:
type: integer
example: 62
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported filter[scenario]: future'
details:
allowed:
- baseline
- live
- current
- '{id}'
- '{slug}'
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported filter[scenario]: future'
details:
type: object
properties:
allowed:
type: array
example:
- baseline
- live
- current
- '{id}'
- '{slug}'
items:
type: string
tags:
- Positions
post:
summary: 'Create a position within the active scenario.'
operationId: createAPositionWithinTheActiveScenario
description: "Applies baseline defaults when the current scenario guard is baseline,\notherwise stores the record against the active scenario id."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 24
org_unit_team_id: 4201
actor_id: null
title: 'Staff Platform Engineer'
target_employment_type: perm
fte: 1
target_annual_salary_cents: 11850000
target_daily_rate_cents: null
target_currency: EUR
valid_from: '2024-03-01'
valid_to: null
scenario_id: null
meta:
cost_centre: ENG-PLAT
notes: 'Supports platform migration.'
team:
id: 8
name: 'Platform Experience'
slug: platform-experience
actor: null
budget:
employment_type: perm
fte: 1
annual_salary_cents: 11850000
daily_rate_cents: null
currency: EUR
links:
self: 'https://tenant.orgonaut.test/api/v1/positions/24'
team: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor: null
created_at: '2025-09-19T09:15:00Z'
updated_at: '2025-09-19T09:15:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 24
description: 'Newly created position id.'
org_unit_team_id:
type: integer
example: 4201
description: 'Budgeted team org unit id (planning metadata only; null when unassigned).'
actor_id:
type: string
example: null
description: 'Assigned actor id when filled.'
title:
type: string
example: 'Staff Platform Engineer'
description: 'Role title displayed in listings.'
target_employment_type:
type: string
example: perm
description: 'Budgeted employment type (perm or contractor).'
fte:
type: integer
example: 1
description: 'Full-time equivalent allocation.'
target_annual_salary_cents:
type: integer
example: 11850000
description: 'Budgeted annual salary when target_employment_type is perm.'
target_daily_rate_cents:
type: string
example: null
description: 'Budgeted daily rate when target_employment_type is contractor.'
target_currency:
type: string
example: EUR
description: 'ISO-4217 currency code for the budget target.'
valid_from:
type: string
example: '2024-03-01'
description: 'Effective start date (YYYY-MM-DD).'
valid_to:
type: string
example: null
description: 'Effective end date when specified.'
scenario_id:
type: string
example: null
description: 'Scenario identifier; null when stored in baseline.'
meta:
type: object
properties:
cost_centre:
type: string
example: ENG-PLAT
notes:
type: string
example: 'Supports platform migration.'
description: 'Arbitrary metadata supplied during creation.'
team:
type: object
properties:
id:
type: integer
example: 8
name:
type: string
example: 'Platform Experience'
slug:
type: string
example: platform-experience
actor:
type: string
example: null
nullable: true
budget:
type: object
properties:
employment_type:
type: string
example: perm
fte:
type: integer
example: 1
annual_salary_cents:
type: integer
example: 11850000
daily_rate_cents:
type: string
example: null
nullable: true
currency:
type: string
example: EUR
description: 'Nested budget details including salary and employment type.'
links:
type: object
properties:
self:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions/24'
team:
type: string
example: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor:
type: string
example: null
nullable: true
description: 'Hypermedia links to related resources.'
created_at:
type: string
example: '2025-09-19T09:15:00Z'
description: 'ISO-8601 timestamp for creation.'
updated_at:
type: string
example: '2025-09-19T09:15:00Z'
description: 'ISO-8601 timestamp for the latest update.'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
target_annual_salary_cents:
- 'Budgeted annual salary applies to permanent roles only.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
target_annual_salary_cents:
type: array
example:
- 'Budgeted annual salary applies to permanent roles only.'
items:
type: string
tags:
- Positions
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description: 'The seat title.'
example: ab
role_type_id:
type: integer
description: 'The id of an existing record in the role_types table.'
example: 11
nullable: true
org_unit_team_id:
type: integer
description: 'The budgeted team for this seat (planning metadata only; does not assign an actor).'
example: 4201
nullable: true
target_employment_type:
type: string
description: 'The budgeted employment type (e.g., perm|contractor).'
example: ab
nullable: true
fte:
type: number
description: 'Full-time equivalent allocation between 0.01 and 2.0. Must be between 0.01 and 2.00.'
example: 1.0
target_annual_salary_cents:
type: integer
description: 'Budgeted annual salary in cents for permanent roles. Must be at least 0.'
example: 8500000
nullable: true
target_daily_rate_cents:
type: integer
description: 'Budgeted daily rate in cents for contractor roles. Must be at least 0.'
example: 45000
nullable: true
target_currency:
type: string
description: 'Three-letter currency code defined in Settings → Currencies. The code of an existing record in the currencies table. Must be 3 characters.'
example: EUR
nullable: true
valid_from:
type: string
description: 'Effective start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-09-20'
valid_to:
type: string
description: 'Effective end date (optional, YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to valid_from.'
example: '2026-03-31'
nullable: true
meta:
type: object
description: 'Arbitrary structured metadata for the position.'
example:
cost_centre: ENG-PLAT
properties: { }
nullable: true
create_placement:
type: boolean
description: 'Set to false to prevent auto-creating a placement when linking this record to downstream observers.'
example: true
nullable: true
tenant_id:
type: integer
description: ''
example: 11
scenario_id:
type: integer
description: ''
example: 11
nullable: true
required:
- title
- fte
- valid_from
- tenant_id
'/api/v1/positions/{id}':
get:
summary: 'Display a specific position.'
operationId: displayASpecificPosition
description: "Honors the active scenario guard unless `filter[scenario]`/`filter[scenario_id]`\nwere provided on the index request and cached via query options middleware."
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: team,actor.'
example: team
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: team,actor.'
example: team
-
in: query
name: 'fields[positions]'
description: 'Sparse fieldset.'
example: 'id,title,team'
required: false
schema:
type: string
description: 'Sparse fieldset.'
example: 'id,title,team'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 24
org_unit_team_id: 4201
actor_id: null
title: 'Staff Platform Engineer'
target_employment_type: perm
fte: 1
target_annual_salary_cents: 11850000
target_daily_rate_cents: null
target_currency: EUR
valid_from: '2024-03-01'
valid_to: null
scenario_id: null
meta:
cost_centre: ENG-PLAT
notes: 'Supports platform migration.'
team:
id: 8
name: 'Platform Experience'
slug: platform-experience
actor: null
budget:
employment_type: perm
fte: 1
annual_salary_cents: 11850000
daily_rate_cents: null
currency: EUR
links:
self: 'https://tenant.orgonaut.test/api/v1/positions/24'
team: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor: null
created_at: '2025-09-19T09:15:00Z'
updated_at: '2025-09-19T09:15:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 24
description: 'Position identifier.'
org_unit_team_id:
type: integer
example: 4201
description: 'Budgeted team org unit id (planning metadata only; null when unassigned).'
actor_id:
type: string
example: null
description: 'Assigned actor id when filled.'
title:
type: string
example: 'Staff Platform Engineer'
description: 'Role title displayed in listings.'
target_employment_type:
type: string
example: perm
description: 'Budgeted employment type (perm or contractor).'
fte:
type: integer
example: 1
description: 'Full-time equivalent allocation.'
target_annual_salary_cents:
type: integer
example: 11850000
description: 'Budgeted annual salary in cents.'
target_daily_rate_cents:
type: string
example: null
description: 'Budgeted daily rate in cents.'
target_currency:
type: string
example: EUR
description: 'ISO-4217 currency code for the budget target.'
valid_from:
type: string
example: '2024-03-01'
description: 'Effective start date (YYYY-MM-DD).'
valid_to:
type: string
example: null
description: 'Effective end date (YYYY-MM-DD).'
scenario_id:
type: string
example: null
description: 'Scenario identifier when not baseline.'
meta:
type: object
properties:
cost_centre:
type: string
example: ENG-PLAT
notes:
type: string
example: 'Supports platform migration.'
description: 'Arbitrary structured metadata payload.'
team:
type: object
properties:
id:
type: integer
example: 8
name:
type: string
example: 'Platform Experience'
slug:
type: string
example: platform-experience
description: 'Team details when requested via include.'
actor:
type: string
example: null
description: 'Actor summary when requested via include.'
budget:
type: object
properties:
employment_type:
type: string
example: perm
fte:
type: integer
example: 1
annual_salary_cents:
type: integer
example: 11850000
daily_rate_cents:
type: string
example: null
nullable: true
currency:
type: string
example: EUR
description: 'Nested budget details including salary and employment type.'
links:
type: object
properties:
self:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions/24'
team:
type: string
example: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor:
type: string
example: null
nullable: true
description: 'Hypermedia links for related resources.'
created_at:
type: string
example: '2025-09-19T09:15:00Z'
description: 'ISO-8601 timestamp for creation.'
updated_at:
type: string
example: '2025-09-19T09:15:00Z'
description: 'ISO-8601 timestamp for the latest update.'
tags:
- Positions
put:
summary: 'Update a position.'
operationId: updateAPosition
description: "Validation enforces mutual exclusivity between salary and daily rate,\nmirroring the create endpoint rules."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 24
org_unit_team_id: 4201
actor_id: null
title: 'Principal Platform Engineer'
target_employment_type: perm
fte: 1
target_annual_salary_cents: 12600000
target_daily_rate_cents: null
target_currency: EUR
valid_from: '2024-03-01'
valid_to: null
scenario_id: null
meta:
cost_centre: ENG-PLAT
notes: 'Role upgraded to lead migration.'
team:
id: 8
name: 'Platform Experience'
slug: platform-experience
actor: null
budget:
employment_type: perm
fte: 1
annual_salary_cents: 12600000
daily_rate_cents: null
currency: EUR
links:
self: 'https://tenant.orgonaut.test/api/v1/positions/24'
team: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor: null
created_at: '2025-09-19T09:15:00Z'
updated_at: '2025-09-26T11:20:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 24
description: 'Position identifier.'
org_unit_team_id:
type: integer
example: 4201
description: 'Budgeted team org unit id (planning metadata only; null when unassigned).'
actor_id:
type: string
example: null
description: 'Assigned actor id when filled.'
title:
type: string
example: 'Principal Platform Engineer'
description: 'Role title displayed in listings.'
target_employment_type:
type: string
example: perm
description: 'Budgeted employment type (perm or contractor).'
fte:
type: integer
example: 1
description: 'Full-time equivalent allocation.'
target_annual_salary_cents:
type: integer
example: 12600000
description: 'Budgeted annual salary in cents.'
target_daily_rate_cents:
type: string
example: null
description: 'Budgeted daily rate in cents.'
target_currency:
type: string
example: EUR
description: 'ISO-4217 currency code for the budget target.'
valid_from:
type: string
example: '2024-03-01'
description: 'Effective start date (YYYY-MM-DD).'
valid_to:
type: string
example: null
description: 'Effective end date.'
scenario_id:
type: string
example: null
description: 'Scenario identifier; null for baseline.'
meta:
type: object
properties:
cost_centre:
type: string
example: ENG-PLAT
notes:
type: string
example: 'Role upgraded to lead migration.'
description: 'Arbitrary structured metadata payload.'
team:
type: object
properties:
id:
type: integer
example: 8
name:
type: string
example: 'Platform Experience'
slug:
type: string
example: platform-experience
actor:
type: string
example: null
nullable: true
budget:
type: object
properties:
employment_type:
type: string
example: perm
fte:
type: integer
example: 1
annual_salary_cents:
type: integer
example: 12600000
daily_rate_cents:
type: string
example: null
nullable: true
currency:
type: string
example: EUR
description: 'Nested budget details including salary and employment type.'
links:
type: object
properties:
self:
type: string
example: 'https://tenant.orgonaut.test/api/v1/positions/24'
team:
type: string
example: 'https://tenant.orgonaut.test/api/v1/teams/8'
actor:
type: string
example: null
nullable: true
description: 'Hypermedia links for related resources.'
created_at:
type: string
example: '2025-09-19T09:15:00Z'
description: 'ISO-8601 timestamp for creation.'
updated_at:
type: string
example: '2025-09-26T11:20:00Z'
description: 'ISO-8601 timestamp for the latest update.'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
target_daily_rate_cents:
- 'Budgeted daily rate applies to contractor roles only.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
target_daily_rate_cents:
type: array
example:
- 'Budgeted daily rate applies to contractor roles only.'
items:
type: string
tags:
- Positions
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description: 'The seat title.'
example: ab
role_type_id:
type: integer
description: 'The id of an existing record in the role_types table.'
example: 11
nullable: true
org_unit_team_id:
type: integer
description: 'The budgeted team for this seat (planning metadata only; does not assign an actor).'
example: 4201
nullable: true
target_employment_type:
type: string
description: 'The budgeted employment type (e.g., perm|contractor).'
example: ab
nullable: true
fte:
type: number
description: 'Full-time equivalent allocation between 0.01 and 2.0. Must be between 0.01 and 2.00.'
example: 1.0
target_annual_salary_cents:
type: integer
description: 'Budgeted annual salary in cents for permanent roles. Must be at least 0.'
example: 8500000
nullable: true
target_daily_rate_cents:
type: integer
description: 'Budgeted daily rate in cents for contractor roles. Must be at least 0.'
example: 45000
nullable: true
target_currency:
type: string
description: 'Three-letter currency code defined in Settings → Currencies. The code of an existing record in the currencies table. Must be 3 characters.'
example: EUR
nullable: true
valid_from:
type: string
description: 'Effective start date (YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d.'
example: '2025-09-20'
valid_to:
type: string
description: 'Effective end date (optional, YYYY-MM-DD). Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date after or equal to valid_from.'
example: '2026-03-31'
nullable: true
meta:
type: object
description: 'Arbitrary structured metadata for the position.'
example:
cost_centre: ENG-PLAT
properties: { }
nullable: true
create_placement:
type: boolean
description: 'Set to false to prevent auto-creating a placement when linking this record to downstream observers.'
example: true
nullable: true
tenant_id:
type: integer
description: ''
example: 11
scenario_id:
type: integer
description: ''
example: 11
nullable: true
required:
- title
- fte
- valid_from
- tenant_id
delete:
summary: 'Soft delete a position.'
operationId: softDeleteAPosition
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Positions
parameters:
-
in: path
name: id
description: 'The ID of the position.'
example: 11
required: true
schema:
type: integer
-
in: path
name: position
description: 'The ID of the position.'
example: 24
required: true
schema:
type: integer
/api/v1/role-types/search:
get:
summary: 'Search Role Types for the active tenant.'
operationId: searchRoleTypesForTheActiveTenant
description: "Returns up to 20 matching role types ordered by display order, level, then name.\nRequires `settings.manage` ability."
parameters:
-
in: query
name: q
description: 'Search term applied to name and slug.'
example: engineer
required: false
schema:
type: string
description: 'Search term applied to name and slug.'
example: engineer
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
name: 'Senior Engineer'
slug: senior-engineer
level: 4
color: '#2563eb'
description: null
is_active: true
display_order: 6
properties:
data:
type: array
example:
-
id: 1
name: 'Senior Engineer'
slug: senior-engineer
level: 4
color: '#2563eb'
description: null
is_active: true
display_order: 6
items:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'Senior Engineer'
slug:
type: string
example: senior-engineer
level:
type: integer
example: 4
color:
type: string
example: '#2563eb'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 6
tags:
- 'Role Types'
/api/v1/scenarios/tasks:
get:
summary: 'List scenario tasks.'
operationId: listScenarioTasks
description: "Returns scenario tasks for the authenticated tenant, ordered by latest first.\nThese tasks mirror the progress shown in the Flux UI at /scenarios/tasks."
parameters:
-
in: query
name: status
description: 'Filter by status (pending, running, failed, complete).'
example: running
required: false
schema:
type: string
description: 'Filter by status (pending, running, failed, complete).'
example: running
-
in: query
name: type
description: 'Filter by task type (clone, promotion, snapshot, all). Defaults to clone for compatibility.'
example: promotion
required: false
schema:
type: string
description: 'Filter by task type (clone, promotion, snapshot, all). Defaults to clone for compatibility.'
example: promotion
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: integer
example: 81
scenario_id:
type: integer
example: 42
scenario_name:
type: string
example: 'Q2 Planning'
type:
type: string
example: clone
stage:
type: string
example: actors
status:
type: string
example: running
percent:
type: integer
example: 33
message:
type: string
example: 'Copying Actors...'
error_message:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-11-01T12:14:22Z'
updated_at:
type: string
example: '2025-11-01T12:15:03Z'
example:
-
id: 81
scenario_id: 42
scenario_name: 'Q2 Planning'
type: clone
stage: actors
status: running
percent: 33
message: 'Copying Actors...'
error_message: null
created_at: '2025-11-01T12:14:22Z'
updated_at: '2025-11-01T12:15:03Z'
tags:
- 'Scenario Tasks'
/api/v1/scenarios:
get:
summary: 'Display a paginated listing of scenarios.'
operationId: displayAPaginatedListingOfScenarios
description: ''
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
-
in: query
name: 'filter[status]'
description: 'Filter by status.'
example: cloning
required: false
schema:
type: string
description: 'Filter by status.'
example: cloning
-
in: query
name: 'filter[kind]'
description: 'Filter by kind (planning, baseline_archive, applied_scenario).'
example: planning
required: false
schema:
type: string
description: 'Filter by kind (planning, baseline_archive, applied_scenario).'
example: planning
-
in: query
name: 'fields[scenarios]'
description: 'Sparse fields for scenarios.'
example: 'id,name,status'
required: false
schema:
type: string
description: 'Sparse fields for scenarios.'
example: 'id,name,status'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: 'teams,aggregate'
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: 'teams,aggregate'
-
in: query
name: as_of
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
name: 'FY26 Cost Optimisation'
status: new
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 1
name: 'FY26 Cost Optimisation'
status: new
items:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'FY26 Cost Optimisation'
status:
type: string
example: new
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- name
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- name
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- Scenarios
post:
summary: 'Create a new scenario.'
operationId: createANewScenario
description: 'Triggers a background clone pipeline and returns immediately with status=initialising.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
202:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Scenario creation started. Cloning in progress.'
status: initialising
scenario:
id: 42
name: 'Q2 Planning'
status: initialising
notes: 'Budget-cut planning run.'
tasks_url: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
properties:
message:
type: string
example: 'Scenario creation started. Cloning in progress.'
status:
type: string
example: initialising
scenario:
type: object
properties:
id:
type: integer
example: 42
name:
type: string
example: 'Q2 Planning'
status:
type: string
example: initialising
notes:
type: string
example: 'Budget-cut planning run.'
tasks_url:
type: string
example: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
403:
description: ''
content:
application/json:
schema:
type: object
example:
code: feature.unavailable
message: 'Your current subscription plan does not include this feature.'
properties:
code:
type: string
example: feature.unavailable
message:
type: string
example: 'Your current subscription plan does not include this feature.'
429:
description: ''
content:
application/json:
schema:
type: object
example:
code: limit.scenarios
message: 'Active planning scenario limit reached (1/1). Archive or apply an existing scenario, or upgrade your plan.'
limit: 1
current: 1
properties:
code:
type: string
example: limit.scenarios
message:
type: string
example: 'Active planning scenario limit reached (1/1). Archive or apply an existing scenario, or upgrade your plan.'
limit:
type: integer
example: 1
current:
type: integer
example: 1
tags:
- Scenarios
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'The scenario name.'
example: '"Q2 Planning"'
notes:
type: string
description: 'Notes about the scenario.'
example: '"Budget-cut planning run."'
nullable: true
source_scenario_id:
type: integer
description: 'The active scenario to clone from (null to clone from baseline).'
example: 12
nullable: true
required:
- name
'/api/v1/scenarios/{slug}':
get:
summary: 'Display the specified scenario.'
operationId: displayTheSpecifiedScenario
description: ''
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
-
in: query
name: as_of
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: 'FY26 Cost Optimisation'
status: new
aggregate:
as_of_date: '2025-09-01'
scenario_direct_headcount: 0
scenario_subtree_headcount: 0
scenario_direct_monthly_cost_cents: 0
scenario_subtree_monthly_cost_cents: 0
velocity_completed_sp: 0
velocity_team_count: 0
computed_at: '2025-09-06T12:00:00Z'
metrics: { }
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'FY26 Cost Optimisation'
status:
type: string
example: new
aggregate:
type: object
properties:
as_of_date:
type: string
example: '2025-09-01'
scenario_direct_headcount:
type: integer
example: 0
scenario_subtree_headcount:
type: integer
example: 0
scenario_direct_monthly_cost_cents:
type: integer
example: 0
scenario_subtree_monthly_cost_cents:
type: integer
example: 0
velocity_completed_sp:
type: integer
example: 0
velocity_team_count:
type: integer
example: 0
computed_at:
type: string
example: '2025-09-06T12:00:00Z'
metrics:
type: object
properties: { }
tags:
- Scenarios
parameters:
-
in: path
name: slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'The ID of the scenario.'
example: 1
required: true
schema:
type: integer
'/api/v1/scenarios/{scenario_slug}/delta':
get:
summary: 'Show changed-record deltas between a scenario and its comparison source.'
operationId: showChangedRecordDeltasBetweenAScenarioAndItsComparisonSource
description: ''
parameters:
-
in: query
name: compare
description: 'Optional comparison source. Use "baseline" to compare against the live baseline instead of the scenario''s source.'
example: baseline
required: false
schema:
type: string
description: 'Optional comparison source. Use "baseline" to compare against the live baseline instead of the scenario''s source.'
example: baseline
nullable: true
-
in: query
name: as_of
description: 'Optional comparison date (YYYY-MM-DD). Dates up to today use recorded snapshots; later dates are projected from dated placements, pay and approved deployments. Ignored for archived scenarios.'
example: '2028-01-01'
required: false
schema:
type: string
description: 'Optional comparison date (YYYY-MM-DD). Dates up to today use recorded snapshots; later dates are projected from dated placements, pay and approved deployments. Ignored for archived scenarios.'
example: '2028-01-01'
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
scenario:
id: 7
name: 'FY26 Restructure'
slug: fy26-restructure
status: draft
kind: planning
notes: 'Budget-cut planning run.'
live_from: null
live_to: null
locked_at: null
archived_at: null
is_read_only: false
source_scenario_id: null
created_at: '2026-03-01T09:00:00Z'
updated_at: '2026-03-01T09:00:00Z'
source: null
source_label: 'Live baseline'
as_of: null
counts:
added: 1
changed: 1
removed: 0
total: 2
families:
-
family: Teams
counts:
added: 1
changed: 0
removed: 0
total: 1
files:
- 'team:44'
-
family: 'Scenario Metrics'
counts:
added: 0
changed: 1
removed: 0
total: 1
files:
- 'metrics:summary'
files:
-
key: 'team:44'
family: Teams
status: added
title: 'Platform Enablement'
path: teams/platform-enablement
icon: users
added_lines: 4
removed_lines: 0
activity_event_ids:
- 311
hunks:
-
title: 'Team details'
status: added
lines:
-
type: added
prefix: +
field: Name
content: 'Name: Platform Enablement'
metrics:
-
key: 'metrics:summary'
family: 'Scenario Metrics'
status: changed
title: 'Scenario metrics'
path: metrics/summary
icon: chart-bar
added_lines: 1
removed_lines: 1
activity_event_ids: []
hunks:
-
title: Headcount
status: changed
lines:
-
type: removed
prefix: '-'
field: Headcount
content: 'Headcount: 123'
-
type: added
prefix: +
field: Headcount
content: 'Headcount: 118'
properties:
scenario:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: 'FY26 Restructure'
slug:
type: string
example: fy26-restructure
status:
type: string
example: draft
kind:
type: string
example: planning
notes:
type: string
example: 'Budget-cut planning run.'
live_from:
type: string
example: null
nullable: true
live_to:
type: string
example: null
nullable: true
locked_at:
type: string
example: null
nullable: true
archived_at:
type: string
example: null
nullable: true
is_read_only:
type: boolean
example: false
source_scenario_id:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-03-01T09:00:00Z'
updated_at:
type: string
example: '2026-03-01T09:00:00Z'
source:
type: string
example: null
nullable: true
source_label:
type: string
example: 'Live baseline'
as_of:
type: string
example: null
nullable: true
counts:
type: object
properties:
added:
type: integer
example: 1
changed:
type: integer
example: 1
removed:
type: integer
example: 0
total:
type: integer
example: 2
families:
type: array
example:
-
family: Teams
counts:
added: 1
changed: 0
removed: 0
total: 1
files:
- 'team:44'
-
family: 'Scenario Metrics'
counts:
added: 0
changed: 1
removed: 0
total: 1
files:
- 'metrics:summary'
items:
type: object
properties:
family:
type: string
example: Teams
counts:
type: object
properties:
added:
type: integer
example: 1
changed:
type: integer
example: 0
removed:
type: integer
example: 0
total:
type: integer
example: 1
files:
type: array
example:
- 'team:44'
items:
type: string
files:
type: array
example:
-
key: 'team:44'
family: Teams
status: added
title: 'Platform Enablement'
path: teams/platform-enablement
icon: users
added_lines: 4
removed_lines: 0
activity_event_ids:
- 311
hunks:
-
title: 'Team details'
status: added
lines:
-
type: added
prefix: +
field: Name
content: 'Name: Platform Enablement'
items:
type: object
properties:
key:
type: string
example: 'team:44'
family:
type: string
example: Teams
status:
type: string
example: added
title:
type: string
example: 'Platform Enablement'
path:
type: string
example: teams/platform-enablement
icon:
type: string
example: users
added_lines:
type: integer
example: 4
removed_lines:
type: integer
example: 0
activity_event_ids:
type: array
example:
- 311
items:
type: integer
hunks:
type: array
example:
-
title: 'Team details'
status: added
lines:
-
type: added
prefix: +
field: Name
content: 'Name: Platform Enablement'
items:
type: object
properties:
title:
type: string
example: 'Team details'
status:
type: string
example: added
lines:
type: array
example:
-
type: added
prefix: +
field: Name
content: 'Name: Platform Enablement'
items:
type: object
properties:
type:
type: string
example: added
prefix:
type: string
example: +
field:
type: string
example: Name
content:
type: string
example: 'Name: Platform Enablement'
metrics:
type: array
example:
-
key: 'metrics:summary'
family: 'Scenario Metrics'
status: changed
title: 'Scenario metrics'
path: metrics/summary
icon: chart-bar
added_lines: 1
removed_lines: 1
activity_event_ids: []
hunks:
-
title: Headcount
status: changed
lines:
-
type: removed
prefix: '-'
field: Headcount
content: 'Headcount: 123'
-
type: added
prefix: +
field: Headcount
content: 'Headcount: 118'
items:
type: object
properties:
key:
type: string
example: 'metrics:summary'
family:
type: string
example: 'Scenario Metrics'
status:
type: string
example: changed
title:
type: string
example: 'Scenario metrics'
path:
type: string
example: metrics/summary
icon:
type: string
example: chart-bar
added_lines:
type: integer
example: 1
removed_lines:
type: integer
example: 1
activity_event_ids:
type: array
example: []
hunks:
type: array
example:
-
title: Headcount
status: changed
lines:
-
type: removed
prefix: '-'
field: Headcount
content: 'Headcount: 123'
-
type: added
prefix: +
field: Headcount
content: 'Headcount: 118'
items:
type: object
properties:
title:
type: string
example: Headcount
status:
type: string
example: changed
lines:
type: array
example:
-
type: removed
prefix: '-'
field: Headcount
content: 'Headcount: 123'
-
type: added
prefix: +
field: Headcount
content: 'Headcount: 118'
items:
type: object
properties:
type:
type: string
example: removed
prefix:
type: string
example: '-'
field:
type: string
example: Headcount
content:
type: string
example: 'Headcount: 123'
tags:
- Scenarios
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'Scenario id or slug.'
example: fy26-restructure
required: true
schema:
type: string
'/api/v1/scenarios/{scenario_slug}/timeline':
get:
summary: "Show a scenario's path against its comparison source on several dates."
operationId: showAScenariosPathAgainstItsComparisonSourceOnSeveralDates
description: "One call returns headcount, FTE and monthly cost (total, people and agent)\nfor the scenario and its source on each date, plus the difference, so an\nagent can draw the path without calling the delta once per date. Dates up\nto today read recorded snapshots; later dates are projected from dated\nplacements, pay records and approved AI deployments. Cost figures need\n`costs.read` and are otherwise removed."
parameters:
-
in: query
name: compare
description: 'Optional comparison source. Use "baseline" to compare against the live baseline instead of the scenario''s source.'
example: baseline
required: false
schema:
type: string
description: 'Optional comparison source. Use "baseline" to compare against the live baseline instead of the scenario''s source.'
example: baseline
enum:
- baseline
nullable: true
-
in: query
name: dates
description: 'Must be a valid date in the format Y-m-d. Must be a date after or equal to 1970-01-01. Must be a date before or equal to 2076-10-11.'
example:
- '2039-11-03'
required: false
schema:
type: array
description: 'Must be a valid date in the format Y-m-d. Must be a date after or equal to 1970-01-01. Must be a date before or equal to 2076-10-11.'
example:
- '2039-11-03'
items:
type: string
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
scenario:
id: 7
name: 'Path to 2030'
slug: path-to-2030
source: null
source_label: 'Live baseline'
has_dated_changes: true
last_change: '2030-06-30'
points:
-
date: '2026-09-27'
label: Today
projected: false
scenario:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
source:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
difference:
headcount: 0
fte: 0
cost: 0
people_cost: 0
agent_cost: 0
-
date: '2028-01-01'
label: '2028'
projected: true
scenario:
headcount: 936
fte: 903.1
cost: 890000000
people_cost: 868000000
agent_cost: 22000000
source:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
difference:
headcount: -64
fte: -59.3
cost: -44000000
people_cost: -65000000
agent_cost: 21000000
properties:
scenario:
type: object
properties:
id:
type: integer
example: 7
name:
type: string
example: 'Path to 2030'
slug:
type: string
example: path-to-2030
source:
type: string
example: null
nullable: true
source_label:
type: string
example: 'Live baseline'
has_dated_changes:
type: boolean
example: true
last_change:
type: string
example: '2030-06-30'
points:
type: array
example:
-
date: '2026-09-27'
label: Today
projected: false
scenario:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
source:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
difference:
headcount: 0
fte: 0
cost: 0
people_cost: 0
agent_cost: 0
-
date: '2028-01-01'
label: '2028'
projected: true
scenario:
headcount: 936
fte: 903.1
cost: 890000000
people_cost: 868000000
agent_cost: 22000000
source:
headcount: 1000
fte: 962.4
cost: 934000000
people_cost: 933000000
agent_cost: 1000000
difference:
headcount: -64
fte: -59.3
cost: -44000000
people_cost: -65000000
agent_cost: 21000000
items:
type: object
properties:
date:
type: string
example: '2026-09-27'
label:
type: string
example: Today
projected:
type: boolean
example: false
scenario:
type: object
properties:
headcount:
type: integer
example: 1000
fte:
type: number
example: 962.4
cost:
type: integer
example: 934000000
people_cost:
type: integer
example: 933000000
agent_cost:
type: integer
example: 1000000
source:
type: object
properties:
headcount:
type: integer
example: 1000
fte:
type: number
example: 962.4
cost:
type: integer
example: 934000000
people_cost:
type: integer
example: 933000000
agent_cost:
type: integer
example: 1000000
difference:
type: object
properties:
headcount:
type: integer
example: 0
fte:
type: integer
example: 0
cost:
type: integer
example: 0
people_cost:
type: integer
example: 0
agent_cost:
type: integer
example: 0
409:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Archived scenarios keep the figures recorded when they were archived. Use the scenario delta instead.'
properties:
message:
type: string
example: 'Archived scenarios keep the figures recorded when they were archived. Use the scenario delta instead.'
tags:
- Scenarios
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'Scenario id or slug.'
example: path-to-2030
required: true
schema:
type: string
'/api/v1/scenarios/{scenario_slug}/promote':
post:
summary: 'Promote a planning scenario to the live baseline.'
operationId: promoteAPlanningScenarioToTheLiveBaseline
description: 'Queues the existing promotion pipeline with type `scenario_promotion`.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
202:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Scenario promotion started. Promotion in progress.'
status: queued
scenario_id: 1
tasks_url: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
properties:
message:
type: string
example: 'Scenario promotion started. Promotion in progress.'
status:
type: string
example: queued
scenario_id:
type: integer
example: 1
tasks_url:
type: string
example: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
tags:
- Scenarios
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
confirmed_promotion:
type: boolean
description: 'Optional confirmation flag for audit.'
example: true
nullable: true
confirmed_archive:
type: boolean
description: 'Optional confirmation flag for audit.'
example: true
nullable: true
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'The ID of the scenario.'
example: 1
required: true
schema:
type: integer
'/api/v1/scenarios/{scenario_slug}/submit':
post:
summary: 'Submit the scenario for review.'
operationId: submitTheScenarioForReview
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: 'FY26 Cost Optimisation'
status: under_review
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'FY26 Cost Optimisation'
status:
type: string
example: under_review
tags:
- Scenarios
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'The ID of the scenario.'
example: 1
required: true
schema:
type: integer
'/api/v1/scenarios/{scenario_slug}/approve':
post:
summary: 'Approve the scenario.'
operationId: approveTheScenario
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: 'FY26 Cost Optimisation'
status: approved
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'FY26 Cost Optimisation'
status:
type: string
example: approved
tags:
- Scenarios
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'The ID of the scenario.'
example: 1
required: true
schema:
type: integer
/api/v1/snapshots:
get:
summary: 'List baseline snapshots.'
operationId: listBaselineSnapshots
description: ''
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
-
in: query
name: 'filter[status]'
description: 'Filter by status.'
example: archived
required: false
schema:
type: string
description: 'Filter by status.'
example: archived
-
in: query
name: 'fields[scenarios]'
description: 'Sparse fields for scenarios.'
example: 'id,name,kind'
required: false
schema:
type: string
description: 'Sparse fields for scenarios.'
example: 'id,name,kind'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
-
in: query
name: as_of
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 12
name: 'Baseline Snapshot 2025-11-01'
kind: baseline_archive
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 12
name: 'Baseline Snapshot 2025-11-01'
kind: baseline_archive
items:
type: object
properties:
id:
type: integer
example: 12
name:
type: string
example: 'Baseline Snapshot 2025-11-01'
kind:
type: string
example: baseline_archive
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
tags:
- Snapshots
'/api/v1/snapshots/{scenario_slug}':
get:
summary: 'Display a baseline snapshot.'
operationId: displayABaselineSnapshot
description: ''
parameters:
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: teams,aggregate.'
example: aggregate
-
in: query
name: as_of
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
required: false
schema:
type: string
description: 'Snapshot date for aggregates. Format: YYYY-MM-DD.'
example: '2025-09-01'
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 12
name: 'Baseline Snapshot 2025-11-01'
kind: baseline_archive
status: archived
properties:
data:
type: object
properties:
id:
type: integer
example: 12
name:
type: string
example: 'Baseline Snapshot 2025-11-01'
kind:
type: string
example: baseline_archive
status:
type: string
example: archived
tags:
- Snapshots
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'Snapshot id.'
example: 12
required: true
schema:
type: integer
'/api/v1/snapshots/{scenario_slug}/restore':
post:
summary: 'Restore a baseline snapshot to become the live baseline.'
operationId: restoreABaselineSnapshotToBecomeTheLiveBaseline
description: 'Queues the existing promotion pipeline with type `snapshot_restore`.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
202:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Snapshot restore started. Promotion in progress.'
status: queued
snapshot_id: 12
tasks_url: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
properties:
message:
type: string
example: 'Snapshot restore started. Promotion in progress.'
status:
type: string
example: queued
snapshot_id:
type: integer
example: 12
tasks_url:
type: string
example: 'https://app.orgonaut.test/api/v1/scenarios/tasks'
tags:
- Snapshots
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
confirmed_promotion:
type: boolean
description: 'Optional confirmation flag for audit.'
example: true
nullable: true
confirmed_archive:
type: boolean
description: 'Optional confirmation flag for audit.'
example: true
nullable: true
parameters:
-
in: path
name: scenario_slug
description: 'The slug of the scenario.'
example: ab
required: true
schema:
type: string
-
in: path
name: scenario
description: 'Snapshot id.'
example: 12
required: true
schema:
type: integer
/api/v1/team-types/search:
get:
summary: 'Search Team Types for the active tenant.'
operationId: searchTeamTypesForTheActiveTenant
description: "Returns up to 20 matching types ordered by display order then name.\nRequires `settings.manage` ability."
parameters:
-
in: query
name: q
description: 'Search term applied to name and slug.'
example: stream
required: false
schema:
type: string
description: 'Search term applied to name and slug.'
example: stream
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
name: Stream-aligned
slug: stream-aligned
color: '#fbbf24'
description: null
is_active: true
display_order: 0
properties:
data:
type: array
example:
-
id: 1
name: Stream-aligned
slug: stream-aligned
color: '#fbbf24'
description: null
is_active: true
display_order: 0
items:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Stream-aligned
slug:
type: string
example: stream-aligned
color:
type: string
example: '#fbbf24'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 0
tags:
- 'Team Types'
/api/v1/team-types:
post:
summary: 'Create a Team Type for the active tenant.'
operationId: createATeamTypeForTheActiveTenant
description: 'Requires `settings.manage` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
name: Platform
slug: platform
color: '#7c3aed'
description: null
is_active: true
display_order: 0
properties:
data:
type: object
properties:
id:
type: integer
example: 5
name:
type: string
example: Platform
slug:
type: string
example: platform
color:
type: string
example: '#7c3aed'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 0
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The name has already been taken.'
errors:
name:
- 'The name has already been taken.'
properties:
message:
type: string
example: 'The name has already been taken.'
errors:
type: object
properties:
name:
type: array
example:
- 'The name has already been taken.'
items:
type: string
tags:
- 'Team Types'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name. Max 120 characters. Must be unique within the tenant.'
example: Platform
slug:
type: string
description: 'URL-safe slug. Auto-derived from name if omitted. Max 120 characters. Must be unique within the tenant.'
example: platform
nullable: true
color:
type: string
description: 'Hex colour code with or without leading `#`.'
example: '#7c3aed'
nullable: true
description:
type: string
description: 'Optional description. Max 500 characters.'
example: 'Infrastructure and tooling teams'
nullable: true
display_order:
type: integer
description: 'Sort order for selectors. Between 0 and 999.'
example: 2
nullable: true
required:
- name
'/api/v1/team-types/{teamType_id}':
get:
summary: 'Show a specific Team Type.'
operationId: showASpecificTeamType
description: 'Requires `settings.manage` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: Stream-aligned
slug: stream-aligned
color: '#fbbf24'
description: null
is_active: true
display_order: 0
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Stream-aligned
slug:
type: string
example: stream-aligned
color:
type: string
example: '#fbbf24'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 0
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
tags:
- 'Team Types'
patch:
summary: 'Update a Team Type.'
operationId: updateATeamType
description: 'Requires `settings.manage` ability. All fields are optional for partial updates.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 1
name: Platform
slug: platform
color: '#7c3aed'
description: null
is_active: true
display_order: 2
properties:
data:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: Platform
slug:
type: string
example: platform
color:
type: string
example: '#7c3aed'
description:
type: string
example: null
nullable: true
is_active:
type: boolean
example: true
display_order:
type: integer
example: 2
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The name has already been taken.'
errors:
name:
- 'The name has already been taken.'
properties:
message:
type: string
example: 'The name has already been taken.'
errors:
type: object
properties:
name:
type: array
example:
- 'The name has already been taken.'
items:
type: string
tags:
- 'Team Types'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name. Max 120 characters. Must be unique within the tenant.'
example: Platform
slug:
type: string
description: 'URL-safe slug. Auto-derived from name if omitted on create; not auto-updated on edit. Max 120 characters. Must be unique within the tenant.'
example: platform
nullable: true
color:
type: string
description: 'Hex colour code with or without leading `#`.'
example: '#7c3aed'
nullable: true
description:
type: string
description: 'Optional description. Max 500 characters.'
example: 'Infrastructure and tooling teams'
nullable: true
is_active:
type: boolean
description: 'Whether the type is active.'
example: true
display_order:
type: integer
description: 'Sort order for selectors. Between 0 and 999.'
example: 2
nullable: true
delete:
summary: 'Delete a Team Type.'
operationId: deleteATeamType
description: "Requires `settings.manage` ability. Associated teams will have their\n`team_type_id` set to null on delete."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
404:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Not found.'
properties:
message:
type: string
example: 'Not found.'
tags:
- 'Team Types'
parameters:
-
in: path
name: teamType_id
description: 'The ID of the teamType.'
example: 11
required: true
schema:
type: integer
-
in: path
name: teamType
description: 'The ID of the team type.'
example: 1
required: true
schema:
type: integer
/api/v1/teams:
get:
summary: 'Display a paginated listing of teams.'
operationId: displayAPaginatedListingOfTeams
description: 'Requires `teams.read` ability.'
parameters:
-
in: query
name: page
description: 'The page number.'
example: 1
required: false
schema:
type: integer
description: 'The page number.'
example: 1
-
in: query
name: per_page
description: 'Max 100.'
example: 25
required: false
schema:
type: integer
description: 'Max 100.'
example: 25
-
in: query
name: scenario
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
required: false
schema:
type: string
description: 'Scenario slug to read from. Omit for the Live Baseline. Unknown scenarios return 400.'
example: q3-plan
-
in: query
name: 'filter[scenario_id]'
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
required: false
schema:
type: string
description: 'Scenario id or slug; `baseline`/`live`/`null` for the Live Baseline. Overrides `scenario`.'
example: '7'
-
in: query
name: 'filter[scenario]'
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
required: false
schema:
type: string
description: 'Same as filter[scenario_id]; also accepts `current`.'
example: q3-plan
-
in: query
name: sort
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
required: false
schema:
type: string
description: 'Comma-separated columns, prefix with - for DESC. Allowed: id,name,created_at.'
example: '-created_at,name'
-
in: query
name: 'filter[department_id]'
description: 'Filter by department id.'
example: 5
required: false
schema:
type: integer
description: 'Filter by department id.'
example: 5
-
in: query
name: 'filter[org_unit_id]'
description: 'Filter by org unit id (department subtree).'
example: 10
required: false
schema:
type: integer
description: 'Filter by org unit id (department subtree).'
example: 10
-
in: query
name: 'fields[teams]'
description: 'Sparse fields for teams.'
example: 'id,name'
required: false
schema:
type: string
description: 'Sparse fields for teams.'
example: 'id,name'
-
in: query
name: include
description: 'Comma-separated relationships. Allowed: aggregate.'
example: aggregate
required: false
schema:
type: string
description: 'Comma-separated relationships. Allowed: aggregate.'
example: aggregate
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 15
name: 'Team CúChulainn'
team_type_id: 3
team_type:
id: 3
name: Cross-functional
slug: cross-functional
purpose: 'Platform delivery'
parent_org_unit_id: 202
scenario_id: 1
valid_from: '2025-01-10'
valid_to: null
created_at: '2025-01-10T09:00:00Z'
links:
first: null
last: null
prev: null
next: null
meta:
total: 1
current_page: 1
per_page: 15
last_page: 1
properties:
data:
type: array
example:
-
id: 15
name: 'Team CúChulainn'
team_type_id: 3
team_type:
id: 3
name: Cross-functional
slug: cross-functional
purpose: 'Platform delivery'
parent_org_unit_id: 202
scenario_id: 1
valid_from: '2025-01-10'
valid_to: null
created_at: '2025-01-10T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
team_type_id:
type: integer
example: 3
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Cross-functional
slug:
type: string
example: cross-functional
purpose:
type: string
example: 'Platform delivery'
parent_org_unit_id:
type: integer
example: 202
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-10'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
links:
type: object
properties:
first:
type: string
example: null
nullable: true
last:
type: string
example: null
nullable: true
prev:
type: string
example: null
nullable: true
next:
type: string
example: null
nullable: true
meta:
type: object
properties:
total:
type: integer
example: 1
current_page:
type: integer
example: 1
per_page:
type: integer
example: 15
last_page:
type: integer
example: 1
400:
description: ''
content:
application/json:
schema:
type: object
example:
code: query.invalid_parameter
message: 'Unsupported sort: salary'
details:
allowed:
- id
- name
- created_at
properties:
code:
type: string
example: query.invalid_parameter
message:
type: string
example: 'Unsupported sort: salary'
details:
type: object
properties:
allowed:
type: array
example:
- id
- name
- created_at
items:
type: string
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'The given data was invalid.'
errors:
per_page:
- 'The per page must be at least 1.'
properties:
message:
type: string
example: 'The given data was invalid.'
errors:
type: object
properties:
per_page:
type: array
example:
- 'The per page must be at least 1.'
items:
type: string
tags:
- Teams
post:
summary: 'Store a newly created team.'
operationId: storeANewlyCreatedTeam
description: "Requires `teams.create` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 15
name: 'Team CúChulainn'
team_type_id: 3
team_type:
id: 3
name: Cross-functional
slug: cross-functional
purpose: 'Platform delivery'
parent_org_unit_id: 202
scenario_id: 1
valid_from: '2025-01-10'
valid_to: null
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
team_type_id:
type: integer
example: 3
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Cross-functional
slug:
type: string
example: cross-functional
purpose:
type: string
example: 'Platform delivery'
parent_org_unit_id:
type: integer
example: 202
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-10'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Teams
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Team name. Must not be greater than 255 characters.'
example: Platform
team_type_id:
type: integer
description: 'Optional team type id. The id of an existing record in the team_types table.'
example: 1
nullable: true
purpose:
type: string
description: 'Optional purpose/mission. Must not be greater than 255 characters.'
example: 'Internal platforms'
nullable: true
valid_from:
type: string
description: 'Date the team becomes active. Must be a valid date.'
example: '2025-01-01'
valid_to:
type: string
description: 'Optional date the team becomes inactive. Must be a valid date. Must be a date after or equal to valid_from.'
example: '2025-12-31'
nullable: true
parent_org_unit_id:
type: integer
description: nullable
example: 7
nullable: true
required:
- name
- valid_from
'/api/v1/teams/{id}':
get:
summary: 'Display a specific team.'
operationId: displayASpecificTeam
description: 'Requires `teams.read` ability.'
parameters:
-
in: query
name: 'filter[scenario_id]'
description: 'Filter by scenario ID.'
example: 1
required: false
schema:
type: integer
description: 'Filter by scenario ID.'
example: 1
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 15
name: 'Team CúChulainn'
team_type_id: 3
team_type:
id: 3
name: Cross-functional
slug: cross-functional
purpose: 'Platform delivery'
parent_org_unit_id: 202
scenario_id: 1
valid_from: '2025-01-10'
valid_to: null
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team CúChulainn'
team_type_id:
type: integer
example: 3
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Cross-functional
slug:
type: string
example: cross-functional
purpose:
type: string
example: 'Platform delivery'
parent_org_unit_id:
type: integer
example: 202
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-10'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Teams
put:
summary: 'Update a team.'
operationId: updateATeam
description: "Requires `teams.update` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 15
name: 'Team Fianna'
team_type_id: 3
team_type:
id: 3
name: Cross-functional
slug: cross-functional
purpose: 'Platform delivery'
parent_org_unit_id: 202
scenario_id: 1
valid_from: '2025-01-10'
valid_to: null
created_at: '2025-01-10T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 15
name:
type: string
example: 'Team Fianna'
team_type_id:
type: integer
example: 3
team_type:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Cross-functional
slug:
type: string
example: cross-functional
purpose:
type: string
example: 'Platform delivery'
parent_org_unit_id:
type: integer
example: 202
scenario_id:
type: integer
example: 1
valid_from:
type: string
example: '2025-01-10'
valid_to:
type: string
example: null
nullable: true
created_at:
type: string
example: '2025-01-10T09:00:00Z'
tags:
- Teams
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Team name when changing team metadata. Must not be greater than 255 characters.'
example: Platform
team_type_id:
type: integer
description: 'Optional team type id. The id of an existing record in the team_types table.'
example: 1
nullable: true
purpose:
type: string
description: 'Optional purpose/mission. Must not be greater than 255 characters.'
example: 'Internal platforms'
nullable: true
valid_from:
type: string
description: 'Date the team becomes active when changing validity. Must be a valid date.'
example: '2025-01-01'
valid_to:
type: string
description: 'Optional date the team becomes inactive. Must be a valid date. Must be a date after or equal to valid_from.'
example: '2025-12-31'
nullable: true
parent_org_unit_id:
type: integer
description: nullable
example: 7
nullable: true
delete:
summary: 'Delete a team.'
operationId: deleteATeam
description: "Requires `teams.delete` ability.\nCLI-scoped tokens can call this endpoint only inside an active mutable scenario."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
204:
description: ''
content:
application/json:
schema:
type: object
example: { }
properties: { }
tags:
- Teams
parameters:
-
in: path
name: id
description: 'The ID of the team.'
example: 11
required: true
schema:
type: integer
'/api/v1/teams/{team_id}/velocity':
get:
summary: 'Get velocity stats for a team in a sprint.'
operationId: getVelocityStatsForATeamInASprint
description: ''
parameters:
-
in: query
name: sprint_id
description: 'The sprint to query.'
example: 11
required: false
schema:
type: integer
description: 'The sprint to query.'
example: 11
nullable: true
-
in: query
name: as_of
description: 'date Mutually exclusive with sprint_id.'
example: ab
required: false
schema:
type: string
description: 'date Mutually exclusive with sprint_id.'
example: ab
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
team_id: 12
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
committed_sp: 34
completed_sp: 31
scope_added_sp: 3
carried_over_sp: 5
stories_done: 12
source: jira
properties:
data:
type: object
properties:
team_id:
type: integer
example: 12
sprint_id:
type: integer
example: 42
period:
type: object
properties:
label:
type: string
example: 'Sprint 18'
starts_at:
type: string
example: '2025-09-01'
ends_at:
type: string
example: '2025-09-14'
committed_sp:
type: integer
example: 34
completed_sp:
type: integer
example: 31
scope_added_sp:
type: integer
example: 3
carried_over_sp:
type: integer
example: 5
stories_done:
type: integer
example: 12
source:
type: string
example: jira
tags:
- 'Teams — Velocity'
parameters:
-
in: path
name: team_id
description: 'The ID of the team.'
example: 11
required: true
schema:
type: integer
-
in: path
name: team
description: 'The team ID.'
example: 12
required: true
schema:
type: integer
'/api/v1/teams/{team_id}/velocity/series':
get:
summary: 'Get a velocity series for a team.'
operationId: getAVelocitySeriesForATeam
description: ''
parameters:
-
in: query
name: from_sprint_id
description: 'Starting sprint ID.'
example: 11
required: false
schema:
type: integer
description: 'Starting sprint ID.'
example: 11
nullable: true
-
in: query
name: to_sprint_id
description: 'Ending sprint ID.'
example: 11
required: false
schema:
type: integer
description: 'Ending sprint ID.'
example: 11
nullable: true
-
in: query
name: from
description: 'date Start date.'
example: ab
required: false
schema:
type: string
description: 'date Start date.'
example: ab
nullable: true
-
in: query
name: to
description: 'date End date.'
example: ab
required: false
schema:
type: string
description: 'date End date.'
example: ab
nullable: true
-
in: query
name: limit
description: 'Maximum results. Defaults to 12.'
example: 11
required: false
schema:
type: integer
description: 'Maximum results. Defaults to 12.'
example: 11
nullable: true
-
in: query
name: order
description: 'asc or desc. Defaults to asc.'
example: ab
required: false
schema:
type: string
description: 'asc or desc. Defaults to asc.'
example: ab
nullable: true
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "demo"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
team_id: 12
sprint_id: 41
period:
label: 'Sprint 17'
starts_at: '2025-08-18'
ends_at: '2025-08-31'
committed_sp: 29
completed_sp: 27
scope_added_sp: 2
carried_over_sp: 4
stories_done: 10
source: jira
-
team_id: 12
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
committed_sp: 34
completed_sp: 31
scope_added_sp: 3
carried_over_sp: 5
stories_done: 12
source: jira
properties:
data:
type: array
example:
-
team_id: 12
sprint_id: 41
period:
label: 'Sprint 17'
starts_at: '2025-08-18'
ends_at: '2025-08-31'
committed_sp: 29
completed_sp: 27
scope_added_sp: 2
carried_over_sp: 4
stories_done: 10
source: jira
-
team_id: 12
sprint_id: 42
period:
label: 'Sprint 18'
starts_at: '2025-09-01'
ends_at: '2025-09-14'
committed_sp: 34
completed_sp: 31
scope_added_sp: 3
carried_over_sp: 5
stories_done: 12
source: jira
items:
type: object
properties:
team_id:
type: integer
example: 12
sprint_id:
type: integer
example: 41
period:
type: object
properties:
label:
type: string
example: 'Sprint 17'
starts_at:
type: string
example: '2025-08-18'
ends_at:
type: string
example: '2025-08-31'
committed_sp:
type: integer
example: 29
completed_sp:
type: integer
example: 27
scope_added_sp:
type: integer
example: 2
carried_over_sp:
type: integer
example: 4
stories_done:
type: integer
example: 10
source:
type: string
example: jira
tags:
- 'Teams — Velocity'
parameters:
-
in: path
name: team_id
description: 'The ID of the team.'
example: 11
required: true
schema:
type: integer
-
in: path
name: team
description: 'The team ID.'
example: 12
required: true
schema:
type: integer
/api/v1/tenant-invitations:
get:
summary: 'List invitations for the current tenant.'
operationId: listInvitationsForTheCurrentTenant
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 17
tenant_id: 3
email: new.user@example.com
role: manager
state: pending
invited_by: 7
expires_at: '2026-03-14T09:00:00Z'
accepted_at: null
accepted_by_user_id: null
revoked_at: null
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
properties:
data:
type: array
example:
-
id: 17
tenant_id: 3
email: new.user@example.com
role: manager
state: pending
invited_by: 7
expires_at: '2026-03-14T09:00:00Z'
accepted_at: null
accepted_by_user_id: null
revoked_at: null
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
items:
type: object
properties:
id:
type: integer
example: 17
tenant_id:
type: integer
example: 3
email:
type: string
example: new.user@example.com
role:
type: string
example: manager
state:
type: string
example: pending
invited_by:
type: integer
example: 7
expires_at:
type: string
example: '2026-03-14T09:00:00Z'
accepted_at:
type: string
example: null
nullable: true
accepted_by_user_id:
type: string
example: null
nullable: true
revoked_at:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T09:00:00Z'
tags:
- 'Tenant Invitations'
post:
summary: 'Create a new tenant invitation.'
operationId: createANewTenantInvitation
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 17
tenant_id: 3
email: new.user@example.com
role: manager
state: pending
invited_by: 7
expires_at: '2026-03-14T09:00:00Z'
accepted_at: null
accepted_by_user_id: null
revoked_at: null
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T09:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 17
tenant_id:
type: integer
example: 3
email:
type: string
example: new.user@example.com
role:
type: string
example: manager
state:
type: string
example: pending
invited_by:
type: integer
example: 7
expires_at:
type: string
example: '2026-03-14T09:00:00Z'
accepted_at:
type: string
example: null
nullable: true
accepted_by_user_id:
type: string
example: null
nullable: true
revoked_at:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T09:00:00Z'
tags:
- 'Tenant Invitations'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: 'Invitee email address.'
example: '"new.user@example.com"'
role:
type: string
description: 'User type to assign on acceptance. Must be one of `admin`, `manager`, `member`, or `viewer`.'
example: '"manager"'
required:
- email
- role
'/api/v1/tenant-invitations/{invite}/resend':
post:
summary: 'Resend a pending invitation and revoke the existing pending token.'
operationId: resendAPendingInvitationAndRevokeTheExistingPendingToken
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 23
tenant_id: 3
email: new.user@example.com
role: manager
state: pending
invited_by: 7
expires_at: '2026-03-21T09:00:00Z'
accepted_at: null
accepted_by_user_id: null
revoked_at: null
created_at: '2026-03-07T10:00:00Z'
updated_at: '2026-03-07T10:00:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 23
tenant_id:
type: integer
example: 3
email:
type: string
example: new.user@example.com
role:
type: string
example: manager
state:
type: string
example: pending
invited_by:
type: integer
example: 7
expires_at:
type: string
example: '2026-03-21T09:00:00Z'
accepted_at:
type: string
example: null
nullable: true
accepted_by_user_id:
type: string
example: null
nullable: true
revoked_at:
type: string
example: null
nullable: true
created_at:
type: string
example: '2026-03-07T10:00:00Z'
updated_at:
type: string
example: '2026-03-07T10:00:00Z'
tags:
- 'Tenant Invitations'
parameters:
-
in: path
name: invite
description: 'Invitation id.'
example: 17
required: true
schema:
type: integer
'/api/v1/tenant-invitations/{invite}/revoke':
post:
summary: 'Revoke a pending invitation.'
operationId: revokeAPendingInvitation
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 17
tenant_id: 3
email: new.user@example.com
role: manager
state: revoked
invited_by: 7
expires_at: '2026-03-14T09:00:00Z'
accepted_at: null
accepted_by_user_id: null
revoked_at: '2026-03-07T10:15:00Z'
created_at: '2026-03-07T09:00:00Z'
updated_at: '2026-03-07T10:15:00Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 17
tenant_id:
type: integer
example: 3
email:
type: string
example: new.user@example.com
role:
type: string
example: manager
state:
type: string
example: revoked
invited_by:
type: integer
example: 7
expires_at:
type: string
example: '2026-03-14T09:00:00Z'
accepted_at:
type: string
example: null
nullable: true
accepted_by_user_id:
type: string
example: null
nullable: true
revoked_at:
type: string
example: '2026-03-07T10:15:00Z'
created_at:
type: string
example: '2026-03-07T09:00:00Z'
updated_at:
type: string
example: '2026-03-07T10:15:00Z'
tags:
- 'Tenant Invitations'
parameters:
-
in: path
name: invite
description: 'Invitation id.'
example: 17
required: true
schema:
type: integer
/api/v1/tenant-members:
get:
summary: 'List active and archived tenant memberships.'
operationId: listActiveAndArchivedTenantMemberships
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
active:
-
tenant_id: 3
user_id: 42
name: "Aisling O'Neill"
email: aisling@example.com
role: admin
membership_state: active
archived_at: null
archived_by: null
reactivated_at: null
reactivated_by: null
archived:
-
tenant_id: 3
user_id: 51
name: 'Niall Byrne'
email: niall@example.com
role: member
membership_state: archived
archived_at: '2026-02-21T09:30:00Z'
archived_by: 42
reactivated_at: null
reactivated_by: null
properties:
data:
type: object
properties:
active:
type: array
example:
-
tenant_id: 3
user_id: 42
name: "Aisling O'Neill"
email: aisling@example.com
role: admin
membership_state: active
archived_at: null
archived_by: null
reactivated_at: null
reactivated_by: null
description: 'Active memberships.'
items:
type: object
properties:
tenant_id:
type: integer
example: 3
user_id:
type: integer
example: 42
name:
type: string
example: "Aisling O'Neill"
email:
type: string
example: aisling@example.com
role:
type: string
example: admin
membership_state:
type: string
example: active
archived_at:
type: string
example: null
nullable: true
archived_by:
type: string
example: null
nullable: true
reactivated_at:
type: string
example: null
nullable: true
reactivated_by:
type: string
example: null
nullable: true
archived:
type: array
example:
-
tenant_id: 3
user_id: 51
name: 'Niall Byrne'
email: niall@example.com
role: member
membership_state: archived
archived_at: '2026-02-21T09:30:00Z'
archived_by: 42
reactivated_at: null
reactivated_by: null
description: 'Archived memberships.'
items:
type: object
properties:
tenant_id:
type: integer
example: 3
user_id:
type: integer
example: 51
name:
type: string
example: 'Niall Byrne'
email:
type: string
example: niall@example.com
role:
type: string
example: member
membership_state:
type: string
example: archived
archived_at:
type: string
example: '2026-02-21T09:30:00Z'
archived_by:
type: integer
example: 42
reactivated_at:
type: string
example: null
nullable: true
reactivated_by:
type: string
example: null
nullable: true
tags:
- 'Tenant Members'
'/api/v1/tenant-members/{user}/archive':
patch:
summary: 'Archive a non-owner tenant membership.'
operationId: archiveANonOwnerTenantMembership
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
tenant_id: 3
user_id: 42
name: "Aisling O'Neill"
email: aisling@example.com
role: member
membership_state: archived
archived_at: '2026-03-07T10:15:00Z'
archived_by: 7
reactivated_at: null
reactivated_by: null
properties:
data:
type: object
properties:
tenant_id:
type: integer
example: 3
user_id:
type: integer
example: 42
description: 'Membership user id.'
name:
type: string
example: "Aisling O'Neill"
email:
type: string
example: aisling@example.com
role:
type: string
example: member
membership_state:
type: string
example: archived
description: 'Updated membership state.'
archived_at:
type: string
example: '2026-03-07T10:15:00Z'
archived_by:
type: integer
example: 7
reactivated_at:
type: string
example: null
nullable: true
reactivated_by:
type: string
example: null
nullable: true
tags:
- 'Tenant Members'
parameters:
-
in: path
name: user
description: 'Tenant user id.'
example: 42
required: true
schema:
type: integer
'/api/v1/tenant-members/{user}/reactivate':
patch:
summary: 'Reactivate an archived tenant membership.'
operationId: reactivateAnArchivedTenantMembership
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
tenant_id: 3
user_id: 42
name: "Aisling O'Neill"
email: aisling@example.com
role: member
membership_state: active
archived_at: '2026-03-01T10:15:00Z'
archived_by: 7
reactivated_at: '2026-03-07T11:05:00Z'
reactivated_by: 7
properties:
data:
type: object
properties:
tenant_id:
type: integer
example: 3
user_id:
type: integer
example: 42
description: 'Membership user id.'
name:
type: string
example: "Aisling O'Neill"
email:
type: string
example: aisling@example.com
role:
type: string
example: member
membership_state:
type: string
example: active
description: 'Updated membership state.'
archived_at:
type: string
example: '2026-03-01T10:15:00Z'
archived_by:
type: integer
example: 7
reactivated_at:
type: string
example: '2026-03-07T11:05:00Z'
reactivated_by:
type: integer
example: 7
tags:
- 'Tenant Members'
parameters:
-
in: path
name: user
description: 'Tenant user id.'
example: 42
required: true
schema:
type: integer
'/api/v1/tenant-members/{user}/role':
patch:
summary: 'Update a tenant member role without using ownership transfer.'
operationId: updateATenantMemberRoleWithoutUsingOwnershipTransfer
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
tenant_id: 3
user_id: 42
name: "Aisling O'Neill"
email: aisling@example.com
role: viewer
membership_state: active
archived_at: null
archived_by: null
reactivated_at: null
reactivated_by: null
properties:
data:
type: object
properties:
tenant_id:
type: integer
example: 3
user_id:
type: integer
example: 42
description: 'Membership user id.'
name:
type: string
example: "Aisling O'Neill"
email:
type: string
example: aisling@example.com
role:
type: string
example: viewer
description: 'Updated membership role.'
membership_state:
type: string
example: active
archived_at:
type: string
example: null
nullable: true
archived_by:
type: string
example: null
nullable: true
reactivated_at:
type: string
example: null
nullable: true
reactivated_by:
type: string
example: null
nullable: true
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'Archived memberships must be reactivated before changing the user type.'
code: tenancy.invalid_state
properties:
message:
type: string
example: 'Archived memberships must be reactivated before changing the user type.'
code:
type: string
example: tenancy.invalid_state
tags:
- 'Tenant Members'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
role:
type: string
description: 'User type to assign. Must be one of `admin`, `manager`, `member`, or `viewer`.'
example: '"viewer"'
required:
- role
parameters:
-
in: path
name: user
description: 'Tenant user id.'
example: 42
required: true
schema:
type: integer
/api/v1/tenant-members/transfer-ownership:
post:
summary: 'Transfer tenant ownership to an existing active admin.'
operationId: transferTenantOwnershipToAnExistingActiveAdmin
description: ''
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
status: ok
properties:
data:
type: object
properties:
status:
type: string
example: ok
tags:
- 'Tenant Members'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
target_user_id:
type: integer
description: 'Existing active admin user id.'
example: 42
required:
- target_user_id
/api/v1/work-activities:
get:
summary: 'List work activities for the active context.'
operationId: listWorkActivitiesForTheActiveContext
description: 'Requires `work.read` ability.'
parameters:
-
in: query
name: q
description: 'Search term applied to name and slug.'
example: triage
required: false
schema:
type: string
description: 'Search term applied to name and slug.'
example: triage
-
in: query
name: category
description: 'Filter by work category slug (see Settings → Work Categories).'
example: delivery
required: false
schema:
type: string
description: 'Filter by work category slug (see Settings → Work Categories).'
example: delivery
-
in: query
name: include_archived
description: 'Include archived activities.'
example: false
required: false
schema:
type: boolean
description: 'Include archived activities.'
example: false
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
-
id: 1
name: 'Triage support tickets'
slug: triage-support-tickets
category:
id: 2
name: Coordination
slug: coordination
color: '#f59e0b'
source: manual
description: null
archived_at: null
role_type_count: 2
team_count: 1
properties:
data:
type: array
example:
-
id: 1
name: 'Triage support tickets'
slug: triage-support-tickets
category:
id: 2
name: Coordination
slug: coordination
color: '#f59e0b'
source: manual
description: null
archived_at: null
role_type_count: 2
team_count: 1
items:
type: object
properties:
id:
type: integer
example: 1
name:
type: string
example: 'Triage support tickets'
slug:
type: string
example: triage-support-tickets
category:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Coordination
slug:
type: string
example: coordination
color:
type: string
example: '#f59e0b'
source:
type: string
example: manual
description:
type: string
example: null
nullable: true
archived_at:
type: string
example: null
nullable: true
role_type_count:
type: integer
example: 2
team_count:
type: integer
example: 1
tags:
- 'Work Catalog'
post:
summary: 'Create a work activity in the active context.'
operationId: createAWorkActivityInTheActiveContext
description: 'Requires `work.write` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
201:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
name: 'Draft release notes'
slug: draft-release-notes
category:
id: 2
name: Delivery
slug: delivery
color: '#f59e0b'
source: manual
description: null
archived_at: null
properties:
data:
type: object
properties:
id:
type: integer
example: 5
name:
type: string
example: 'Draft release notes'
slug:
type: string
example: draft-release-notes
category:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Delivery
slug:
type: string
example: delivery
color:
type: string
example: '#f59e0b'
source:
type: string
example: manual
description:
type: string
example: null
nullable: true
archived_at:
type: string
example: null
nullable: true
422:
description: ''
content:
application/json:
schema:
type: object
example:
message: 'A work activity with this name already exists in this context.'
errors:
name:
- 'A work activity with this name already exists in this context.'
properties:
message:
type: string
example: 'A work activity with this name already exists in this context.'
errors:
type: object
properties:
name:
type: array
example:
- 'A work activity with this name already exists in this context.'
items:
type: string
tags:
- 'Work Catalog'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name. Max 120 characters. Must be unique within the context.'
example: 'Draft release notes'
description:
type: string
description: 'Optional description. Max 2000 characters.'
example: 'Summarise shipped changes for customers'
nullable: true
work_category_id:
type: integer
description: "Work category identifier from the tenant's taxonomy."
example: 2
required:
- name
- work_category_id
'/api/v1/work-activities/{workActivity_id}':
get:
summary: 'Show a work activity with its role-type and team mappings.'
operationId: showAWorkActivityWithItsRoleTypeAndTeamMappings
description: 'Requires `work.read` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
name: 'Draft release notes'
slug: draft-release-notes
category:
id: 2
name: Delivery
slug: delivery
color: '#f59e0b'
source: manual
description: null
archived_at: null
role_types:
-
id: 3
name: Engineer
slug: engineer
time_share_pct: 15
teams:
-
id: 9
name: Payments
emphasis: primary
properties:
data:
type: object
properties:
id:
type: integer
example: 5
name:
type: string
example: 'Draft release notes'
slug:
type: string
example: draft-release-notes
category:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Delivery
slug:
type: string
example: delivery
color:
type: string
example: '#f59e0b'
source:
type: string
example: manual
description:
type: string
example: null
nullable: true
archived_at:
type: string
example: null
nullable: true
role_types:
type: array
example:
-
id: 3
name: Engineer
slug: engineer
time_share_pct: 15
items:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineer
slug:
type: string
example: engineer
time_share_pct:
type: integer
example: 15
teams:
type: array
example:
-
id: 9
name: Payments
emphasis: primary
items:
type: object
properties:
id:
type: integer
example: 9
name:
type: string
example: Payments
emphasis:
type: string
example: primary
tags:
- 'Work Catalog'
patch:
summary: 'Update a work activity.'
operationId: updateAWorkActivity
description: 'Requires `work.write` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
name: 'Draft customer release notes'
slug: draft-customer-release-notes
category:
id: 2
name: Delivery
slug: delivery
color: '#f59e0b'
source: manual
description: null
archived_at: null
properties:
data:
type: object
properties:
id:
type: integer
example: 5
name:
type: string
example: 'Draft customer release notes'
slug:
type: string
example: draft-customer-release-notes
category:
type: object
properties:
id:
type: integer
example: 2
name:
type: string
example: Delivery
slug:
type: string
example: delivery
color:
type: string
example: '#f59e0b'
source:
type: string
example: manual
description:
type: string
example: null
nullable: true
archived_at:
type: string
example: null
nullable: true
tags:
- 'Work Catalog'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 'Display name. Max 120 characters.'
example: 'Draft customer release notes'
description:
type: string
description: 'Optional description. Max 2000 characters.'
example: 'Customer-facing change summaries'
nullable: true
work_category_id:
type: integer
description: "Work category identifier from the tenant's taxonomy."
example: 2
parameters:
-
in: path
name: workActivity_id
description: 'The ID of the workActivity.'
example: 11
required: true
schema:
type: integer
-
in: path
name: workActivity
description: 'Work activity identifier.'
example: 5
required: true
schema:
type: integer
'/api/v1/work-activities/{workActivity_id}/archive':
post:
summary: 'Archive a work activity.'
operationId: archiveAWorkActivity
description: "Archived activities keep their mappings but are excluded from listings by default.\nRequires `work.write` ability."
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
archived_at: '2026-07-02T10:00:00.000000Z'
properties:
data:
type: object
properties:
id:
type: integer
example: 5
archived_at:
type: string
example: '2026-07-02T10:00:00.000000Z'
tags:
- 'Work Catalog'
parameters:
-
in: path
name: workActivity_id
description: 'The ID of the workActivity.'
example: 11
required: true
schema:
type: integer
-
in: path
name: workActivity
description: 'Work activity identifier.'
example: 5
required: true
schema:
type: integer
'/api/v1/work-activities/{workActivity_id}/restore':
post:
summary: 'Restore an archived work activity.'
operationId: restoreAnArchivedWorkActivity
description: 'Requires `work.write` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
archived_at: null
properties:
data:
type: object
properties:
id:
type: integer
example: 5
archived_at:
type: string
example: null
nullable: true
tags:
- 'Work Catalog'
parameters:
-
in: path
name: workActivity_id
description: 'The ID of the workActivity.'
example: 11
required: true
schema:
type: integer
-
in: path
name: workActivity
description: 'Work activity identifier.'
example: 5
required: true
schema:
type: integer
'/api/v1/work-activities/{workActivity_id}/role-types':
put:
summary: 'Replace the role-type mappings for a work activity.'
operationId: replaceTheRoleTypeMappingsForAWorkActivity
description: 'Requires `work.write` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
role_types:
-
id: 3
name: Engineer
slug: engineer
time_share_pct: 15
properties:
data:
type: object
properties:
id:
type: integer
example: 5
role_types:
type: array
example:
-
id: 3
name: Engineer
slug: engineer
time_share_pct: 15
items:
type: object
properties:
id:
type: integer
example: 3
name:
type: string
example: Engineer
slug:
type: string
example: engineer
time_share_pct:
type: integer
example: 15
tags:
- 'Work Catalog'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
role_types:
type: array
description: 'Full replacement set of mappings.'
example:
-
role_type_id: 3
time_share_pct: 15
items:
type: object
properties:
role_type_id:
type: integer
description: 'Role type identifier.'
example: 3
time_share_pct:
type: integer
description: "Share of the role's time (0–100)."
example: 15
required:
- role_type_id
- time_share_pct
required:
- role_types
parameters:
-
in: path
name: workActivity_id
description: 'The ID of the workActivity.'
example: 11
required: true
schema:
type: integer
-
in: path
name: workActivity
description: 'Work activity identifier.'
example: 5
required: true
schema:
type: integer
'/api/v1/work-activities/{workActivity_id}/teams':
put:
summary: 'Replace the team mappings for a work activity.'
operationId: replaceTheTeamMappingsForAWorkActivity
description: 'Requires `work.write` ability.'
parameters:
-
in: header
name: X-Tenant
description: ''
example: 'string required Tenant slug; required for tenant-scoped endpoints. Example: "acme"'
schema:
type: string
responses:
200:
description: ''
content:
application/json:
schema:
type: object
example:
data:
id: 5
teams:
-
id: 9
name: Payments
emphasis: primary
properties:
data:
type: object
properties:
id:
type: integer
example: 5
teams:
type: array
example:
-
id: 9
name: Payments
emphasis: primary
items:
type: object
properties:
id:
type: integer
example: 9
name:
type: string
example: Payments
emphasis:
type: string
example: primary
tags:
- 'Work Catalog'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
teams:
type: array
description: 'Full replacement set of mappings.'
example:
-
team_id: 9
emphasis: primary
items:
type: object
properties:
team_id:
type: integer
description: "Team identifier (must share the activity's scenario context)."
example: 9
emphasis:
type: string
description: 'One of: primary, secondary.'
example: primary
required:
- team_id
- emphasis
required:
- teams
parameters:
-
in: path
name: workActivity_id
description: 'The ID of the workActivity.'
example: 11
required: true
schema:
type: integer
-
in: path
name: workActivity
description: 'Work activity identifier.'
example: 5
required: true
schema:
type: integer