projects

PUT /projects/{project_id}

Request

  • Base URL
    https://api.focusbear.io (the document declares no server; this is the origin it was published from)
  • Auth
    HTTP bearer

Path parameters

project_idstring uuid required

Request body

namestring

Omit to keep the name. Not @IsOptional(): that would also skip validation for null, which then reached the duplicate-name check as a non-string (a 500) — and "" would blank the name.

descriptionstring
due_datestring
importancenumber
outcomenumber nullable

Outcome significance, 1..10. Omit to preserve the rating; null clears it.

status'active' | 'completed' | 'archived'
iconstring nullable

The project's emoji, e.g. "🎯" — the literal character, which is what the icon generator itself stores. Either "" or null clears it back to the automatic icon; both are accepted so a client whose model is a nullable string (e.g. a Swift String?) needs no special case.

Declared here deliberately: the global pipe runs with whitelist: true, so before this existed an icon-only PUT arrived as an empty patch and TypeORM threw on the empty SET (a 500, not a validation error) — report 2026-09-14_20-07-42.

metadataobject nullable

Open per-project bag; metadata.tags is the reserved, validated, queryable key.

Stored unencrypted so the server can index and filter it — do not put anything sensitive here. Capped at 8KB serialized.

Shallow-merged over the stored bag one level deep (in SQL, so concurrent writes cannot clobber each other), so a client that only knows about tags cannot wipe a key another client added. Set a key to null to delete it, or send metadata: null to clear the bag entirely.

The cost of merge semantics: there is no single-request way to replace the whole bag — that is metadata: null followed by a second write.

MUST stay declared here: the global pipe runs whitelist: true, so an undeclared field is stripped before the service sees it, leaving an empty SET and a bare 500 (UpdateValuesMissingError) — how the project icon save broke (#2404).

Response

idstring required

For native projects: the project UUID. For synced (ClickUp) projects: the focus_mode_tags.id when a tag exists, otherwise the synced_projects.id. Use synced_project_id to reliably identify the synced project record regardless of tag presence.

Not normalized to synced_project_id as mobile/web clients use this id for GET /projects/:id lookups and routing. A swap to synced_project_id requires a coordinated client release.

namestring required
descriptionstring
owner_idstring required
custom_statusesobject[] required
iconstring nullable

One emoji character, or null when the project has no icon yet — which is what a clear returns, and what a project awaiting generation carries. This is the schema clients decode, so the nullability belongs here rather than only in the tests that assert it.

task_countnumber
uncompleted_task_countnumber
synced_project_idstring
synced_platformstring nullable

Stored integration platform for synced projects; null when the legacy source is unknown. Read only.

due_datestring nullable
importancenumber
outcomenumber nullable required

Outcome significance on the 1..10 wire scale; null for unrated or synced projects.

status'active' | 'completed' | 'archived' required

Lifecycle state: active (default), completed, or archived.

metadataobject nullable

Open per-project bag; metadata.tags holds the project's tags, lower-cased. Null when unset, and always null for synced projects, which have no row in projects to carry it.

created_atstring required
updated_atstring required

Changes

No recorded changes to this operation across all 1 revision of this API.