Update or archive/unarchive a project
Edits project detail fields and/or flips status. A body `{ "status": "archived" }` archives the project (the v1 delete semantics), `{ "status": "active" }` unarchives it. Detail fields and a status change may be sent in one call — the detail edit applies first. Archiving **checks the site's crew out** (ADR 0012, amended): shifts already past 12 hours close as `closedAutomaticallyReason` `12h` with **no hours**; every shift still open at that instant closes at the archive moment with **real** hours (always under 12). Both write `auto_closed` diary entries, and an archive whose close fails returns `422` — archive again to finish the job.
Edits project detail fields and/or flips status. A body
{ "status": "archived" } archives the project (the v1 delete semantics),
{ "status": "active" } unarchives it. Detail fields and a status change
may be sent in one call — the detail edit applies first.
Archiving checks the site's crew out (ADR 0012, amended): shifts already
past 12 hours close as closedAutomaticallyReason 12h with no hours;
every shift still open at that instant closes at the archive moment with
real hours (always under 12). Both write auto_closed diary entries, and
an archive whose close fails returns 422 — archive again to finish the job.
The per-tenant API key, copied from Settings → API & integrations.
Sent as the x-api-key request header. The key is tenant-scoped and acts
with Admin-equivalent, tenant-wide access.
In: header
Path Parameters
Resource id.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
All fields optional. status archives/unarchives the project; the other
fields edit its details. Both may be sent together.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X PATCH "https://example.com/projects/497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "name": "string", "address": "string", "latitude": 0, "longitude": 0, "timezone": "string", "standardHours": "string", "ownerContact": "string", "gateCodes": "string", "description": "string", "status": "active", "inductionToken": "string", "inductionUrl": "http://example.com", "createdAt": "2019-08-24T14:15:22Z"}{ "error": { "code": "unauthorized", "message": "Missing or invalid API key." }}{ "error": { "code": "read_only", "message": "Your subscription is inactive. This action is read-only." }}{ "error": { "code": "not_found", "message": "Not found." }}{ "error": { "code": "validation", "message": "One or more inputs are invalid.", "fields": { "fieldName": "A message explaining what's wrong with this field." } }}Remove a crew member from a project DELETE
Removes a Site Crew member from the roster (also clears their Site Manager flag for the project). Removing someone not on the roster is a no-op.
Sign up an agent-driven tenant POST
**Unauthenticated.** Creates a new **active** Free tenant and an active Admin and returns the tenant **API key immediately** (deferred verification) — the agent can start using FOREMAN right away, without waiting for the human to click an email. A "set your password / confirm your email" link is emailed to the human so they can later log into the browser dashboard, but it gates nothing programmatic. **Rate-limited per client IP** (the only unauthenticated write surface) — over the cap returns `429`. A duplicate email returns the same generic message with no key (so the surface can't probe for registered accounts).