Skip to main content

POST /v1/ask

POST /v1/ask asks a natural-language question over every document in your workspace and returns a cited, verified answer. One flat credit per question, no RAG stack.

POST /v1/ask is the natural-language front door to your document corpus: send a question, get back an answer grounded in your own documents, with a citation for every load-bearing claim and a verification verdict on the answer as a whole. There is no index to build, no embeddings to manage, and no retrieval pipeline to tune. Every document you ingest with ingestion_target: "ingest" (the default on [POST /v1/run](run-spec)) is askable, and the question runs over the entire workspace corpus, not a top-k slice of it.

Only one field is required: question, up to 20,000 characters. The optional fields narrow, route, shape, or thread the turn: scope restricts it to a slice of the workspace as a hard filter, conversation_id continues a thread, model and model_class pick the model, output_format shapes the answer, and on_behalf_of applies a named user's compartment visibility. All of them are covered in depth in [Scope, Models & Access](ask-scoping). The endpoint answers 202 Accepted immediately with an ask_id, a poll_url, a stream_url, and the conversation_id the turn threads into; the answer itself is produced asynchronously and collected via [GET /v1/ask/:id](ask-results) or streamed live via [GET /v1/ask/:id/stream](ask-streaming). A turn typically takes 10 to 60 seconds, which is why the surface is async-only by design: a synchronous response would sit inside edge and proxy timeouts. Authentication is a standard tlnc_ Bearer key with the read scope. The key must be workspace-scoped: asks are tenant-isolated end to end.

Why this replaces a RAG stack

A conventional RAG pipeline embeds document chunks, retrieves the top-k nearest ones, and hopes the answer is inside that slice. An ask on Talonic instead runs a read-only agent turn over a corpus that was structured at ingestion. The agent retrieves across three planes at once: a semantic match against the field registry (the deduplicated graph of every field concept discovered in your documents), a lexical match over the extracted cell values themselves, and semantic plus full-text search over the raw document text through a persistent chunk index. A question about a number, a date, or a counterparty does not depend on the right paragraph landing in a context window: the value was already extracted, typed, and bound to a canonical concept.

On top of retrieval, the agent runs read-only SQL over the structured cell plane. Questions RAG is structurally bad at, such as "how many of our contracts auto-renew?" or "what is the total value of invoices from Q2?", become aggregate queries over extracted cells with the denominator taken from real corpus coverage, never estimated from a handful of retrieved chunks. And the corpus improves as it is questioned: when a question exposes a coverage gap, the platform extracts and persists at query time, promoting or mining the concept into the structured plane, so the second time anyone asks, the answer is a plain SQL read. Your corpus gets faster and cheaper to query the more it is used, which is the opposite of a RAG stack.

Two more properties matter for trust. First, the coverage plane turns absence into evidence: "no document in the workspace mentions a termination penalty" is a checkable statement backed by corpus-wide coverage, not a guess from an empty retrieval. Second, every answer passes through a post-answer verification step that re-checks the answer's claims against the evidence the turn itself gathered, and the verdict ships in the response. See [Citations & Verification](ask-citations-verification) for how to consume both.

An ask never modifies your workspace. The turn runs under a least-privilege read-only role: documents, schemas, pipelines, and settings cannot be changed by a question, and every mutating tool is denied before it executes.
POST/v1/ask

Request body (JSON)

question*stringThe natural-language question, up to 20,000 characters. Markdown is fine; the agent reads it as plain intent.
scopeobjectRestrict the turn to a slice of the workspace: document_ids (max 1000), schema_id, pipeline_id, data_product_id, document_type, source_id, tags (max 100), ingested_after, ingested_before. Present fields are ANDed and enforced as a SQL predicate, not a hint. An empty document_ids array matches nothing.
conversation_iduuidContinue this conversation; the agent answers with the prior turns in view. Absent, a fresh conversation is created and its id returned.
modelstringRun the turn on a specific model, e.g. claude-opus. A model the workspace AI policy denies fails loudly; it is never silently substituted.
model_classstringRun the turn on a model class, e.g. complex. Used when model is absent.
output_formatobjectShape the final answer: instruction (free-text format instruction, max 4,000 chars), template (a markdown skeleton the answer keeps, max 20,000 chars). Constrains form only, never grounding.
on_behalf_ofuuidAnswer as this workspace user would see it, applying that user's compartment and classification visibility. Opt-in per request; the default reads workspace-wide. See Scope, Models & Access.

curl

Response (202)

{
  "ask_id": "7c2f0a4e-9d31-4b8a-b3e6-2f1c5d9a8e07",
  "status": "processing",
  "poll_url": "/v1/ask/7c2f0a4e-9d31-4b8a-b3e6-2f1c5d9a8e07",
  "stream_url": "/v1/ask/7c2f0a4e-9d31-4b8a-b3e6-2f1c5d9a8e07/stream",
  "conversation_id": "8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c"
}

Conversations

Every ask belongs to a conversation. Pass conversation_id to continue a thread, and the agent answers with the prior questions and answers in view, so follow-ups like "and only the ones above 50,000 EUR?" resolve against the earlier turn. Omit it and the platform creates a fresh conversation, returning its id on the 202 so the very first ask of a session already gives you the handle to thread the next one. Conversations are listed, read, renamed, and deleted through the [Conversations](agent-conversations) endpoints.

Pricing

Each accepted ask charges one flat agent_ask credit unit: 100 credits, or 0.10 EUR (1,000 credits = 1 EUR). The charge is taken when the ask is accepted and is keyed to the turn, so it is idempotent: a network retry of the same submission, or polling the result any number of times, never bills twice. There is no per-token or per-document component; a question over 10 documents and a question over 10,000 cost the same. The completed response reports the charge back in usage.credits_charged, and the full catalog is public at [GET /v1/pricing](pricing-overview).

When your balance cannot cover one unit, the ask is rejected up front with 402 insufficient_credits before any work starts. The 402 body follows the platform's agent-actionable credits contract: it names the unit, the shortfall, and a buy_credits_url, so an autonomous integration can top up and resubmit without human interpretation.

Rate limits

Ask submissions are metered in their own daily rate-limit namespace, ask, separate from extraction and platform reads. Polling GET /v1/ask/:id counts against the general read namespace, never against the ask budget, so tight polling loops are free with respect to this cap. Stream connects are metered in the separate ask_stream namespace, sized above ask to leave room for reconnects, and direct tool invocations in agent_tools; both are documented on [Streaming](ask-streaming) and [Invoke a Tool](agent-invoke-tool).

Daily ask caps by plan

freetier200 asks per day.
individualtier100 asks per day.
protier5,000 asks per day.
enterprisetierUnlimited.

Getting a key and a corpus

If your workspace already has documents, any read-scoped key works immediately. On deployments where self-serve signup is enabled, there is a zero-dashboard path from email to first answer: POST /v1/auth/register with your email sends a magic link, and following it (GET /v1/auth/register/confirm) returns a scoped tlnc_ key together with a seeded workspace containing two example documents, a Northwind invoice and an Acme/Globex master services agreement, so your very first POST /v1/ask has something real to answer against. To make your own documents askable, ingest them via [POST /v1/run](run-spec) with the default ingestion_target: "ingest".

Errors

Error responses

400validation_errorMissing or over-length question, or the API key is not workspace-scoped.
401unauthorizedMissing or invalid API key.
402insufficient_creditsBalance cannot cover one agent_ask unit. Body includes the shortfall and a buy_credits_url.
403insufficient_scopeThe key lacks the read scope.
429rate_limit_exceededDaily ask cap for your plan exhausted. Retry after the period in the Retry-After header.