The rule, in one line
A delete removes what you named and refuses anything that would take something else with it. That means “delete an empty thing” for a container and “delete this thing” for a leaf. It is deliberately conservative: your real need is to undo what you just made, and you can always empty a container first. A singleDELETE that quietly removed a hundred documents, their stored files and their vectors is not an operation anybody can safely retry.
Deleted means deleted
Some resources go to a trash a person can see in the app. Drafts and comparisons do; documents, clients, matters, folders, reviews, workflow runs and matrices do not. From this API the two are indistinguishable, on purpose. A deleted resource answers404 on its own GET, disappears from its own list, and stops being exportable. Nothing here brings it back.
There is no ?hard=true, no deletedAt field and no restore operation, and there will not be: an irreversible variant of something whose reversible variant you cannot observe is a footgun with no upside. Each delete’s own description in the Workspace Reference says whether a colleague could still restore it in the app.
Delete is not idempotent
ADELETE that removed a row answers 204. Repeating it answers 404, because we report what actually happened rather than assuming success. PostgREST reports success for a delete that matched nothing, so “always 204” would mean answering 204 for a mistyped id too.
There is no Idempotency-Key on a delete.
What refuses, and why
Every refusal is a409, never a 403. On this API a 403 means your credential is missing a scope or your installation is inactive, and both send you to rotate a credential. A refusal about the state of a row must not read like that.
409 resource-not-empty — the container still holds something
409 resource-not-empty — the container still holds something
Read
blockers. It names every reason and how many of each, so you can clear them in one pass rather than discovering them one at a time.409 operation-in-flight — a job is still writing to it
409 operation-in-flight — a job is still writing to it
Poll
operationId when the problem carries one, then repeat the delete. It is absent when the work was started in the app, because there is no operation of ours to poll; read the resource’s own status instead.There is no way to cancel work through this API. A delete that killed a running job would be a second way to spend your money and lose the result.409 matter-not-deletable — it is the default matter
409 matter-not-deletable — it is the default matter
Every organization has exactly one, minted at signup, and it cannot be deleted here or in the app. Emptying it will not help. Create matters explicitly with
POST /v1/matters rather than writing into the default one, and a matter your integration created can be emptied and deleted.Per resource
Playbooks cannot be deleted through this API. There is no
playbooks.delete
operation, and a DELETE against a playbook path answers 405 method-not-allowed. A playbook you no longer want can be emptied with
playbooks.update, or deleted by its owner in the app. The gap is deliberate
for now: a review records the playbook it ran against as a plain JSONB key with
no foreign key, so nothing in the database stops a deletion from leaving twelve
completed reviews pointing at a row that is gone.
Deleting a document reaches further than the document
This is the one delete with a blast radius worth reading before you loop over it. Removing a document also removes:- its extracted text, its versions and its stored original;
- its highlights, flags, obligations and summary;
- its entries in the matter’s chronology;
- its row, and that row’s answers, in every document matrix it appears in.
Scopes
Most deletes carry the resource’s write scope. Three do not, because the scope taxonomy has no write scope for them::run reads as “starting work” and these are deletes. The taxonomy is a frozen contract, and adding compare:write would make the operation answer 403 for every credential already issued, including yours. If you are minting a credential for a cleanup job, grant the :run scope for those three.
A worked cleanup
Undoing everything one run created, in the order the refusals allow:1
Delete the runs and results
comparisons.list, reviews.list, workflowRuns.list and matrices.list inside the matter, then delete each. Anything still running answers 409 operation-in-flight; poll it and come back.2
Delete the drafts and documents
drafts.list and documents.list, then delete each. Abort any upload session you left open with DELETE /v1/uploads/{uploadId}; find them with GET /v1/uploads?status=in_progress.3
Delete the folders, deepest first
GET /v1/folders?parentId= walks one level down. A folder with a child folder answers 409 resource-not-empty, so clear the leaves first.4
Delete the matter, then the client
The matter refuses while anything is left, and names what. The client refuses while it owns a matter.

