202 Accepted with an operation, not a result.
Sixteen kinds of work do, from ingesting a document to running a matrix, and every one of them uses this envelope, so you write one polling loop rather than one per feature.
The type values are listed under Finding operations you did not keep.
202 also carries two headers worth using:
The five statuses
There are exactly five, and no others will ever appear.succeeded, failed and cancelled are terminal. A terminal operation always has completedAt set, and a non-terminal one never does.
Internally these features use nineteen different status vocabularies. They are mapped onto these five before they reach you, so an internal value can never leak into your integration and become something you depend on.
Reading progress
progress carries done, total and a unit. The unit matters: {done: 43, total: 100} means something quite different for cells than for documents, and a progress bar built without it will be wrong.
A partial success reports succeeded with done short of total, rather than failed. The work that completed is real and available; failing the whole operation would tell you nothing worked when most of it did.
Polling well
RespectRetry-After on the first poll, then back off. Operations remain readable for 30 days, so a poller that dies can resume.
Finding operations you did not keep
{data, pagination} page, newest first. This is how you recover an operation id you lost, and how you answer “what of mine is still running” after a restart.
Three filters, and they combine:
The sixteen
type values, measured against the job registry on 2026-09-06:
document.ingest, review.run, review.runDeep, compare.run, matrix.run, workflow.run, template.run, draft.generate, summary.generate, factSet.generate, ndaTriage.run, complianceCheck.run, playbook.extract, research.ask, deepResearch.run, message.verify.
Three of those do not match the endpoint you called.
review.runDeep is what POST /v1/matters/{matterId}/reviews produces when you send "depth": "deep".
document.ingest covers both completing an upload and saving a draft back as a document.
A draft improvement reports as draft.generate.
You only see operations whose capability your credential can read. A credential with review:read and nothing else sees reviews and no matrix runs, and one with no capability scope at all gets an empty page rather than an error. An unknown type is likewise an empty page, never a 422.
Operations drop out of this list at the same 30 days after which they stop being readable individually, so the list can never offer you an id that then answers 404.
When it fails
error carries a code and a message written for the person reading your logs. Internal exception text, file paths and stack frames are stripped before it reaches you.
A worker that dies mid-job does not leave you polling forever: a sweeper moves abandoned operations to failed with STUCK_OPERATION.
