Delete is not available via the API
Deleting a diary entry stays in the app (Admin only, on the entry's detail page); this verb is answered with a `405` pointing there.
Deleting a diary entry stays in the app (Admin only, on the entry's
detail page); this verb is answered with a 405 pointing there.
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
Response Body
application/json
curl -X DELETE "https://example.com/diary-entries"{ "error": { "code": "method_not_allowed", "message": "This resource is read-only via the API. Edit it in the FOREMAN app." }}Create a diary entry POST
Logs a daily site-diary entry. The key acts as a tenant Admin: with `userId` the entry is logged FOR that crew member (issue 6) — they must be an active tenant member assigned to the project, the entry's origin is `logged_for`, `createdBy` names the acting admin, and every surface shows "Logged by [admin] for [crew member]"; without it the key logs its own owner's day (origin `manual`). `entryDate` may not be in the future, and hours ENTERED BY HAND move in 15-minute steps with a 12-hour maximum (ADR 0012, amended): pass `durationMinutes` as a multiple of 15 (0–720, e.g. `465` = 7h 45m), or the legacy `hours` (0–12, rounded to the nearest minute). A value that is not a multiple of 15 is refused the way one over 720 is; entries created by a check-out can hold any whole minute (e.g. 518 = 8h 38m), but those hours are derived and never entered here. 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 (the edit verbs `405`, pointing there — "Edit it in the FOREMAN app."; creating is a real API call, so the message does not say "create"). While the subject is checked in, logging by hand would double-count the shift its check-out is about to write, so the create `409`s with "Check out first to log this shift." (brief B2 — one rule across the web form, this REST route and MCP `create_diary_entry`).
List diary entries GET
Lists diary entries, most-recent-first, paginated. Filters map onto the domain browse: `projectId` and `userId` are repeatable. An API key is **Admin-equivalent and tenant-wide**, so this returns every entry in the tenant. The narrower per-role visibility introduced by SUP-449 — a Site Manager sees their sites plus their own, Site Crew only their own — applies to signed-in users of the web app; there is no crew-scoped API credential. **This read closes expired shifts before it answers** (ADR 0012, amended): open shifts past 12 hours inside the read's scope are auto-closed first, so the list can contain entries created by this very call — `origin` `auto_closed`, `createdBy` null, `durationMinutes`/`hours` **null** (hours *missing*, never 0, zero in totals), `closedAutomaticallyReason` `12h`. An hourly database job runs the same sweep whether or not anyone reads, so the entries exist before they are asked for. Writes never sweep.