This API does not stream. An ask answers
202 with an operation; you poll it, then read the answer off the message it points at. Why, and what it costs you, is below.The loop
Four calls: open a conversation once, then ask, poll, read.messages.list shows the turn immediately with the answer empty and its status set to queued. You can poll either the operation or the message; they report the same thing.
Why there is no stream
The web app streams tokens over SSE, and this API deliberately does not publish that. Four reasons, all pointing the same way. Your backend is not a browser. The value of a token stream is a human watching text appear. Consuming SSE from a server means holding a connection open through a load balancer for the whole generation, reassembling a token stream into a string you were going to buffer anyway, and handling a mid-stream disconnect with no way to ask what you missed. It is strictly more work than polling. An answer takes tens of seconds. Well past the threshold where this API returns200 with a result rather than 202 with an operation. Deep tier adds multi-hop retrieval; agentic mode adds a tool loop.
The operation envelope has nowhere to put half an answer. It carries five statuses, an optional progress and a resource pointer. Adding a partial-text field would put a chat-specific field on the shape every capability on this API shares, and a published field can never be withdrawn.
We already made this call once, for drafting. The streaming draft endpoint was removed because it bound the work to a browser tab and lost the result on a refresh. A backend that loses its connection has no refresh button.
The honest cost: if you are relaying our answers to your own end user, they see a spinner for the whole generation where a Vaquill user sees text appearing. If that matters to you, tell us; the fix is a second route that replays a stored message, not a different shape for the ask.
Toggles: omitting one does not turn it off
Every research toggle is three-valued.
This is the field integrators get wrong most often. A matter has web search and corpus search ON by default, so leaving
enableWebSearch out of your request leaves it on. Send false to turn it off.
The matter’s own settings are readable and writable at /v1/matters/{matterId}/research-config, which carries matters:read and matters:write rather than the research scopes: they change what every future answer costs, so a reporting credential should not be able to touch them.
Pinning documents: two fields, and they are not the same
Use
groundIn when the documents ARE the answer (“what does this contract say”). Use alsoConsider when they are context for a wider question (“how does this compare to market”).
Sending both is refused with research-scope-rejected. Internally the locked list wins and the additive one is dropped, so accepting both would answer your question differently from how you asked it and say nothing.
Both cap at 20 documents. Every id is checked against your organization and against the matter in the path before it reaches retrieval.
What actually ran
Two settings objects come back on every message this API produced.requestedSettingsis what you asked for.effectiveSettingsis what the pipeline recorded doing.
- Agentic mode forces the standard tier. Agentic mode runs on the standard model, so
ragTier: "deep"withenableAgenticMode: truewould silently become standard. This API refuses that combination outright rather than demoting it. - A pinned document forces deep research off. Answering from the web while ignoring the file you pinned is wrong, so
enableDeepResearchMode: truewithgroundInset produces an ordinary retrieval answer.requestedSettings.deepResearchModewill betrueand the answer will have no web citations.
effectiveSettings.answeredBy is the other one to read. A question can be answered by a route other than research (a document summarizer, a redline generator), and when it is, ragTier is null and answeredBy names the engine. Those answers carry no citations and cannot be verified.
Citations
Every answer carries acitations array matched to the [N] markers in its text.
sourceType is one of document (one of your own files), corpus (a statute, regulation, rule or case), web, or draft. pageStart and pageEnd are published only for document, so you can jump a viewer to the page. citation carries the formal legal citation string where the source has one.
Retrieval internals are not published: no chunk ids, no character offsets, no relevance scores, and no links into our storage. A document’s location is its documentId, which you can resolve through this API.
Verifying an answer
contradictedClaims, where a source says something different from what the answer said. unverified is common and is not by itself an error; a claim of general law often has no supporting passage in your documents.
An answer with no stored source passages is refused with message-not-verifiable. That is a real state rather than a bug: a summarize, extract or rewrite turn emits no source cards.
Verifying twice replaces the previous result. There is one verification per message.
Skills
A skill is a named prompt that steers an answer. Discover them withGET /v1/skills and pass one as skillSlug on an ask.
Only system skills and your organization’s skills are listed. Skills belonging to an individual person are invisible to a machine credential: there is no person behind an API key, and borrowing the identity of whoever set up the integration would let one lawyer’s private prompts drive your organization’s automated research.
An unknown slug is refused with skill-not-found rather than ignored. A skill changes the prompt behind the answer, so a typo that was quietly dropped would hand you a confident answer written by something else.
Deep research
A long web-research pass, run into a conversation:202 and a poll. The report lands as a message in the conversation with its sources as citations, which is where you read it afterwards.
Different from asking with enableDeepResearchMode: that runs the research pipeline and can fall back to retrieval; this is the web pass on its own, over the open web, with no matter documents and no corpus in play.
Standalone web research
Three routes that touch no client data, take no matter and store nothing:
They answer
200 directly. Sort on authorityScore and isAuthoritativeSource to prefer courts, legislatures and agencies over commentary; those describe the HOST rather than our ranking of it. Our own relevance score is not published, because it is a scale we retune.
Deleting a conversation
DELETE /v1/matters/{matterId}/chats/{chatId} removes the conversation and everything derived from it: its messages, its in-conversation threads, its per-document reading outlines, its message edit history and its verifications. Five tables, none of them a resource this API publishes on its own. Nothing else in the system references a conversation.
A conversation with an ask, a deep-research run or a verification still running is refused with 409 operation-in-flight. Poll what you started, then delete.
Limits
Over a concurrency limit you get
429 concurrency-limit-reached, counting your own unfinished runs, so it clears itself.
