Skip to main content
POST
/
v1
/
api
/
documents
/
upload
Upload a document (multipart)
curl --request POST \
  --url https://api.hq.zone/v1/api/documents/upload \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: multipart/form-data' \
  --form file='@example-file' \
  --form 'caption=<string>' \
  --form 'category=<string>' \
  --form 'channel_id=<string>' \
  --form 'scope=<string>' \
  --form 'tags=<string>'
{
  "deduplicated": true,
  "document_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "download_url": "<string>",
  "sha256": "<string>",
  "size_bytes": 1,
  "enriched": true
}

Multipart file upload

Send the file as multipart/form-data (a real binary file part), not JSON. Use this variant for direct uploads from a browser file-picker or a form. The interactive playground’s file control posts the part for you; from code, build a multipart body.

Authorizations

Authorization
string
header
required

Personal Access Token. Send as Authorization: Bearer hq_pat_....

Body

multipart/form-data

Documentation shape for the POST /v1/api/documents/upload multipart form. The handler reads the parts directly; this only drives the spec.

file
file
required

The file bytes (a file part carrying filename + content-type).

caption
string | null
category
string | null
channel_id
string | null

Required iff scope=channel.

scope
string | null

private | channel | team. Defaults to private.

tags
string | null

Comma-separated tag list.

Response

Document saved

deduplicated
boolean
required

True iff this hashed identical to an existing document in this tenant - we still record the new metadata row but the Trove object is shared. The UI surfaces this as a "saved (dedup'd against existing copy)" hint.

document_id
string<uuid>
required
download_url
string
required
sha256
string
required
size_bytes
integer<int64>
required
Required range: x >= 0
enriched
boolean

True iff this was a same-owner/same-scope dedup AND the caller supplied new metadata (tags/caption/category) that we actually merged onto the existing row. Lets the UI say "already in your library - details updated" honestly vs a bare "already there".