Upload a draft

Upload the draft to review as a file, so the review runs against the exact bytes you hold and the returned hash proves it.

Last updated 12 September 2026

Upload a draft

POST https://api.quorumtech.ch/attest/v1/drafts

Upload a draft to review.

Uploads the draft as a file, which is preferred over sending its text: the review then runs against the exact bytes you hold, and the returned fileHash proves it. Reference the returned id from POST /attest/v1/attest/draft. Capped at 2 MB and 500,000 characters of text.

Upload the finished draft as a file and reference the returned id from the review call. Passing the draft as text instead means the calling program, often a model, retypes its own work into a request, and a generation step can drift: a figure lands a digit out, a hedge disappears, and the review then runs against text nobody will read.

fileHash is the SHA-256 of the bytes as uploaded. Recompute it against the file still on your disk to prove which copy the verdicts describe:

shasum -a 256 briefing.md

Plain text, Markdown, PDF, Word and PowerPoint are accepted, up to 2 MB and 500,000 characters of text. There is deliberately no listing of drafts: a draft is the thing you have not published yet, so keep the id from the upload response. Drafts are held in memory only, expire after six hours, and can be deleted once the review is collected.

Request

A multipart/form-data body with these parts:

| Part | Type | Required | Description | | --- | --- | --- | --- | | file | a file | yes | The draft, as plain text, Markdown, PDF, Word or PowerPoint. |

Example request

curl -X POST "https://api.quorumtech.ch/attest/v1/drafts" \
  -H "Authorization: Bearer $QUORUM_API_KEY" \
  -F "file=@briefing.md"

Responses

201

The draft is held and ready to review.

| Field | Type | Description | | --- | --- | --- | | id | string | The draft id to review by. inline when the text came in the request. | | filename | string | May be null. | | fileHash | string | SHA-256 of the draft as uploaded, or of the text as sent. | | chars | integer | | | createdAt | string (date-time) | | | source | upload or inline | |

Errors

The body is { "error": { "code", "message" } }; the full catalogue with what to do about each code is on the Errors page.

| Status | Codes | When | | --- | --- | --- | | 400 | invalid_upload, invalid_request | The multipart body is malformed or uses an unexpected field (invalid_upload), or no file part was sent at all (invalid_request). On a draft upload, a file that could not be read is also invalid_upload. | | 401 | | The key is missing, not recognised, or revoked. | | 402 | payment_required, credits_exhausted, remaining, needed | The workspace has no active API subscription (payment_required), or is prepaid and has no credits left for this request (credits_exhausted, with remaining and needed). Manage billing and add credits at https://developer.quorumtech.ch/billing. | | 403 | | The key is not scoped to Attest. | | 413 | file_too_large, draft_too_large | The file is larger than 2 MB (file_too_large), or its text is longer than 500,000 characters (draft_too_large). | | 429 | rate_limited, claims_rate_limited, claim_budget_exhausted, monthly_cap_reached, cap | Over the key's requests-per-minute limit (rate_limited), its claims-per-minute ceiling (claims_rate_limited), its claims-per-day budget (claim_budget_exhausted), or, for a postpaid workspace, its monthly credit cap (monthly_cap_reached, with cap and resetsAt). Retry-After says when to try again; the daily budget resets at midnight UTC and the cap on the first of the month. |

Cost

Free. Uploading a draft costs no credits; the review is charged when it runs.

Still need help?

Ask Quincy in the chat bubble below, or write to support@quorumtech.ch and we will help you directly.