Workspaces

Search

One question, answered once, from a workspace's files.

The box at the top of a workspace, under File search in the sidebar, asks one question of its files and answers it once. It reads only files that are Ready.

From code, the same search is POST /v1/workspaces/{workspace_id}/automatic-search. Every example below is a whole request for a workspace you created and ingested; see the Python, TypeScript and CLI pages for the SDK and CLI details.

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "path_prefix": "reports/2025",
    "mode": "agent"
  }'

How it runs

A search creates a job, like the tools: ?wait_seconds (0 to 60; more waits 60) works the same way, an Idempotency-Key lets an identical retry return the original job (use a new key when the question, mode or other inputs change), the answer is 200 when the job finishes within the wait and 202 otherwise, and you read the result as in Jobs and results.

Automatic searches are limited to 60 per account every 10 minutes. Past that, a request is refused with 429 rate_limited before any job is created: wait the retry-after seconds it gives, then send it again.

Pricing to be announced.

Settings

In the dashboard, these are the workspace's Settings tab, beside the box, and the folder choice in the box. Each applies to every search from the box and is saved for the workspace. From code, each is an option of the request.

Workspace

Which workspace to search. In the dashboard, a workspace's own box searches that workspace. From code, the workspace is in the URL, as its workspace_id.

# The workspace is in the URL: its workspace_id
WORKSPACE_ID=<workspace_id>

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "What were total liabilities at year end?" }'
OptionTypeDefault
workspace_id, in the URLstringRequired

Folder

Whole workspace is the default. Pick one folder the files sit in from the list, or type or paste a path.

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "path_prefix": "reports/2025"
  }'
OptionTypeDefault
path_prefixstringWhole workspace

Mode

Which search runs.

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "mode": "fact"
  }'
OptionTypeDefault
mode"auto" | "fact" | "agent"auto
ModeWhat it does
Auto (auto, the default)Reads the question first and picks: a fast lookup for a focused fact, or the agent for anything that needs investigating.
Fast (fact)One pass over the workspace. Answers in seconds when the fact is stated somewhere.
Agent (agent; Deep in the dashboard)Reads documents and queries tables until it can answer, so it can combine figures across files. Takes longer.

While a search runs, the dashboard says what it is doing and, in Auto, which route it chose. The route chosen for a question can differ between similar questions, so pick Fast or Agent (Deep in the dashboard) when you know which you want: Fast for a stated fact, Agent for anything that needs reading, calculating or listing.

Add context

Background the search should know. In the dashboard this is Background in Settings, and every search from the workspace uses it.

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "context": "Entity: Acme Holdings Ltd. Fiscal year ends 30 June."
  }'
OptionTypeDefault
contextstringNone

Structured output

A JSON Schema the answer must follow. In the dashboard this is Answer format, in Settings. A schema that is not a JSON object blocks the search until you fix or clear it.

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "output_schema": {"type": "object", "properties": {"total_liabilities": {"type": "number"}, "currency": {"type": "string"}}}
  }'
OptionTypeDefault
output_schemaobjectNone

The answer then also comes back as JSON in structured_answer.

The root must be an object; wrap a list as {"items": [...]}. $ref may only point inside the schema, and not back at itself. pattern, patternProperties, unevaluatedProperties and unevaluatedItems are refused: describe a format in description instead.

The answer is checked against the schema and corrected when it misses. structured_answer then holds the parsed value: output.structured_answer for a fact answer, output.answer.structured_answer for the agent. If the answer still misses the schema, the job succeeds with structured_answer: null and the text in answer. Read structured_answer, not answer. output_schema never changes the route.

More options from code

A request takes two more options and two query settings that the dashboard doesn't expose:

curl "https://console.nace.ai/v1/workspaces/$WORKSPACE_ID/automatic-search?wait_seconds=60" \
  -H "Authorization: Bearer $NACE_API_KEY" \
  -H "Idempotency-Key: liabilities-fy25" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What were total liabilities at year end?",
    "paths": ["contracts/acme-msa.pdf"],
    "top_k": 10
  }'
OptionTypeDefaultWhat it does
pathsstring[]NoneSearch exactly these uploaded files too, by path. No limit on how many. Adds to Folder: the search covers every file under the folder plus every named file. A path that names no file is refused with 404 file_not_found, and one you aren't allowed to read with 403 access_denied, before any job is created.
top_kinteger6How many evidences a fast answer cites, 1 to 50. A cap on the citation list, not on how much is read. The agent ignores it.
wait_secondsinteger0How long the request waits for the job, 0 to 60. See How it runs.
Idempotency-KeyheaderNoneSending the same key with identical inputs returns the same job; use a new key for changed inputs. The SDKs call it idempotency_key.

The answer

A finished search shows these, each a field of the job's result:

In the dashboardFieldType
Which route answeredrouting.final"fact" | "agent"
How confident it is, from Speculative to Certainoutput.confidence"certain" | "very_high" | "high" | "medium" | "low" | "speculative"
The answer itselfoutput.answerstring
A table of rows, when the question asked for a list (which invoices are over $10,000), with one row per matching file or part of oneoutput.catalogobject | null
The evidence: each passage the answer rests on, with its file, page, the quote and why it mattersoutput.evidencesobject[], see Evidences

On an agent answer, the same fields sit under output.answer; see Fact answers and Agent answers for every field.

For the question above, a fast answer looks like this:

