Skip to content

API Reference

Departments

List departments and fetch a single department's snapshot, with live mode-aware cost rolled up from its teams.

Last updated


Two endpoints cover the department surface: a paginated list and a single-department lookup by UUID. A department's cost.current_run_rate_hourly, assigned_workloads, and assigned_pvs are the sum of its teams' values, counting distinct entities — a workload split across two teams in the same department counts as 1; a workload split across teams in different departments contributes to both. A team without a department is valid; it does not roll up to any department total. The run rate covers the last seven complete days (UTC), per hour. Both endpoints accept ?cost_mode= and compute the cost at the requested mode (see Cost Modes).

The list sorts by cost.current_run_rate_hourly descending. Pagination is cursor-based; see Pagination & Filtering.

List departments

GET /v1/departments

Required scope: departments:read

Department inventory across the tenant, sorted by hourly run-rate cost descending.

Query parameters

NameTypeDefaultAllowed valuesDescription
limitinteger1001..500Page size.
cursorstringOpaque pagination token from a previous response.
include_totalbooleanfalsetrue, falseInclude meta.pagination.total_count.
sortstringcostcost, idcost puts the highest run rate first. id gives an order that holds while you walk every page. See Sort policy.
cost_modestringfully_loadedfully_loaded, workload_onlyCost attribution mode. See Cost Modes.
originstring (csv)Common: k8s, kubeadaptRestrict by where the department was created. Not strictly validated — any string is accepted.

Example request

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/departments?cost_mode=fully_loaded&limit=20"

Example response

json
1{
2  "data": [
3    {
4      "id": "e1f2a3b4-c5d6-4e7f-a8b9-c0d1e2f3a4b5",
5      "kind": "Department",
6      "metadata": {
7        "name": "Engineering",
8        "description": "All engineering teams: platform, payments, data, growth.",
9        "origin": "kubeadapt",
10        "owner_email": "vp-engineering@acme.io",
11        "created_at": "2025-08-14T10:00:00Z",
12        "updated_at": "2026-05-04T16:20:00Z"
13      },
14      "teams": 14,
15      "assigned_workloads": 247,
16      "assigned_pvs": 38,
17      "cost": {
18        "current_run_rate_hourly": { "amount": "84.1200", "currency": "USD" },
19        "cost_mode": "fully_loaded"
20      }
21    },
22    {
23      "id": "5d6e7f8a-9b0c-4d1e-8f23-4a5b6c7d8e9f",
24      "kind": "Department",
25      "metadata": {
26        "name": "Data",
27        "description": "Analytics, ML, and the data warehouse.",
28        "origin": "kubeadapt",
29        "owner_email": "data-lead@acme.io",
30        "created_at": "2025-08-14T10:00:00Z",
31        "updated_at": "2026-04-30T12:11:00Z"
32      },
33      "teams": 4,
34      "assigned_workloads": 62,
35      "assigned_pvs": 8,
36      "cost": {
37        "current_run_rate_hourly": { "amount": "24.6800", "currency": "USD" },
38        "cost_mode": "fully_loaded"
39      }
40    }
41  ],
42  "meta": {
43    "request_id": "0196f1c2-cc42-7789-bd6f-70755411f8c4",
44    "applied_at": "2026-05-21T10:30:00Z",
45    "pagination": {
46      "has_more": false,
47      "limit": 20
48    },
49    "cost_mode": "fully_loaded"
50  }
51}

Example error response

json
1{
2  "data": null,
3  "meta": {
4    "request_id": "0196f1c2-e01a-7c59-8bb6-dcff4a8b2629",
5    "applied_at": "2026-05-21T10:30:05Z"
6  },
7  "error": {
8    "code": "DEPARTMENT_NOT_FOUND",
9    "message": "department not found"
10  }
11}

Common errors

