---
title: "Update project"
method: PATCH
path: "/projects/{project_id}"
tags: ["projects"]
---

# Update project

`PATCH /projects/{project_id}`

## Request

- Base URL: `https://api.cogram.com/v1`
- URL: `https://api.cogram.com/v1/projects/{project_id}`
- Auth: HTTP bearer

Update a project.

Updates the specified fields of the project. Only provided fields are updated.
Set is_active=false to archive the project.

Note: is_public bypasses the org allow_override lock — API keys are
admin-scoped credentials, so the key holder is trusted to set any value.

## Path parameters

- `project_id` string, required

## Request body

- ProjectUpdateV1: Update project request. All fields are optional - only provided fields will be updated.
  - `name` string, nullable: Unique within the org.
  - `description` string, nullable
  - `external_id` string, nullable: Your system's ID for this project
  - `client_name` string, nullable
  - `project_address` string, nullable
  - `is_active` boolean, nullable: Set to false to archive the project
  - `email_filing_enabled` boolean, nullable
  - `meeting_filing_enabled` boolean, nullable: Whether Cogram suggests this project for meetings and, where the organization allows it, files meetings into it. Only takes effect while the organization has meeting filing turned on. Filing a meeting here by hand works either way.
  - `is_public` boolean, nullable: If true, project appears in org project directory; non-members can request access

## Response `200`

Successful Response

- ProjectV1: Project response.
  - `id` string, required
  - `name` string, required
  - `description` string, nullable, required
  - `external_id` string, nullable, required: Your system's ID for this project.
  - `client_name` string, nullable, required
  - `project_address` string, nullable, required
  - `is_active` boolean, required: False once the project is archived.
  - `email_filing_enabled` boolean, required
  - `meeting_filing_enabled` boolean, required: Whether Cogram suggests this project for meetings and, where the organization allows it, files meetings into it. Only takes effect while the organization has meeting filing turned on. Filing a meeting here by hand works either way.
  - `is_public` boolean, required: If true, project appears in org project directory; non-members can request access.
  - `unanet_project_id` string, nullable, required: Unanet ERP A/E project id, for projects synced from Unanet; null for every other project. Stable across customer re-codes, so join on this rather than on external_id.
  - `unanet_lead_stage` string, nullable, required: Unanet lead/pursuit stage name (e.g. "06-Submitted Proposal"). Set means an open opportunity; null means a normal project.
  - `unanet_custom_fields` object, nullable, required: The project's Unanet user-defined fields, keyed by Unanet fieldName. Replaced in full on each sync, so a cleared field disappears.
  - `unanet_market_sectors` ProjectMarketSectorV1[], nullable, required: The project's Unanet market sectors and their percentage split, in Unanet's order. Null for projects that aren't synced from Unanet or have no sectors.
    - `name` string, required: Sector name as configured in Unanet, e.g. "Healthcare".
    - `pct` number, nullable: Percent of the project attributed to this sector.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, nullable, required: Tracks the project record only — not the emails, RFIs, meetings or other records filed under it. Null if never updated.
  - `related_counts` ProjectRelatedCountsV1: How many records of each type the project holds. Every field defaults to 0, so a project with nothing filed under it returns zeros rather than omitting keys. Counts cover the record types an all-time export of the same project ships, with one exception: soft-deleted meetings are excluded, because they are absent from every other read path. An export narrowed to a time range ships a subset of what is counted here. Cogram's seeded example records are counted; they are real rows in the project. Usable as a change signal: poll, compare against the previous values, and re-export the projects that moved. Three classes of change are invisible to it, because cardinality does not move — an in-place edit (a renamed document, a corrected email subject); a new revision of an existing drawing, or action items generated for an existing meeting, since only the top-level record is counted; and an add plus a delete inside the same polling window, which nets to zero.
    - `emails` integer
    - `documents` integer
    - `drawings` integer
    - `drawing_sets` integer
    - `submittals` integer
    - `rfis` integer
    - `meetings` integer
    - `reports` integer
    - `observations` integer
    - `transmittals` integer
  - `members` ProjectMemberSummaryV1[], nullable: Users holding a role on this project, ordered by email. Present only when the request asked for it with ?include=members; null otherwise, so existing callers pay nothing for it. An empty list means the project genuinely has no members — distinguishable from null, which means they were not requested. Group-granted access is not listed; only direct per-user roles are.
    - `user_id` string, uuid, required
    - `email` string, required
    - `role` 'MEMBER' | 'OWNER' | 'LEAD' | 'VIEWER', required: Per-project role: OWNER manages membership, LEAD manages the project but not membership, MEMBER read/write, VIEWER read-only.

## Other responses

- `401`: Unauthorized
- `404`: Not found
- `409`: Conflict
- `422`: Validation error
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/cogram/apis/cogram-api.md) · [All operations](https://skmtc.dev/cogram/apis/cogram-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cogram/apis/cogram-api/revisions/5a3c9c40fca5?raw)
