Skip to main content

10. Documents

Upload a file, optionally naming a workflow to start on it:

curl -H "Authorization: Bearer $CLERK" \
-F file=@invoice.txt -F workflow=invoice_v1 \
http://localhost:8080/api/documents
{"document_id":"a4dd9e3f-92aa-4321-b4f9-e558a234c8b4","duplicate":false,"thread_id":"01a1c5a2-9931-73f8-8aeb-d25495c5ce97"}
  • The file is stored once per tenant and content: uploading the same bytes again returns the same document_id with "duplicate": true.
  • A background job (the ingest queue) parses the document, stores the markdown, splits it into chunks of about 1,500 characters, embeds them with every embedding model in models.yaml, and stores the vectors in embeddings (pgvector). The vector match strategy uses them.
  • If workflow was given, the job starts that workflow on the document and drives it in the background (the workflows queue) until it pauses.

Follow a run started this way:

curl -H "Authorization: Bearer $CLERK" http://localhost:8080/api/runs/$THREAD
{
"current_task": "approval",
"interrupt": {
"id": "01a1c5a2-9931-73f8-8aeb-d25495c5ce97:approval",
"request": { "expires_in_hours": 72, "forced": false, "four_eyes": true,
"node": "approval", "reason": "confirmation", "roles": ["approver"] }
},
"state": { "awaiting_approval": true, "invoice": {…}, "match": {…}, "validation_issues": [] },
"status": "awaiting_approval",
"thread_id": "01a1c5a2-9931-73f8-8aeb-d25495c5ce97",
"workflow": "invoice_v1"
}