# Projects API

The Projects API manages organization projects through a stable external model. It does not expose Firestore paths, internal screen payloads, access materialization fields, or implementation metadata.

## Roles

| Operation | Member | Manager | Finance | HR |
|---|---:|---:|---:|---:|
| List and read projects | Yes | Yes | Financial fields only where permitted | Staffing fields only where permitted |
| Create or update projects | No | Yes | No | No |
| Archive or restore projects | No | Yes | No | No |

Organization-wide-by-Role access means a permitted client may see all active projects allowed by its fields and Role, without project membership.

## Project object

```json
{
  "object": "project",
  "id": "prj_01J8Q8QFXT2Y3QAD6M0MPB75GC",
  "code": "ACME-001",
  "name": "Acme implementation",
  "description": "Implement and launch Acme's operating workspace.",
  "status": "active",
  "start_date": "2026-08-01",
  "end_date": "2026-11-30",
  "customer_id": "com_01J8Q8VSMHH33D1FAMJNGHQCCM",
  "manager_member_id": "alice@example.com",
  "currency": "USD",
  "custom_fields": {},
  "created_at": "2026-07-20T12:00:00Z",
  "updated_at": "2026-08-22T09:45:00Z"
}
```

Organization-defined fields appear inside `custom_fields` and are described by the [Custom Fields API](custom-fields.html).

## List projects

`GET /v1/projects`

Operation ID: `listProjects`

Filters: `status`, `customer_id`, `manager_member_id`, `start_date_gte`, `end_date_lte`, `search`, `sort`, `order`, `limit`, and `after`.

Archived projects are excluded unless `status=archived` is requested.

## Create a project

`POST /v1/projects`

Operation ID: `createProject`

Required Role: Manager. Required header: `Idempotency-Key`.

```json
{
  "code": "ACME-001",
  "name": "Acme implementation",
  "description": "Implement and launch Acme's operating workspace.",
  "start_date": "2026-08-01",
  "end_date": "2026-11-30",
  "manager_member_id": "alice@example.com",
  "customer_id": "com_01J8Q8VSMHH33D1FAMJNGHQCCM",
  "custom_fields": {}
}
```

The server assigns `id`, audit fields, access materialization, and initial status. References must belong to the same organization and must not be deleted.

## Get a project

`GET /v1/projects/{project_id}`

Operation ID: `getProject`

Returns `ETag` for concurrency control.

## Update a project

`PATCH /v1/projects/{project_id}`

Operation ID: `updateProject`

Required Role: Manager. Use `If-Match` with the current ETag.

Immutable fields such as `id`, organization, creation audit fields, and internal access data are ignored only where explicitly documented; otherwise they produce `IMMUTABLE_FIELD`.

## Archive a project

`POST /v1/projects/{project_id}/archive`

Operation ID: `archiveProject`

Required Role: Manager. Required header: `Idempotency-Key`.

Archiving is the v1 deletion model. It preserves audit history and dependent records. Eos returns `409` when an active workflow prevents archival.

## Restore a project

`POST /v1/projects/{project_id}/restore`

Operation ID: `restoreProject`

Required Role: Manager. Restores an archived project when its dependencies remain valid.

## Common errors

`PROJECT_CODE_CONFLICT`, `PROJECT_NOT_FOUND`, `INVALID_MANAGER`, `INVALID_CUSTOM_FIELD`, `STALE_RESOURCE`, and `PROJECT_ARCHIVE_BLOCKED`.

Next: [Tasks API](tasks.html).
