Projects API — User Service
API reference for Cosmos projects: listing and filtering, creation, summaries, members, bulk role changes, project roles, and enablements
Updated 2026-11-03
Verified 2026-11-03
Projects group users, roles, and enabled resources (agents, apps, knowledge bases, graphs, analyzers) inside an organization. For architecture and configuration, see User Service. Organization-level roles are covered in Organizations API.
Request Rules
- Every request needs
Authorization: Bearer YOUR_TOKENandX-Org-Id: YOUR_ORG_ID. The caller must be an active member of the organization. X-Project-Idis optional. When sent on a/{project_id}/...route it must equal the project in the path.- Service tokens must send exactly one subject header:
X-On-Behalf-Of-User-Id,X-Cosmos-Subject-User-Id, orX-Actor-User-Id. - An inactive project only accepts a lifecycle update (
PATCHwithis_active). Other writes return409withcode: "project_inactive".
Organizations no longer get an automatic "Default" project. Create projects explicitly.
Pagination
The project list and the member list use cursor pagination:
| Parameter | Description |
|---|---|
limit | Page size, 1–100 (default 25) |
cursor | Opaque value from the previous response's next or previous |
Responses use {"results": [...], "next": "...", "previous": "..."}. Cursors are signed, tied to the query that produced them, and expire after 24 hours. Enablement lists use page-number pagination instead (page, page_size; {count, next, previous, results}). See API Conventions.
Projects
List projects
GET /api/v1/projects/?purpose=manage&q=onboarding&is_active=true&limit=25
| Parameter | Description |
|---|---|
purpose | manage (default; projects the caller can administer) or select (active projects the caller can enter) |
q | Case-insensitive substring match on name (up to 255 characters) |
is_active | true or false |
limit, cursor | Cursor pagination |
{
"results": [
{
"id": "PROJECT_UUID",
"name": "Q3 Onboarding",
"description": "",
"is_active": true,
"external_ref": null,
"capabilities": ["..."],
"can_enter": true,
"created_at": "2026-10-01T09:00:00Z",
"created_by": "USER_UUID",
"updated_at": "2026-10-01T09:00:00Z",
"updated_by": "USER_UUID"
}
],
"next": "...",
"previous": null,
"can_create": true,
"organization": {"id": "YOUR_ORG_ID", "name": "Acme"}
}
Create a project
POST /api/v1/projects/
{"name": "Q3 Onboarding", "description": "Customer onboarding agents"}
Returns 201. The creator becomes the project's project_admin. A duplicate name returns 409 with {"code": "duplicate", ...}.
Get, update
GET /api/v1/projects/{project_id}/
PATCH /api/v1/projects/{project_id}/
PATCH accepts name, description, and is_active.
Summaries
Fetch counts for up to 100 projects in one call, for example to render a project table:
POST /api/v1/projects/summaries/
{"project_ids": ["PROJECT_UUID_1", "PROJECT_UUID_2"]}
{
"results": [
{
"project_id": "PROJECT_UUID_1",
"member_count": 12,
"role_count": 4,
"project_admin_count": 2,
"roles_in_use_count": 3,
"resource_counts": {"agents": 5, "apps": 2, "knowledge_bases": 3, "graphs": 1, "analyzers": 0, "total": 11}
}
],
"requested_count": 2,
"returned_count": 1
}
Projects the caller cannot read are left out, so returned_count can be lower than requested_count.
Members
List members
GET /api/v1/projects/{project_id}/members/?role_ids=ROLE_A,ROLE_B&q=jane&limit=50
Requires permission to manage project members. role_ids is a comma-separated list; a member matches if they hold any of the roles. q is a substring match on first name, last name, and email (up to 255 characters). Pages are keyed by user, so a member with several roles appears once:
{"user_id": "USER_UUID", "email": "jane@example.com", "display_name": "Jane Doe", "roles": ["..."]}
Add a member
POST /api/v1/projects/{project_id}/members/
{"user_id": "USER_UUID", "role_id": "ROLE_UUID"}
Bulk role changes
Set the desired direct roles for up to 100 users in one atomic request. Each user can have up to 25 role IDs, and a user can appear only once. An empty role_ids list removes all of the user's direct roles.
PUT /api/v1/projects/{project_id}/members/
{
"members": [
{"user_id": "USER_UUID_1", "role_ids": ["EDITOR_ROLE_UUID"]},
{"user_id": "USER_UUID_2", "role_ids": ["VIEWER_ROLE_UUID", "EDITOR_ROLE_UUID"]}
]
}
{
"results": [
{
"user_id": "USER_UUID_1",
"roles": ["..."],
"added_role_ids": ["EDITOR_ROLE_UUID"],
"removed_role_ids": ["VIEWER_ROLE_UUID"],
"unchanged_role_ids": []
}
],
"summary": {
"members_added": 1,
"members_removed": 0,
"members_updated": 1,
"unchanged": 0,
"role_assignments_added": 2,
"role_assignments_removed": 1
}
}
If any entry is invalid, nothing is changed.
Remove a role or member
DELETE /api/v1/projects/{project_id}/members/{user_id}/?role_id=ROLE_UUID
GET /api/v1/projects/{project_id}/available-users/ lists organization members who can be added.
Project Roles
GET /api/v1/projects/{project_id}/roles/?q=edit
POST /api/v1/projects/{project_id}/roles/
The list returns {"results": [...]} without pagination. Every project shares the default roles project_admin, editor, and viewer; projects can add custom roles:
{"code": "reviewer", "name": "Reviewer", "description": "Read and review", "permission_codes": ["..."]}
code must be lowercase letters, digits, and underscores, starting with a letter. permission_codes cannot be empty. PATCH /api/v1/projects/{project_id}/roles/{role_id}/ updates name, description, or permission_codes.
DELETE /api/v1/projects/{project_id}/roles/{role_id}/ removes a custom role. A role that is still assigned returns 409 with code: "role_in_use".
Enablements
Enablements control which organization resources a project can use.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/projects/{project_id}/enablements/ | All enablements for a project |
| GET | /api/v1/projects/{project_id}/enablements/{kind}/ | Enablements of one kind |
| GET | /api/v1/projects/enablements/?project_id= | Query enablements across projects |
Other Routes
These routes support the frontend and service-to-service authorization:
| Path | Purpose |
|---|---|
preferences/ | The caller's project preferences |
permissions/, permissions/mine/ | Project permission catalog; the caller's project permissions |
lookup/ (POST), by-ref/ | Resolve projects by ID or external reference |
activity-read-scope/, {project_id}/activity-access/ | Recent Activity visibility |
authorized-targets/, {project_id}/authorized-targets/ | Resources the caller can use |
{project_id}/groups/... | Project groups, their members, and their roles |
{project_id}/external-refs/... | External references |
{project_id}/entitlements/... | Entitlements |
{project_id}/access-matrix/, access-matrix/batch/ | Member-by-resource access matrix |
{project_id}/agent-access/... | Per-agent access |
{project_id}/access-check/, {project_id}/resource-batch/ | Authorization checks |
All paths are relative to /api/v1/projects/.