Documents

List a project's document metadata

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).

GET
/documents

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).

Authorization

x-api-key<token>

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

Query Parameters

limit?integer

Page size, 1–200. Defaults to 50.

cursor?string

Opaque cursor from a previous page's nextCursor. Omit for the first page.

projectId*string

The project whose documents to list.

kind?string

Narrow to one library.

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/documents?projectId=497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "data": [    {      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",      "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",      "title": "string",      "storagePath": "string",      "uploadedAt": "2019-08-24T14:15:22Z",      "uploadedByName": "string",      "audience": "all_crew",      "kind": "ohs"    }  ],  "nextCursor": "string"}
{  "error": {    "code": "unauthorized",    "message": "Missing or invalid API key."  }}
{  "error": {    "code": "validation",    "message": "One or more inputs are invalid.",    "fields": {      "fieldName": "A message explaining what's wrong with this field."    }  }}

Request a presigned diary-photo upload URL POST

**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.

Register an uploaded document POST

**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.