Create and manage projects — the primary workspace unit that groups entities, files, tasks, and views within an organization. The organization is taken from the authenticated session; callers never pass `org_id`. Identifiers and timestamps are assigned by the platform.
GET /v1/projects
List projects
Returns the projects in the caller's organization that the caller can see, with offset pagination. Requires a valid session; the organization and RLS scope are derived from the access token.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
status | query | string | no | Filter by lifecycle status (e.g. `active`, `archived`). Omit for the default active set. |
limit | query | integer | no | Maximum number of projects to return (1–100, default 50). |
offset | query | integer | no | Number of projects to skip for pagination. |
Responses
| Status | Description |
200 | Paginated list of projects. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/projects
Create a project
Creates a new project in the caller's organization. The only required field is `name`. A URL-safe `slug` is generated from the name when omitted. The organization is taken from the session — `org_id` is never accepted in the body. Returns the full created record, including the platform-assigned `id`, `slug`, `is_active`, and timestamps.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | yes | Project name. |
slug | string | no | Optional canonical slug (lowercase alphanumeric with single internal hyphens, not UUID-shaped). Auto-generated from the name when omitted; reserved words are rejected. |
description | string | no | Optional project summary. |
settings | object | no | Optional bounded settings object. |
{
"name": "Q2 Client Onboarding"
}
Responses
| Status | Description |
201 | Project created. The full project record is returned under `data`. |
400 | `INVALID_JSON` (unparseable body), `VALIDATION_ERROR` (a field failed validation, including a non-canonical or reserved `slug` → message names `RESERVED_SLUG`/`INVALID_FORMAT`). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `PERMISSION_DENIED` (missing the `project.create` permission) or `PROJECT_LIMIT_REACHED` (the organization's plan project limit is reached). |
409 | `PROJECT_SLUG_EXISTS` — a project with that slug already exists in this organization and environment. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | Platform-assigned project identifier (UUIDv7). |
org_id | string<uuid> | Owning organization. |
name | string | Display name (1–255 chars). |
slug | string | URL-safe slug (unique per org+environment). Auto-generated from the name when not supplied. |
description | string | null | Optional summary (≤4096 chars). |
prefix | string | null | Optional short prefix used for human-friendly entity ids. |
visibility | string (enum) publicprivateinternal | Project visibility. |
category_id | string | null | Optional project category. |
owner_scope | string | Ownership scope (e.g. `organization`). |
is_active | boolean | False when archived or soft-deleted. |
created_by_user_id | string | null | User who created the project. |
created_at | string<date-time> | Creation timestamp (assigned by the platform). |
updated_at | string<date-time> | Last-update timestamp. |
settings | object | Project settings object. |
GET /v1/projects/{projectId}
Get a project
Returns a single project by id. A project the caller cannot see is reported as `404 NOT_FOUND` (indistinguishable from a missing one, per the anti-enumeration contract).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
Responses
| Status | Description |
200 | The project record. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | Platform-assigned project identifier (UUIDv7). |
org_id | string<uuid> | Owning organization. |
name | string | Display name (1–255 chars). |
slug | string | URL-safe slug (unique per org+environment). Auto-generated from the name when not supplied. |
description | string | null | Optional summary (≤4096 chars). |
prefix | string | null | Optional short prefix used for human-friendly entity ids. |
visibility | string (enum) publicprivateinternal | Project visibility. |
category_id | string | null | Optional project category. |
owner_scope | string | Ownership scope (e.g. `organization`). |
is_active | boolean | False when archived or soft-deleted. |
created_by_user_id | string | null | User who created the project. |
created_at | string<date-time> | Creation timestamp (assigned by the platform). |
updated_at | string<date-time> | Last-update timestamp. |
settings | object | Project settings object. |
PUT /v1/projects/{projectId}
Update a project
Updates a project's name, slug, description, visibility, archive state, or settings. At least one field must be provided. `description: null` clears the description; `is_active` toggles archive/active.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
name | string | no | New name. |
slug | string | no | New canonical slug. |
description | string | null | no | New description; null clears it. |
visibility | string (enum) publicprivateinternal | no | New visibility. |
is_active | boolean | no | Archive (false) / unarchive (true). |
settings | object | no | Replacement settings object. |
Responses
| Status | Description |
200 | The updated project record. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | `PROJECT_SLUG_EXISTS` — the requested slug is already taken in this organization. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | Platform-assigned project identifier (UUIDv7). |
org_id | string<uuid> | Owning organization. |
name | string | Display name (1–255 chars). |
slug | string | URL-safe slug (unique per org+environment). Auto-generated from the name when not supplied. |
description | string | null | Optional summary (≤4096 chars). |
prefix | string | null | Optional short prefix used for human-friendly entity ids. |
visibility | string (enum) publicprivateinternal | Project visibility. |
category_id | string | null | Optional project category. |
owner_scope | string | Ownership scope (e.g. `organization`). |
is_active | boolean | False when archived or soft-deleted. |
created_by_user_id | string | null | User who created the project. |
created_at | string<date-time> | Creation timestamp (assigned by the platform). |
updated_at | string<date-time> | Last-update timestamp. |
settings | object | Project settings object. |
DELETE /v1/projects/{projectId}
Delete (archive) a project
Soft-deletes a project by setting `is_active = false`. The underlying data is preserved for recovery and the audit trail; the project is hidden from listings.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
Responses
| Status | Description |
200 | The project was soft-deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
is_active | boolean (enum) false | |
GET /v1/projects/{projectId}/members
List project members
Returns the members of a project with offset pagination.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
limit | query | integer | no | Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100). |
offset | query | integer | no | Number of records to skip for offset pagination. |
Responses
| Status | Description |
200 | Paginated list of project members. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/projects/{projectId}/members
Add a project member
Adds a user to the project with a role. The acting user must have permission to manage project membership.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
user_id | string<uuid> | yes | User to add (UUIDv7). |
role | string | yes | Role to grant within the project. |
{
"user_id": "019b0000-0000-7000-8000-000000000000",
"role": "editor"
}
Responses
| Status | Description |
201 | The member was added. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
user_id | string<uuid> | Member user id. |
project_id | string<uuid> | Project id. |
role | string | Member's role within the project. |
display_name | string | null | Member display name. |
email | string | null | Member email. |
created_at | string<date-time> | When the membership was created. |
DELETE /v1/projects/{projectId}/members/{userId}
Remove a project member
Removes a user from the project. A non-existent or cross-tenant project is reported as `404 NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
userId | path | string<uuid> | yes | The user to remove (UUIDv7). |
Responses
| Status | Description |
200 | The member was removed. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PUT /v1/projects/{projectId}/settings
Upsert project settings
Replaces the project's settings JSON object. The body is a bounded JSON object validated for size and depth.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
projectId | path | string<uuid> | yes | Project identifier (UUIDv7). |
Request Body
Arbitrary bounded settings object (size/depth limited).
Responses
| Status | Description |
200 | The settings were saved. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |