# FOREMAN API

- [Getting started](https://docs.foremanapp.com.au/docs): Connect to your FOREMAN tenant over HTTP or from an AI assistant.
- [Authentication](https://docs.foremanapp.com.au/docs/authentication): Get your tenant API key from Settings and send it with every request.
- [Connect an AI assistant (MCP)](https://docs.foremanapp.com.au/docs/connect-ai-assistant): Connect FOREMAN to Claude or ChatGPT the simple point-and-click way, or wire it into a coding tool with the developer setup.

- **API reference**
- Billing
  - [Create an upgrade Checkout session](https://docs.foremanapp.com.au/docs/billing/createUpgradeCheckout): Returns a freshly-created Stripe Checkout URL to upgrade the tenant off
the Free plan (e.g. before adding a second project). The human pays in
their own browser; the webhook upgrades the tenant. Admin-equivalent.
- Diagnostics
  - [Resolve the authenticated tenant](https://docs.foremanapp.com.au/docs/diagnostics/whoami): Echoes the tenant and role the presented API key resolves to. Useful as
an "is my key valid?" check. Returns `401` if the key is missing/invalid.
- Diary entries
  - [Create a diary entry](https://docs.foremanapp.com.au/docs/diary-entries/createDiaryEntry): Logs a daily site-diary entry on behalf of a crew member. The key acts as
a tenant Admin, so the body names the crew member (`userId`) the entry is
for; the entry is attributed to them and they must be an active tenant
member assigned to the project. `entryDate` may not be in the future, and
`hours` are 0–14 in 0.25h steps. To attach photos, first upload each via
`POST /projects/{id}/diary-photos/upload-url` and pass the returned
`storagePath`(s) in `photoPaths`. Editing/deleting entries stays in the app.
  - [List diary entries](https://docs.foremanapp.com.au/docs/diary-entries/listDiaryEntries): Lists the tenant's diary entries, most-recent-first, paginated. Filters
map onto the domain browse: `project` and `user` are repeatable.
  - [Request a presigned diary-photo upload URL](https://docs.foremanapp.com.au/docs/diary-entries/requestDiaryPhotoUploadUrl): **Step 1 of the presigned diary-photo upload** — the image-only sibling
of the document upload. Validates the declared image (JPG/PNG only — no
PDF) and returns a short-lived, single-use **signed PUT URL**
(`uploadUrl`) plus the computed `storagePath`.

**The image bytes never travel through this API call.** After this
returns, the caller PUTs the raw image bytes directly to `uploadUrl` (a
plain HTTP `PUT` with the file as the request body and the matching
`Content-Type`) — out of band — then passes the returned `storagePath` in
the `photoPaths` array of `POST /diary-entries`. **There is no register
step**: creating the diary entry writes the `diary_photo` row(s) (ADR
0001 §5).

Any crew member assigned to the project may log diary photos (not
manager-only); an Admin/API key is implicitly on every project. Blocked
on read-only/archived projects.
- Documents
  - [List a project's document metadata](https://docs.foremanapp.com.au/docs/documents/listDocuments): Lists document **metadata** (never the binary) for one project,
paginated. `project` is required; `kind` narrows to one library, omitted
returns both (OHS first, then Project Information).
  - [Register an uploaded document](https://docs.foremanapp.com.au/docs/documents/registerDocument): **Step 2 of the two-step presigned document upload.** Call this *after*
you have PUT the file bytes to the `uploadUrl` from
`POST /projects/{id}/documents/upload-url`. Pass the `uploadRef` from
step 1 (or the `storagePath` + `kind`) plus the `title` (and `audience`
for `kind: info`).

Verifies the object actually landed in storage (and re-checks its real
size/type against the ≤25 MB, PDF/JPG/PNG cap), then creates the document
record. The new document then appears in `GET /documents?projectId={id}`.
Reading document metadata stays on the read-only `/documents` collection;
this project-scoped route is the upload (write) side. Admin or the
project's Site Manager; blocked on read-only/archived projects.
  - [Get a signed download URL for a document](https://docs.foremanapp.com.au/docs/documents/requestDocumentDownload): Returns a short-lived **signed download URL** for the document plus its
metadata — the read counterpart of the presigned upload
(`/projects/{id}/documents/upload-url`). The file bytes are fetched out of
band by GETting `downloadUrl`; they never transit this JSON response. The
Project-Information audience rule is enforced: a document the caller may
not see returns `404` (indistinguishable from a missing one). `?kind`
optionally asserts the library (`ohs`/`info`); a mismatch is `404`.
  - [Request a presigned document upload URL](https://docs.foremanapp.com.au/docs/documents/requestDocumentUploadUrl): **Step 1 of the two-step presigned document upload.** Validates the
declared file (PDF/JPG/PNG, ≤25 MB intent) and returns a short-lived,
single-use **signed PUT URL** (`uploadUrl`), the computed `storagePath`,
and an opaque `uploadRef`.

**The binary bytes never travel through this API call.** After this
returns, the caller PUTs the raw file bytes directly to `uploadUrl` (a
plain HTTP `PUT` with the file as the request body and the matching
`Content-Type`) — out of band — then calls
`POST /projects/{id}/documents` with the `uploadRef` to register the
document (step 2). This is how binary upload is supported via the API/MCP
without bytes passing through the JSON request (ADR 0001 §5).

Admin or the project's Site Manager; blocked on read-only/archived
projects. `audience` applies to Project Information (`kind: info`) only.
- Form submissions
  - [Get a form submission](https://docs.foremanapp.com.au/docs/form-submissions/getFormSubmission): Reads one submission with its frozen template snapshot and answers.
  - [List form submissions](https://docs.foremanapp.com.au/docs/form-submissions/listFormSubmissions): Lists submissions, most-recent-first, paginated, with filters.
- Form templates
  - [Create a form template](https://docs.foremanapp.com.au/docs/form-templates/createFormTemplate): Creates a template from a name and its ordered list of blocks. Building
templates via the API/MCP is the expected primary path.
  - [Delete a form template](https://docs.foremanapp.com.au/docs/form-templates/deleteFormTemplate): Hard-deletes the template — allowed only when it has zero submissions.
With submissions present the API returns `409`; archive it instead so
audit records are never orphaned.
  - [Get a form template](https://docs.foremanapp.com.au/docs/form-templates/getFormTemplate): Fetch a single form template, including its field definitions.
  - [List form templates](https://docs.foremanapp.com.au/docs/form-templates/listFormTemplates): Lists the tenant's templates, paginated, optionally by status.
  - [Update or archive/unarchive a form template](https://docs.foremanapp.com.au/docs/form-templates/updateFormTemplate): Edits name, project-required, the `fillableBy` audience, and/or blocks,
and/or flips status (`{ "status": "archived" }` / `{ "status": "active" }`).
Field edits apply first, then the status change.
- Induction registrations
  - [Get a project's induction content](https://docs.foremanapp.com.au/docs/induction-registrations/getInduction): Reads the project's site-induction body (markdown) and the
acknowledgement wording visitors sign against. Visitor submission stays
app-only.
  - [Get one register record](https://docs.foremanapp.com.au/docs/induction-registrations/getInductionRegistration): Reads one register record in full — every captured field, the signed
acknowledgement snapshot, and a short-lived signed URL for the signature
image. Scoped to its project, so `project` is required.
  - [List a project's induction register](https://docs.foremanapp.com.au/docs/induction-registrations/listInductionRegistrations): Lists one project's induction register, most-recent-first, paginated.
The register is per-project, so `project` is required.
  - [Edit a project's induction content](https://docs.foremanapp.com.au/docs/induction-registrations/updateInduction): Updates the induction body (markdown) and/or the acknowledgement (intro +
numbered points). Edits apply to future visitors only — past registrations
keep their snapshot. Admin or the project's Site Manager.
- Projects
  - [Assign a crew member to a project](https://docs.foremanapp.com.au/docs/projects/assignCrew): Adds a Site Crew member to the project's roster (Admin or the project's
Site Manager). Idempotent — re-adding is a no-op. Admins are on every
project already and can't be rostered.
  - [Create a project](https://docs.foremanapp.com.au/docs/projects/createProject): Create a new job site. On the Free plan, exceeding the project cap returns `403` (`project_cap`) with an upgrade Checkout link.
  - [Archive a project](https://docs.foremanapp.com.au/docs/projects/deleteProject): Archives the project. Projects have no hard delete in v1 — archiving is
the delete semantics and preserves roster and audit data.
  - [Get a project](https://docs.foremanapp.com.au/docs/projects/getProject): Reads one project with its team roster and assignable members.
  - [List projects](https://docs.foremanapp.com.au/docs/projects/listProjects): Lists the tenant's active projects, paginated.
  - [Set or clear a project's Site Manager](https://docs.foremanapp.com.au/docs/projects/setSiteManager): Sets or clears the per-project Site Manager flag for an assigned crew
member (Admin or the project's existing Site Manager). The user must
already be on the roster.
  - [Remove a crew member from a project](https://docs.foremanapp.com.au/docs/projects/unassignCrew): 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.
  - [Update or archive/unarchive a project](https://docs.foremanapp.com.au/docs/projects/updateProject): 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.
- Signup
  - [Sign up an agent-driven tenant](https://docs.foremanapp.com.au/docs/signup/signUp): **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).
- Tasks
  - [Create a task](https://docs.foremanapp.com.au/docs/tasks/createTask): Create an operational to-do on a project, optionally assigned to a crew member.
  - [Delete a task](https://docs.foremanapp.com.au/docs/tasks/deleteTask): Hard-deletes the task (tasks are operational, not audit-bearing).
  - [Get a task](https://docs.foremanapp.com.au/docs/tasks/getTask): Fetch a single task by id.
  - [List tasks](https://docs.foremanapp.com.au/docs/tasks/listTasks): Lists the tenant's tasks, paginated, with optional filters.
  - [Update, reassign, or mark a task done](https://docs.foremanapp.com.au/docs/tasks/updateTask): Edits a task and/or ticks it. A `done` boolean marks the task done/undone;
`title`, `detail`, `projectId`, and `assigneeId` edit the task (reassign is
just an `assigneeId` change). Field edits apply first, then the done flip,
so one call can reassign and mark done together.
- Users
  - [Create a user](https://docs.foremanapp.com.au/docs/users/createUser): Creates a tenant user (Admin or Site Crew) with an initial password and at
least one project assignment, and returns the created user plus the
credentials to share with them (there is no credentials email in v1). The
email must be unique among active users in the tenant.
  - [Get a user](https://docs.foremanapp.com.au/docs/users/getUser): Reads one user with their project roster.
  - [List users](https://docs.foremanapp.com.au/docs/users/listUsers): Lists every user in the tenant (including revoked), paginated.
  - [Reinstate a revoked user](https://docs.foremanapp.com.au/docs/users/reinstateUser): Restores a revoked user's login (existing password) and their preserved
project assignments. Blocked with `409` if their email is now used by
another active user.
  - [Reset a user's password](https://docs.foremanapp.com.au/docs/users/resetUserPassword): Sets a new password for the user (≥4 chars), signing them out of every
device. Returns the credentials to share (no email in v1).
  - [Revoke a user's access](https://docs.foremanapp.com.au/docs/users/revokeUser): Revokes the user — blocks login, kills active sessions, and hides them
from pickers. The row is kept (reinstate restores it). Revoking yourself
is forbidden.
  - [Update a user](https://docs.foremanapp.com.au/docs/users/updateUser): Edits a user's `name` and/or account `role` (Site Crew ⇄ Admin) and
returns the updated user. The key is tenant-Admin-equivalent: it can't
change its own acting admin's role, nor demote the **last** admin (either
is `403`). Email and password are not editable here — use
`POST /users/{id}/reset-password` for the password. Provide at least one
of `name`/`role` (an empty body is `422`).

## Full text & contract

- Full docs as one file: https://docs.foremanapp.com.au/llms-full.txt
- Machine-readable API contract (OpenAPI): the API reference under https://docs.foremanapp.com.au/docs
  is generated from a single OpenAPI document.
