Documents API
| Route | Method | Purpose |
|---|---|---|
/api/doc | GET | Signed document URL |
/api/doc-upload-session | POST | Allocate a document row and signed upload token |
/api/ingest-doc | POST | Enqueue extraction/embedding for an uploaded document |
/api/document-inventory | GET | Admin/lead inventory of indexed documents |
Upload flow
POST /api/doc-upload-sessionallocates thedocumentscatalog row and a signed upload token — the browser uploads directly to storage using that token, not through this API.show_on_portal(defaulttrue) records the intent only (metadata.show_on_portal);falsecreates the row withinternal_only = true. Acontracts_sowfile stays restricted and never records the intent (20 Oct 2026).POST /api/ingest-doc { document_id }then enqueues indexing. Before it does, a staff upload (source_system: "upload") with that intent, not restricted, not Internal and notcontracts_sowgetsreleased_to_client,portal_visible, andrelease_status: "released", but only once the stored object is confirmed in Storage. An upload that never finishes stays off the portal; a retry or later reindex never re-releases or overrides a release decision.
{ "document_id": "document-uuid" }
This route is intentionally durable-only: extraction, embedding, and atomic publication all
run in Trigger.dev (sable.document.backfill-index-batch), not inline in the request handler —
the request only validates access and enqueues the work. Rate-limited via
SABLE_INGEST_RATE_LIMIT (default 12/min).
GET /api/doc
Returns a signed URL for one document. Enforced by the same access rules across every document surface:
- A valid Supabase session is required.
- Restricted documents (contracts, SOWs) require admin/lead.
- Non-leads must be a member of the document's project.
GET /api/document-inventory
Admin/lead only. Every indexed document plus contract/SOW extraction health flags —
buildDocumentInventory (in _deliverable_authoring.js) is shared with the deliverable-drafting
pipeline's evidence-collection step, so this inventory and what a deliverable draft can actually
cite are always the same list.
Where the code lives
web/api/doc.js,doc-upload-session.js,ingest-doc.js,document-inventory.jsweb/api/_doc_upload.js,_document_ingest.js,_ingestion_pipeline.js,_deliverable_authoring.jstrigger/documents.tsdocs-site/docs/reference/search-indexing.md— the retrieval side of this pipeline