HTTPerror.codeWhen
400BAD_REQUESTMalformed limit or cursor.
401UNAUTHORIZEDMissing or invalid Bearer token. See Authentication.
403FORBIDDENToken lacks departments:read. See Permission Scopes.
410CURSOR_EXPIREDCursor older than 24h or query parameters changed since issue.
422INVALID_COST_MODEcost_mode value not in fully_loaded, workload_only.
429RATE_LIMITEDPer-key quota exceeded. See Retry-After header. See Error Handling.

Get department by ID

GET /v1/departments/{dept_id}

Required scope: departments:read

Single department body. Same shape as the list elements.

Path parameters

NameTypeDescription
dept_idUUIDDepartment identifier returned by the list endpoint.

Query parameters

NameTypeDefaultAllowed valuesDescription
cost_modestringfully_loadedfully_loaded, workload_onlyCost attribution mode. See Cost Modes.

Example request

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/departments/e1f2a3b4-c5d6-4e7f-a8b9-c0d1e2f3a4b5?cost_mode=workload_only"

Example response

json
1{
2  "data": {
3    "id": "e1f2a3b4-c5d6-4e7f-a8b9-c0d1e2f3a4b5",
4    "kind": "Department",
5    "metadata": {
6      "name": "Engineering",
7      "description": "All engineering teams: platform, payments, data, growth.",
8      "origin": "kubeadapt",
9      "owner_email": "vp-engineering@acme.io",
10      "created_at": "2025-08-14T10:00:00Z",
11      "updated_at": "2026-05-04T16:20:00Z"
12    },
13    "teams": 14,
14    "assigned_workloads": 247,
15    "assigned_pvs": 38,
16    "cost": {
17      "current_run_rate_hourly": { "amount": "61.3500", "currency": "USD" },
18      "cost_mode": "workload_only"
19    }
20  },
21  "meta": {
22    "request_id": "0196f1c2-d7bf-7360-9437-f4e73c042b45",
23    "applied_at": "2026-05-21T10:30:00Z",
24    "cost_mode": "workload_only"
25  }
26}

Same department as the list example, fetched in workload_only mode. The amount (61.3500) is lower than the fully_loaded list figure (84.1200) because it leaves out the share of idle capacity and cluster overhead.

Common errors

HTTPerror.codeWhen
400BAD_REQUESTdept_id is not a valid UUID.
401UNAUTHORIZEDMissing or invalid Bearer token.
403FORBIDDENToken lacks departments:read.
404DEPARTMENT_NOT_FOUNDNo department with this ID exists in the tenant.
422INVALID_COST_MODEcost_mode value not in fully_loaded, workload_only.
429RATE_LIMITEDPer-key quota exceeded.

Field notes

  • teams is the count of teams whose metadata.department.id equals this department's id — not workloads, not assignments. Enumerate with GET /v1/teams?department_id=.
  • origin matches the Team semantics: kubeadapt for departments created in the UI, k8s for departments mirrored from a configured Kubernetes label key.
  • Department bodies have no last_seen_at. The field exists on Team to detect retired teams; departments do not go stale.
  • Deleting a department orphans its teams rather than deleting them. Orphaned teams have no metadata.department block; their cost stops rolling up.

Filtering patterns

plaintext
GET /v1/departments                                      # all, biggest first
GET /v1/departments?cost_mode=workload_only              # exclude overhead
GET /v1/departments/{dept_id}                            # one department and its teams
GET /v1/teams?department_id={dept_id}                    # child teams
GET /v1/departments?origin=k8s                           # mirrored from labels

See also

  • Teams: the layer below departments, including assignments.
  • Cost Modes. Fully Loaded vs Workload Only, with worked examples.
  • Cost Attribution: Overview: the model behind departments, teams, and assignments.
  • Teams and Departments: the data model and lifecycle, including what happens on delete.
  • Cost Explorer: aggregated cost queries grouped by namespace, workload, or any other dimension — pair with cost_mode for live mode-aware totals.