curl --request POST \
--url https://ndi-api.nace.ai/v1/workspaces/{workspace_id}/tools/qa-file \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"path": "<string>",
"query": "<string>"
}
'{
"answer": "<string>",
"citations": [
{
"file_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"path": "<string>",
"relevance_score": 123,
"snippet": "<string>",
"why": "<string>",
"component": "<string>",
"line_end": 123,
"line_start": 123,
"locator": {
"char_end": 123,
"char_start": 123,
"kind": "text_range",
"page": 123,
"pages": [
123
]
},
"page": 123,
"sql_table": "<string>"
}
],
"engine": "recursive_llm",
"confidence": "certain",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"structured_answer": "<unknown>",
"timed_out": false,
"unavailable": []
}{
"created_at": "2023-11-07T05:31:56Z",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "parse",
"status": "queued",
"cost": {
"lines": [
{
"amount_usd": "<string>",
"execution": "fresh",
"operation": "parse",
"quantity": 1,
"unit": "page",
"unit_price_usd": "<string>",
"reuse_reason": "reused_parse"
}
],
"pricing_version": "<string>",
"total_usd": "<string>",
"currency": "USD"
},
"credit_schedule_version": 123,
"credits": 123,
"deleted_at": "2023-11-07T05:31:56Z",
"effort": "<string>",
"error": {
"code": "invalid_request",
"message": "<string>",
"retryable": true,
"detail": {},
"request_id": "<string>"
},
"finished_at": "2023-11-07T05:31:56Z",
"force": true,
"idempotency_key": "<string>",
"name": "<string>",
"payload_expires_at": "2023-11-07T05:31:56Z",
"progress": {
"items_done": 0,
"items_failed": 0,
"items_total": 123,
"knowledge_graph": {
"countable": true,
"phase_count": 123,
"phase_index": 123,
"documents": 123,
"mentions": 123,
"step": "<string>",
"step_done": 123,
"step_total": 123
},
"routing": {
"final": "fact",
"reason": "<string>",
"router_model": "<string>",
"selected": "fact",
"delegated_wall_ms": 123,
"fact_wall_ms": 123,
"router": {
"kind": "llm"
},
"router_wall_ms": 123
},
"stage": "<string>",
"units_done": 0,
"units_total": 123
},
"project_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"query": "<string>",
"query_scope": {
"type": "workspace"
},
"result": {
"output": {
"categories": [
{
"count": 123,
"name": "<string>"
}
],
"coverage": {
"labels_required": [
"<string>"
],
"request_access_hint": "<string>",
"restricted_candidates": 0
},
"directory": "<string>",
"file_entries": [
{
"ingestion_status": "discovered",
"path": "<string>",
"size_bytes": 123,
"category": "<string>",
"kind": "<string>",
"uploaded_at": "2023-11-07T05:31:56Z"
}
],
"files_truncated": true,
"ingestion_summary": {},
"overall_files": 123,
"subdirectories": [
{
"name": "<string>",
"overall_files": 123,
"failed_files": 123,
"top_categories": [
{
"count": 123,
"name": "<string>"
}
]
}
],
"hint": "<string>",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"result_type": "folder_metadata"
},
"result_state": "available",
"source": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "upload"
},
"started_at": "2023-11-07T05:31:56Z",
"surface": "deep_search",
"units": 0,
"usage": {
"lines": [
{
"credits": 1,
"credits_per_unit": 1,
"multiplier": 2,
"part": "parse",
"quantity": 1,
"unit": "page",
"waiver": {
"part": "parse",
"reason": "reused_parse",
"source_job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}
]
},
"usage_final": false,
"usage_finalized_at": "2023-11-07T05:31:56Z",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}qa_file
Answer a natural-language question about one uploaded file — document, media, image, or table.
Cost class: slow.
path names an uploaded source file — the same addressing as
read_file; a workspace-internal path is refused with
invalid_request.
The engine is picked from what the file (or the selected component) is:
an image goes to vision QA, and text — of any length — to a recursive LLM
built for long documents. A file with several parts (a pdf split into
sections, a workbook with several tabs, a recording with attachments) or
with rows (a spreadsheet tab, a csv/parquet/jsonl upload, a pdf’s long
table) is worked by a QA agent that searches within the file, reads the
relevant parts, and writes its own SQL over the file’s tables. The
response’s engine field reports which one ran.
Scope the question with component=<name> (the names file_metadata
lists) to ask about one section directly. Use this when you need a
direct, cited answer about a file’s contents rather than search hits.
Execution survives HTTP disconnects. By default the route waits and returns
the original answer shape. Send Prefer: respond-async to return a Job
immediately, then poll its Location URL. Idempotency-Key recovers the
same job after a lost response. Only explicit job cancellation stops it.
curl --request POST \
--url https://ndi-api.nace.ai/v1/workspaces/{workspace_id}/tools/qa-file \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"path": "<string>",
"query": "<string>"
}
'{
"answer": "<string>",
"citations": [
{
"file_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"path": "<string>",
"relevance_score": 123,
"snippet": "<string>",
"why": "<string>",
"component": "<string>",
"line_end": 123,
"line_start": 123,
"locator": {
"char_end": 123,
"char_start": 123,
"kind": "text_range",
"page": 123,
"pages": [
123
]
},
"page": 123,
"sql_table": "<string>"
}
],
"engine": "recursive_llm",
"confidence": "certain",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"structured_answer": "<unknown>",
"timed_out": false,
"unavailable": []
}{
"created_at": "2023-11-07T05:31:56Z",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "parse",
"status": "queued",
"cost": {
"lines": [
{
"amount_usd": "<string>",
"execution": "fresh",
"operation": "parse",
"quantity": 1,
"unit": "page",
"unit_price_usd": "<string>",
"reuse_reason": "reused_parse"
}
],
"pricing_version": "<string>",
"total_usd": "<string>",
"currency": "USD"
},
"credit_schedule_version": 123,
"credits": 123,
"deleted_at": "2023-11-07T05:31:56Z",
"effort": "<string>",
"error": {
"code": "invalid_request",
"message": "<string>",
"retryable": true,
"detail": {},
"request_id": "<string>"
},
"finished_at": "2023-11-07T05:31:56Z",
"force": true,
"idempotency_key": "<string>",
"name": "<string>",
"payload_expires_at": "2023-11-07T05:31:56Z",
"progress": {
"items_done": 0,
"items_failed": 0,
"items_total": 123,
"knowledge_graph": {
"countable": true,
"phase_count": 123,
"phase_index": 123,
"documents": 123,
"mentions": 123,
"step": "<string>",
"step_done": 123,
"step_total": 123
},
"routing": {
"final": "fact",
"reason": "<string>",
"router_model": "<string>",
"selected": "fact",
"delegated_wall_ms": 123,
"fact_wall_ms": 123,
"router": {
"kind": "llm"
},
"router_wall_ms": 123
},
"stage": "<string>",
"units_done": 0,
"units_total": 123
},
"project_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"query": "<string>",
"query_scope": {
"type": "workspace"
},
"result": {
"output": {
"categories": [
{
"count": 123,
"name": "<string>"
}
],
"coverage": {
"labels_required": [
"<string>"
],
"request_access_hint": "<string>",
"restricted_candidates": 0
},
"directory": "<string>",
"file_entries": [
{
"ingestion_status": "discovered",
"path": "<string>",
"size_bytes": 123,
"category": "<string>",
"kind": "<string>",
"uploaded_at": "2023-11-07T05:31:56Z"
}
],
"files_truncated": true,
"ingestion_summary": {},
"overall_files": 123,
"subdirectories": [
{
"name": "<string>",
"overall_files": 123,
"failed_files": 123,
"top_categories": [
{
"count": 123,
"name": "<string>"
}
]
}
],
"hint": "<string>",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"result_type": "folder_metadata"
},
"result_state": "available",
"source": {
"upload_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "upload"
},
"started_at": "2023-11-07T05:31:56Z",
"surface": "deep_search",
"units": 0,
"usage": {
"lines": [
{
"credits": 1,
"credits_per_unit": 1,
"multiplier": 2,
"part": "parse",
"quantity": 1,
"unit": "page",
"waiver": {
"part": "parse",
"reason": "reused_parse",
"source_job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}
]
},
"usage_final": false,
"usage_finalized_at": "2023-11-07T05:31:56Z",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}Authorizations
Headers
Replaying a request with the same key returns the original job with 200, never a second job. The key is kept with the job for replay and never cleared, so it must not contain personal data.
200Path Parameters
Workspace identifier.
Body
Request body for qa-file.
path names an uploaded source file — the same addressing as
read-file; a workspace-internal derivative path is refused with
invalid_request. component scopes the question to one public
component by name (a pdf section or a workbook tab — the names
file-metadata lists). For a PDF it may also name one of the figures
file-metadata lists (figure p3-1: vision over that picture alone)
or a page (page 3: vision over the whole rendered page).
1 - 4096A JSON Schema (Draft 2020-12, object root, local non-recursive $ref only, no pattern, patternProperties or unevaluated*) the answer must follow. When set, the agent writes answer as JSON text conforming to it, the run checks that and asks the agent to correct a mismatch, and the result carries the parsed value in structured_answer. A field the source does not state comes back null, whatever type the schema gives it. Explanation goes to reasoning where the result has one, and evidences are unchanged. If the answer still misses the schema, the run succeeds with answer as written and structured_answer null. Omit for a prose answer.
Show child attributes
Show child attributes
Response
Successful Response
- QaFileResponse
- Job
Response body for qa-file.
engine reports what answered: recursive_llm for prose, vision
for an image, and agent when the file has several parts and a QA agent
worked across them. Citations always name the uploaded file, never
anything internal.
job_id is the durable job row created for this run; poll or retrieve
it via GET /v1/jobs/{job_id} to get the stored answer after the fact.
unavailable is always empty since table files moved to query-tables
(which reports unqueryable selections there); the field is retained for
wire compatibility.
Show child attributes
Show child attributes
recursive_llm, vision, agent The engine's self-graded confidence in the answer — how well the file content it read supports it, on the shared six-level scale (certain / very_high / high / medium / low / speculative). Null when the engine could not grade (a timeout's partial answer, a legacy run).
certain, very_high, high, medium, low, speculative answer parsed as JSON, set only when the request carried output_schema and the answer validates against it; a field the source does not state is null whatever type the schema gives it. Null on every run without a schema, and on a run whose answer still missed the schema after its corrections, where answer holds the text as written.
Show child attributes
Show child attributes