Sign in

Projects API — User Service

API reference for Cosmos projects: listing and filtering, creation, summaries, members, bulk role changes, project roles, and enablements

user
apiuserprojectsmembersrolesrbacpagination

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_TOKEN and X-Org-Id: YOUR_ORG_ID. The caller must be an active member of the organization.
  • X-Project-Id is 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, or X-Actor-User-Id.
  • An inactive project only accepts a lifecycle update (PATCH with is_active). Other writes return 409 with code: "project_inactive".

Organizations no longer get an automatic "Default" project. Create projects explicitly.

Pagination

The project list and the member list use cursor pagination:

ParameterDescription
limitPage size, 1–100 (default 25)
cursorOpaque 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
ParameterDescription
purposemanage (default; projects the caller can administer) or select (active projects the caller can enter)
qCase-insensitive substring match on name (up to 255 characters)
is_activetrue or false
limit, cursorCursor pagination
json
{
  "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/
json
{"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/
json
{"project_ids": ["PROJECT_UUID_1", "PROJECT_UUID_2"]}
json
{
  "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:

json
{"user_id": "USER_UUID", "email": "jane@example.com", "display_name": "Jane Doe", "roles": ["..."]}

Add a member

POST /api/v1/projects/{project_id}/members/
json
{"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/
json
{
  "members": [
    {"user_id": "USER_UUID_1", "role_ids": ["EDITOR_ROLE_UUID"]},
    {"user_id": "USER_UUID_2", "role_ids": ["VIEWER_ROLE_UUID", "EDITOR_ROLE_UUID"]}
  ]
}
json
{
  "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:

json
{"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.

MethodPathPurpose
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:

PathPurpose
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/.