{
  "result_type": "automatic_search",
  "routing": { "selected": "fact", "final": "fact", "reason": "One stated figure from the statements." },
  "output": {
    "result_type": "intelligent_search",
    "answer": "Total liabilities were 4,215,300 USD at 31 December 2025.",
    "confidence": "high",
    "evidences": [
      {
        "source_path": "reports/2025/annual-report.pdf",
        "page": 12,
        "quote": "Total liabilities 4,215,300",
        "relevance": "States total liabilities at year end."
      }
    ],
    "grounding_job_ids": ["c41d7e2a-9b3f-4c6d-8e1a-2b3c4d5e6f70"]
  }
}

In the dashboard, that is the answer with its route and High confidence, and one passage from annual-report.pdf, page 12. The example leaves out fields that are null or not shown; see Fact answers and Agent answers for the full result.

Fact answers

output.result_type is "intelligent_search". A fact search reads once and answers in seconds.

FieldTypeWhat it holds
answerstringThe answer, as text.
structured_answerobject | nullThe answer parsed as JSON, with output_schema. Otherwise null.
reasoningstringHow the evidences add up to the answer, including any assumption it made.
confidence"certain" | "very_high" | "high" | "medium" | "low" | "speculative"How sure the answer is.
evidencesobject[]What it cites, most important first. See Evidences.
grounding_job_idsstring[]Jobs that locate each quote. See Evidences.
coverageobjectSee Coverage.

Agent answers

output.result_type is "automatic_agent". The agent reads documents, writes SQL over tables and lists matching documents, for as long as the question needs. Its answer is in output.answer:

FieldTypeWhat it holds
answer.answerstring | nullThe answer, as text.
answer.structured_answerobject | nullThe answer parsed as JSON, with output_schema. Otherwise null.
answer.reasoningstringAs on a fact answer.
answer.confidencestring | nullAs on a fact answer. null when the agent graded none, as when it ran out of steps.
answer.evidencesobject[]As on a fact answer. See Evidences.
answer.sql_receiptsobject[]Every SQL statement the agent ran, in order: result_id and the sql as it ran.
answer.coverageobject[]One entry per thing the question asked for. See Coverage.
answer.exhaustedbooleantrue when the agent ran out of steps first. The answer is partial, and the job still succeeded.
answer.grounding_job_idsnullAlways null: an agent answer starts no jobs to locate its quotes. See Evidences.
output.catalogobject | nullA catalog table when the agent answered by listing documents. Otherwise null.

Evidences (citations)

Every answer cites the passages it rests on. The API calls them evidences; the dashboard shows them as the numbered evidence beside the answer. Each one is an object in output.evidences:

FieldTypeWhat it holds
source_pathstringThe cited file's path in the workspace.
source_file_idstringThe cited file's id.
pageinteger | nullThe page the quote is on, when it has one.
componentstring | nullA sheet or section, when the file has them.
quotestringThe passage, as it appears in the file.
relevancestringWhy it matters to the question.

Phrases of the answer that rest on evidence are underlined, with the evidence's number after them. Select one to mark that evidence and open its file at the passage. The underlines come a moment after the answer, once its phrases are matched to the evidence; an answer that has not been matched reads without them.

Each passage is then looked for in its file: it shows Locating while that runs, then Located or Not located. Select a passage or a row to open its file at that page; a located passage is highlighted there.

From code, whether you get those locations depends on the route that answered:

Route (routing.final)Locations
factThe answer lists Ground jobs in output.grounding_job_ids, one per quote. Read each as a job to get the quote's location.
agentNone. output.answer.grounding_job_ids is null. Run Ground yourself on each cited file, with a workspace_file source naming the workspace and the evidence's source_file_id. It is billed like any Ground job.

This applies to a search in Auto mode that the service sent to the agent too, so check routing.final, not the mode you sent. See Quote locations.

Follow-ups

A search runs once and keeps no conversation.

Catalog tables

When the agent answers a filter, rank or count question by listing documents, such as "invoices over 10,000 from Q4", it adds a catalog table: output.catalog in automatic search, catalog in QA.

FieldTypeWhat it holds
columnsobject[]Each column's field, kind (text, date, money, number or boolean) and description. filtered marks the columns the matches depend on; requested, fields you asked to see.
rowsobject[]The first matching entries, up to 200. Each has source_path and source_file_id, entry_id, summary, and cells: one per column, with its status (found, not_found, ambiguous or unexamined), a typed value and a citation.
total_matchesintegerHow many entries match in all, beyond the rows returned.
total_filesintegerHow many files those matches come from.
exhaustivebooleantrue only when every file in scope was fully read. When false, the rows are valid, but total_matches may not be a complete count.

The table holds its first rows only. To see more, narrow the question or the scope.

Coverage

  • Files withheld: on a fact answer and a catalog table, coverage.restricted_candidates counts matching files the search wasn't allowed to read. 0 means nothing was withheld.
  • What was answered: on an agent answer, answer.coverage has one entry per thing the question asked for, with a status of answered, partial or unanswerable, and missing_inputs saying what kept it from a full answer.

Errors

ErrorWhen
404 workspace_not_foundThe workspace isn't one you can use, or it was deleted.
404 file_not_foundA paths entry names no uploaded file in the workspace.
403 access_deniedA paths entry names a file you aren't allowed to read.
422 invalid_requestA blank query, top_k outside 1 to 50, a path with a . or .. segment, or an output_schema that breaks the rules above.
429 rate_limitedOver 60 automatic searches and QA turns for the account in 10 minutes. Wait retry-after seconds.

Every other error is on Errors.

Coming back to it

The open search is part of the page address, so a reload or a shared link opens the same answer. The Searches tab lists the workspace's recent searches, and Usage › Logs links to each one. An answer stays until explicit deletion. From code, read a search again with GET /v1/documents/jobs/{job_id}.

Searches are limited to 60 per account every 10 minutes.

Next steps

Keep the workspace's files current with Workspace files, or locate a quote exactly with Ground.

On this page