Batches and drafts

Upload documents once as a batch, upload a draft, and let Attest find and check every claim in it, with the hashes that prove which bytes were reviewed.

Last updated 12 September 2026

Batches and drafts

Checking one claim against inline evidence is the simplest call. Reviewing a whole document against a pack of sources is the common job, and it takes three calls.

The flow

  1. Load the sources once as a batch: POST /attest/v1/batches with the files, or POST /attest/v1/batch with their text. You get a batchId and, per document, the hashes below.
  2. Upload the draft with POST /attest/v1/drafts. You get a draftId and the draft's fileHash.
  3. Review it with POST /attest/v1/attest/draft, naming both ids. Attest extracts the claims from the draft, checks each against the batch, and returns one result per claim in draft order, each carrying the passage it came from.
  4. Delete the batch and the draft when the report is written. Both expire on their own after six hours, but "it will age out" is a poor answer to anyone asking where a client's board pack currently is.

Why the server extracts the claims

Passing a claim list makes coverage a function of what the caller thought to submit. In real use that was the binding constraint: over a thirteen-document review a careful manual pass found thirteen errors, and a checker fed a hand-written list surfaced two, because the rest were never sent. The claims that go unsent are the ones not perceived as claims at all. "Marketing deferred three times" reads as narrative, which is precisely why it was wrong and precisely why it was skipped.

Extraction targets what gets missed: counts and tallies, elapsed durations, sequence and firsts, comparisons, aggregations that assert something about every member of a set, attributions, negations and exclusivity, and characterisations of what a document does or does not say. Compound sentences are split, so each assertion gets its own verdict.

Why files rather than text

Passing a draft as a string means the calling program, often a model, retypes its own work into a request. That is a generation step, and a generation step can drift: a figure lands a digit out, a hedge disappears. The review then runs against text nobody will read. Uploading the bytes removes the step, and fileHash proves which bytes were reviewed:

shasum -a 256 briefing.md

The same applies to evidence. fileHash is the SHA-256 of the file as uploaded and can be recomputed from the copy you hold. contentHash is the hash of the normalised text actually searched, which parsing makes version-dependent, so only fileHash proves what a verdict was produced against. A document supplied as text has no fileHash, because there was no file.

Coverage is reported, not assumed

{ "summary": { "extracted": 47, "chunks": 6, "failedChunks": 1, "truncated": false } }

A long draft is read in passages. failedChunks names stretches that could not be read and failedPassages quotes them, so a passage nothing looked at is never reported as a passage with nothing wrong. truncated: true means maxClaims was reached and later claims were not checked.

Each claim also reports coverage: in_scope when the batch could speak to it, out_of_scope with missingTerms when nothing in the batch mentions what the claim is about. Out-of-scope attention is not a finding against the draft.

Long reviews and polling

A short review finishes inside the request and returns 200. A long one returns 202 with a jobId and a poll address. config.waitMs (up to 120,000) says how long the request is held before that happens. Poll GET /attest/v1/attest/draft/jobs/{jobId} until state is done. The finished result stays for five minutes after it is first collected, so a dropped poll can be repeated, and is then forgotten.

What it costs

A draft review reserves config.maxClaims (default 200, at most 500) at two credits each up front, and settles to two credits per claim it actually checked once the result is returned or collected. Set maxClaims to reserve less. The response headers carry X-Credits-Reserved on the 202 and X-Credits-Charged on the result. See Credits and billing.

Where the files live

Batches, drafts and jobs are held in memory only, on one server. Nothing is written to disk or to a database, a restart loses every batch, and the stores are capped and evict oldest-first. The not-found errors (batch_not_found, draft_not_found, job_not_found) all have the same recovery: upload again. See Privacy.

Limits

| What | Limit | | --- | --- | | Files per batch | 200, each up to 25 MB, as PDF, Word, PowerPoint, plain text or Markdown | | Documents per text batch | 200 | | Draft upload | 2 MB and 500,000 characters of text | | Draft sent as text | 200,000 characters | | maxClaims | 1 to 500, default 200 | | waitMs | 0 to 120,000 |

Still need help?

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