{"openapi":"3.1.0","info":{"title":"NDI Service","description":"Nace Document Intelligence Service API","version":"0.1.0"},"paths":{"/api/v1/parse_async":{"post":{"tags":["public-api"],"summary":"Parse Async","description":"Start a parse job; returns a ``job_id`` to poll.","operationId":"parse_async_api_v1_parse_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseJobRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"200":{"description":"Idempotent replay — a job with this idempotency_key already exists; body is its current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/parse":{"post":{"tags":["public-api"],"summary":"Parse Sync","description":"Parse a document and wait for the result (small documents; use /parse_async for large ones).","operationId":"parse_sync_api_v1_parse_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"timeout_seconds","in":"query","required":false,"schema":{"type":"number","maximum":300.0,"minimum":1.0,"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id}).","default":120.0,"title":"Timeout Seconds"},"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseJobRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"},"202":{"description":"The job started but no sync capacity was available; poll GET /jobs/{job_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"408":{"description":"The job did not finish within timeout_seconds; poll GET /jobs/{job_id}."}}}},"/api/v1/upload":{"post":{"tags":["public-api"],"summary":"Upload File","description":"Stage a document and return an opaque ``file_id``.\n\nPass ``ndi://file/<file_id>`` as ``source_url`` on any action endpoint.\nUpload once, reuse across parse → categorize / ground.\n\nOrdinary uploads have no expiry and stay until explicit deletion.","operationId":"upload_file_api_v1_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_api_v1_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__UploadResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Upload exceeds NDI_MAX_UPLOAD_BYTES."},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/ground_async":{"post":{"tags":["public-api"],"summary":"Ground Async","description":"Start a ground job: locate target snippets inside a document.","operationId":"ground_async_api_v1_ground_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundJobRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"200":{"description":"Idempotent replay — a job with this idempotency_key already exists; body is its current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/ground":{"post":{"tags":["public-api"],"summary":"Ground Sync","description":"Ground values in a document and wait for the result.","operationId":"ground_sync_api_v1_ground_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"timeout_seconds","in":"query","required":false,"schema":{"type":"number","maximum":300.0,"minimum":1.0,"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id}).","default":120.0,"title":"Timeout Seconds"},"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundJobRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"},"202":{"description":"The job started but no sync capacity was available; poll GET /jobs/{job_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"408":{"description":"The job did not finish within timeout_seconds; poll GET /jobs/{job_id}."}}}},"/api/v1/categorize_async":{"post":{"tags":["public-api"],"summary":"Categorize Async","description":"Start a categorize job: classify document segments/sheets against a taxonomy.","operationId":"categorize_async_api_v1_categorize_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorizeJobRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"200":{"description":"Idempotent replay — a job with this idempotency_key already exists; body is its current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/categorize":{"post":{"tags":["public-api"],"summary":"Categorize Sync","description":"Categorize a document and wait for the result.","operationId":"categorize_sync_api_v1_categorize_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"timeout_seconds","in":"query","required":false,"schema":{"type":"number","maximum":300.0,"minimum":1.0,"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id}).","default":120.0,"title":"Timeout Seconds"},"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategorizeJobRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"},"202":{"description":"The job started but no sync capacity was available; poll GET /jobs/{job_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"408":{"description":"The job did not finish within timeout_seconds; poll GET /jobs/{job_id}."}}}},"/api/v1/extract/schema/validate":{"post":{"tags":["public-api"],"summary":"Validate Extract Schema","description":"Validate an Extract schema without creating a job or consuming credits.","operationId":"validate_extract_schema_api_v1_extract_schema_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__ExtractSchemaValidationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__ExtractSchemaValidationResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/extract_async":{"post":{"tags":["public-api"],"summary":"Extract Async","description":"Start an extract job: pull schema-shaped structured data out of a document.","operationId":"extract_async_api_v1_extract_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractJobRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"200":{"description":"Idempotent replay — a job with this idempotency_key already exists; body is its current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/extract":{"post":{"tags":["public-api"],"summary":"Extract Sync","description":"Extract structured data from a document and wait for the result.","operationId":"extract_sync_api_v1_extract_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"timeout_seconds","in":"query","required":false,"schema":{"type":"number","maximum":300.0,"minimum":1.0,"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id}).","default":120.0,"title":"Timeout Seconds"},"description":"Max seconds to wait before returning 408 (the job keeps running; poll GET /jobs/{job_id})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractJobRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"},"202":{"description":"The job started but no sync capacity was available; poll GET /jobs/{job_id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"408":{"description":"The job did not finish within timeout_seconds; poll GET /jobs/{job_id}."}}}},"/api/v1/jobs":{"get":{"tags":["public-api"],"summary":"List Jobs","description":"List the tenant's jobs, newest first (summaries only — no result payloads).","operationId":"list_jobs_api_v1_jobs_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Jobs per page.","default":50,"title":"Limit"},"description":"Jobs per page."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"``next_cursor`` from the previous page; omit for the newest page.","title":"Cursor"},"description":"``next_cursor`` from the previous page; omit for the newest page."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pending|running|succeeded|failed)$"},{"type":"null"}],"description":"Optional status filter.","title":"Status"},"description":"Optional status filter."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/jobs/{job_id}":{"get":{"tags":["public-api"],"summary":"Get Job","description":"Return the current state of a job (tenant-scoped; other tenants see 404).","operationId":"get_job_api_v1_jobs__job_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/jobs/{job_id}/cancel":{"post":{"tags":["public-api"],"summary":"Cancel Job","description":"Cancel a pending/running job.\n\nCancellation surfaces as ``status=failed`` with ``error.code=cancelled``\n(there is no separate ``cancelled`` status). Idempotent: cancelling an\nalready-terminal job returns its current state unchanged.","operationId":"cancel_job_api_v1_jobs__job_id__cancel_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__JobStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/usage":{"get":{"tags":["public-api"],"summary":"Get Usage","description":"Return the tenant's resource allowance and finalized consumption.\n\nLike the other GET endpoints, not RPM-limited — safe for dashboards to\npoll.","operationId":"get_usage_api_v1_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__UsageResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/example":{"get":{"tags":["public-api"],"summary":"Get Example","description":"Return (provisioning on first call) the tenant's Playground example.","operationId":"get_example_api_v1_example_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExampleResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No example is configured (or the tenant's storage mode does not support it)."},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"The published example manifest is unreadable or invalid — operator attention needed."}},"security":[{"APIKeyHeader":[]}]}},"/api/v1/health/load":{"get":{"tags":["health"],"summary":"Get Load Probe","description":"Return per-status (and per-action) row counts for the calling client.\n\nThe query is two ``GROUP BY`` selects against ``api_requests``:\n\n1. Status totals across all rows belonging to the client (cheap; the\n   table is partitioned by client in production and ``status`` is\n   cardinality-bounded).\n2. Status × action totals filtered to ``created_at >= now() - window``\n   (uses the existing ``(client, created_at)`` index).\n\nBoth queries are read-only and idempotent — safe to poll at 1 Hz.","operationId":"get_load_probe_api_v1_health_load_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"window_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":86400,"minimum":1,"description":"Window for the ``in_window`` counts, measured from ``created_at``.","default":300,"title":"Window Seconds"},"description":"Window for the ``in_window`` counts, measured from ``created_at``."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoadProbeResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/console/email-code/request":{"post":{"tags":["console","console"],"summary":"Request Email Code","description":"Mail a sign-in code if this address has a console account. The answer never says whether it does.","operationId":"request_email_code_api_v1_console_email_code_request_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailCodeRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailCodeRequestAccepted"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Email sign-in is unavailable (its store is unreachable)."},"429":{"description":"Too many requests for this address or from this network; see Retry-After."}}}},"/api/v1/console/email-code/verify":{"post":{"tags":["console","console"],"summary":"Verify Email Code","description":"Exchange a mailed code for a console session.","operationId":"verify_email_code_api_v1_console_email_code_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailCodeVerifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailCodeSignInResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The code is wrong, expired or already used."},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Email sign-in is unavailable (its store is unreachable)."},"429":{"description":"Too many requests for this address or from this network; see Retry-After."}}}},"/api/v1/console/session":{"post":{"tags":["console"],"summary":"Console Session","description":"Sign in: resolve the identity and report where it may work.\n\nA cloud identity that belongs nowhere and still has free allowance is given\none ordinary organization to own, so the console has something to select and\nthe first visit is not a dead end. Signing in still mints no key: the key the\nbrowser uses is short-lived and asked for separately, once an organization is\non screen. On-premise, and once the allowance is spent, zero organizations\nremains a normal answer and the console offers to create one.","operationId":"console_session_api_v1_console_session_post","responses":{"200":{"description":"Returning sign-in — nothing was written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleSessionResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Unverified email, identity not allowlisted, or account disabled."},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The identity is ambiguous, or an invitation was withdrawn while the join was in flight."},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"201":{"description":"First sign-in, an invitation was accepted into an organization, or the default organization was provisioned."}},"security":[{"HTTPBearer":[]}]}},"/api/v1/console/invitations/exchange":{"post":{"tags":["console"],"summary":"Exchange Invitation","description":"Exchange a live bearer invitation for a bounded first-party session.","operationId":"exchange_invitation_api_v1_console_invitations_exchange_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessInvitationExchangeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessInvitationExchangeResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The invitation cannot establish a session."},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/console/cli/device/{user_code}":{"get":{"tags":["console"],"summary":"Console Cli Device","description":"Confirm the code is a live pending session, for the approve page. Never the secret.","operationId":"console_cli_device_api_v1_console_cli_device__user_code__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_code","in":"path","required":true,"schema":{"type":"string","title":"User Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleDeviceSessionResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"Identity rejected or account disabled."},"404":{"description":"No console account yet — call POST /console/session first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/console/cli/device/{user_code}/approve":{"post":{"tags":["console"],"summary":"Console Cli Device Approve","description":"Mint the reserved ``ndi-mcp`` key for the named organization. The browser never sees it.","operationId":"console_cli_device_approve_api_v1_console_cli_device__user_code__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_code","in":"path","required":true,"schema":{"type":"string","title":"User Code"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveDeviceRequest"}}}},"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"Members may not authorize a CLI login."},"404":{"description":"No console account yet — call POST /console/session first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/console/cli/device/{user_code}/deny":{"post":{"tags":["console"],"summary":"Console Cli Device Deny","description":"Refuse the CLI login. The next token poll returns ``access_denied``.","operationId":"console_cli_device_deny_api_v1_console_cli_device__user_code__deny_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_code","in":"path","required":true,"schema":{"type":"string","title":"User Code"}}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"Identity rejected or account disabled."},"404":{"description":"No console account yet — call POST /console/session first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations":{"get":{"tags":["organization"],"summary":"List Organizations","description":"List every organization the caller belongs to, with their role in each.","operationId":"list_organizations_api_v1_organizations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationListResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["organization"],"summary":"Create Organization","description":"Create an organization with the caller as its owner.\n\nNo API key is minted: creating a tenant and handing out a credential are\nseparate decisions, and a key nobody asked for is a key nobody rotates.","operationId":"create_organization_api_v1_organizations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationInfo"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"The free organization allowance is used up."},"403":{"description":"This installation seeds its organizations with ndi-cli."},"404":{"description":"No console account yet — call POST /console/session first."},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/organizations/{organization_id}":{"patch":{"tags":["organization"],"summary":"Rename Organization","description":"Rename the organization as humans see it. Its storage slug never moves.","operationId":"rename_organization_api_v1_organizations__organization_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameOrganizationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/keys":{"get":{"tags":["organization"],"summary":"List Keys","description":"List the organization's keys (metadata only — secrets are unrecoverable).\n\nExpired keys are listed with ``status: \"expired\"`` so an owner can see why an\nintegration stopped working and replace the key; disabled ones with\n``status: \"disabled\"``.\n\nThe caller's own console session key is included with ``system: true``. Other\nmembers' console keys are not listed at all.","operationId":"list_keys_api_v1_organizations__organization_id__keys_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationKeyListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"post":{"tags":["organization"],"summary":"Create Key","description":"Mint a named key for the organization. The secret is returned exactly once.\n\nAny active member may call this. ``expires_at`` must be sent, explicitly\n``null`` for a key that never expires, so a key's lifetime is always a\nchoice somebody made.","operationId":"create_key_api_v1_organizations__organization_id__keys_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"description":"The requested expiration is not in the future."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/console-key":{"post":{"tags":["organization"],"summary":"Create Console Key","description":"Mint a short-lived data-plane key for the signed-in member.\n\nAny active member may call this. The secret is shown once. ``/v1`` stays\nAPI-key-only; this endpoint is how a console session obtains one.","operationId":"create_console_key_api_v1_organizations__organization_id__console_key_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleKeyResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/keys/{key_prefix}":{"delete":{"tags":["organization"],"summary":"Revoke Key","description":"Revoke one key. Other keys keep working, so this is the safe half of a rotation.","operationId":"revoke_key_api_v1_organizations__organization_id__keys__key_prefix__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No active key with that prefix in this organization."},"409":{"description":"The prefix names a console session key, which is system-managed."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"patch":{"tags":["organization"],"summary":"Set Key Disabled","description":"Suspend or resume one key — the reversible alternative to revoking it.\n\nA disabled key stops authenticating immediately but keeps its row, its\ngrants and its secret, so an integration that has started misbehaving can be\ncut off now and switched back on later without re-keying its callers.","operationId":"set_key_disabled_api_v1_organizations__organization_id__keys__key_prefix__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetKeyDisabledRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationKeyInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No active key with that prefix in this organization."},"409":{"description":"The prefix names a console session key, which is system-managed."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/usage":{"get":{"tags":["organization"],"summary":"Organization Usage","description":"The organization's resource allowance and finalized consumption.\n\nThe same numbers ``GET /api/v1/usage`` reports to an API-key caller, read here by\na human who need not hold a key.","operationId":"organization_usage_api_v1_organizations__organization_id__usage_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__UsageResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/access-labels":{"get":{"tags":["organization"],"summary":"List Access Labels","description":"List the organization's access-label catalog (for grant checkboxes without an API key).","operationId":"list_access_labels_api_v1_organizations__organization_id__access_labels_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationAccessLabelListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/workspaces":{"get":{"tags":["organization"],"summary":"List Labelled Workspaces","description":"List labelled workspaces so administrators can apply key grants without the /v1 plane.","operationId":"list_labelled_workspaces_api_v1_organizations__organization_id__workspaces_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationWorkspaceListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/keys/{key_prefix}/labels":{"put":{"tags":["organization"],"summary":"Set Key Labels","description":"Set the access labels this key holds across every labelled workspace.\n\nEach workspace grant becomes the intersection of ``body.labels`` and that\nworkspace's declared labels. Replaces prior grants on those workspaces.","operationId":"set_key_labels_api_v1_organizations__organization_id__keys__key_prefix__labels_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetKeyLabelsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetKeyLabelsResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No such key in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/keys/{key_prefix}/grants":{"get":{"tags":["organization"],"summary":"List Key Grants","description":"List every workspace grant for one key.","operationId":"list_key_grants_api_v1_organizations__organization_id__keys__key_prefix__grants_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyGrantsListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/keys/{key_prefix}/grants/{workspace_id}":{"get":{"tags":["organization"],"summary":"Get Key Grants","description":"Read the access labels this key may see in one workspace.\n\nAn empty list means the key has no grant (or an empty grant) and sees only\nunlabelled documents in a labelled workspace.","operationId":"get_key_grants_api_v1_organizations__organization_id__keys__key_prefix__grants__workspace_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace the labels apply in.","title":"Workspace Id"},"description":"Workspace the labels apply in."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantsResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No such key, or no such workspace in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"put":{"tags":["organization"],"summary":"Set Key Grants","description":"Set the access labels this key may see in one workspace.\n\nReplaces the whole grant, so revoking a label is the same call as granting\none. An empty list leaves the key seeing only unlabelled documents.","operationId":"set_key_grants_api_v1_organizations__organization_id__keys__key_prefix__grants__workspace_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_prefix","in":"path","required":true,"schema":{"type":"string","description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c.","title":"Key Prefix"},"description":"Key prefix from the key listing, e.g. ndi_sk_a1b2c."},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace the labels apply in.","title":"Workspace Id"},"description":"Workspace the labels apply in."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetGrantsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantsResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No such key, or no such workspace in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"description":"A label the workspace does not declare."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/members":{"get":{"tags":["organization"],"summary":"List Members","description":"List the organization's members. Readable by any member, not just administrators.","operationId":"list_members_api_v1_organizations__organization_id__members_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/members/{user_id}":{"patch":{"tags":["organization"],"summary":"Set Member Role","description":"Change a member's role. Only an owner may create or change another owner.","operationId":"set_member_role_api_v1_organizations__organization_id__members__user_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRoleRequest"}}}},"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"description":"Cannot demote the organization's only owner."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"delete":{"tags":["organization"],"summary":"Remove Member","description":"Remove a human from the organization.\n\nIntegration keys are organization property and stay live. Console-user keys\nattributed to the departing member are revoked.","operationId":"remove_member_api_v1_organizations__organization_id__members__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"description":"Cannot remove the organization's only owner."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/invitations":{"get":{"tags":["organization"],"summary":"List Invitations","description":"List invitations that have neither been accepted nor revoked (administrators only).","operationId":"list_invitations_api_v1_organizations__organization_id__invitations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"post":{"tags":["organization"],"summary":"Create Invitation","description":"Invite an email address to join the organization.\n\nThe address receives a seven-day passwordless link and may still join later\nthrough conventional OIDC sign-in. An address that belongs to another\norganization is fine — that is how a consultant works for two customers.\n\nThe row commits before the secret-bearing email is queued. Delivery failure\nnever rolls back the invitation.","operationId":"create_invitation_api_v1_organizations__organization_id__invitations_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"description":"Already a member here, or already invited here."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/invitations/{invitation_id}":{"delete":{"tags":["organization"],"summary":"Revoke Invitation","description":"Withdraw an invitation so its passwordless link can no longer mint sessions.","operationId":"revoke_invitation_api_v1_organizations__organization_id__invitations__invitation_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No live invitation with that id."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/run-views":{"get":{"tags":["organization"],"summary":"List Run Views","description":"Unviewed watches for the signed-in user in this organization.","operationId":"list_run_views_api_v1_organizations__organization_id__run_views_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunViewListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/organizations/{organization_id}/run-views/{run_key}":{"put":{"tags":["organization"],"summary":"Watch Run","description":"Start watching a run as unviewed. A later PUT does not un-view a seen run.","operationId":"watch_run_api_v1_organizations__organization_id__run_views__run_key__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_key","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"project_id when the workbench minted one, otherwise the job id.","title":"Run Key"},"description":"project_id when the workbench minted one, otherwise the job id."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunViewItem"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No live watchable run with that key in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}},"patch":{"tags":["organization"],"summary":"Mark Run Viewed","description":"Mark the run seen after the user opens its results.","operationId":"mark_run_viewed_api_v1_organizations__organization_id__run_views__run_key__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_key","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"project_id when the workbench minted one, otherwise the job id.","title":"Run Key"},"description":"project_id when the workbench minted one, otherwise the job id."},{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Organization from POST /console/session.","title":"Organization Id"},"description":"Organization from POST /console/session."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkRunViewedRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunViewItem"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"The account is disabled, or the caller's role does not permit this."},"404":{"description":"No console account yet, or no membership in this organization."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/files/download":{"get":{"tags":["downloads"],"summary":"Download File","description":"Serve one local-store object named by a verified download token.\n\n``token`` defaults to empty so a missing token takes the same 403 path\nas a bad one (presigned-URL parity), not FastAPI's 422.\n\n``file`` and ``content_manifest`` tokens are not checked for revocation, by\ndesign (CON-70): such a token is a bearer HMAC grant that names no key or\nclient, like the presigned S3 URLs it stands in for. Revoking a key or disabling a tenant or partner stops minting new\ntokens, but one already issued stays valid until it expires. Its TTL is the\nwhole bound on that exposure: ``JOB_DOWNLOAD_LINK_TTL_SECONDS`` (300s) for\njob links, ``DOWNLOAD_URL_TTL_SECONDS`` (900s) for ``get_file``, and\n``NDI_PRESIGN_TTL_SECONDS`` (3600s by default) for previews.\n\nCustomer workspace grants are the exception: each request rechecks the\ntenant and its parent, the binding, the connection and the granted object\nor document job, so revocation, replacement, deletion or expiry stops an\nissued link. Past the signature check those refusals are typed platform errors.","operationId":"download_file_api_v1_files_download_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/console/evals/perception-leaderboard":{"get":{"tags":["evals"],"summary":"Get Perception Leaderboard","description":"Every PR-versioned perception checkpoint, oldest first.","operationId":"get_perception_leaderboard_api_v1_console_evals_perception_leaderboard_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerceptionLeaderboard"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service Unavailable"}}}},"/api/v1/console/evals/samples":{"get":{"tags":["evals"],"summary":"List Eval Samples","description":"The packaged eval samples a run can select from.\n\nEach entry says whether it can actually run here: a sample that attaches a\nprepared corpus workspace nobody has provisioned is listed as blocked rather\nthan offered and then failed.","operationId":"list_eval_samples_api_v1_console_evals_samples_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalSampleListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/api/v1/console/evals/runs":{"post":{"tags":["evals"],"summary":"Create Eval Run","description":"Start a run over the selected samples. Poll the run for progress.","operationId":"create_eval_run_api_v1_console_evals_runs_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEvalRunRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalRun"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}},"get":{"tags":["evals"],"summary":"List Eval Runs","description":"Every operator's runs, newest first.","operationId":"list_eval_runs_api_v1_console_evals_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`next_cursor` from the previous page.","title":"Cursor"},"description":"`next_cursor` from the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalRunListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/api/v1/console/evals/runs/{eval_run_id}":{"get":{"tags":["evals"],"summary":"Get Eval Run","description":"Fetch one run's status and totals.","operationId":"get_eval_run_api_v1_console_evals_runs__eval_run_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"eval_run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Eval Run Id"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalRun"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/api/v1/console/evals/runs/{eval_run_id}/results":{"get":{"tags":["evals"],"summary":"List Eval Run Results","description":"Per-sample verdicts written so far. Present while the run is still going.","operationId":"list_eval_run_results_api_v1_console_evals_runs__eval_run_id__results_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"eval_run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Eval Run Id"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalSampleResultListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/api/v1/console/evals/runs/{eval_run_id}/results/{sample_id}/rollouts":{"get":{"tags":["evals"],"summary":"Get Eval Sample Rollouts","description":"The raw rollouts behind one sample's metrics.\n\nSeparate from the results list because a rollout carries whole answers,\nevidences, and tool calls — nobody wants them for every sample at once.","operationId":"get_eval_sample_rollouts_api_v1_console_evals_runs__eval_run_id__results__sample_id__rollouts_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"eval_run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Eval Run Id"}},{"name":"sample_id","in":"path","required":true,"schema":{"type":"string","title":"Sample Id"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalRolloutsResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/api/v1/console/evals/prepared-workspaces":{"get":{"tags":["evals"],"summary":"List Prepared Workspaces","description":"Corpus workspaces samples attach to, and the ones still missing.\n\nIn the CLI this registry is a gitignored file on one laptop. Here it is a\ntable, so every eval worker and the console agree on which corpora exist.","operationId":"list_prepared_workspaces_api_v1_console_evals_prepared_workspaces_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvalPreparedWorkspaceListResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}},"post":{"tags":["evals"],"summary":"Provision Prepared Workspace","description":"Provision one corpus workspace: fetch, upload, ingest, record.\n\nAccepted, not finished — ingesting a corpus takes minutes to hours. Poll the\nprepared-workspace list; the name appears when it is usable.","operationId":"provision_prepared_workspace_api_v1_console_evals_prepared_workspaces_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionEvalWorkspaceRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionEvalWorkspaceResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"description":"Missing or invalid bearer token."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"403":{"description":"An API key was sent, the account is not Nace staff, or it is disabled."},"404":{"description":"No console account for this identity — sign in first."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Internal Server Error"},"503":{"description":"The eval harness or its worker queue is not available on this deployment."}}}},"/v1/domains":{"get":{"tags":["domains"],"summary":"list_domains","description":"List every domain visible to the caller. Cost class: cacheable.\n\nReturns the platform-owned domains (``generic`` and the curated verticals,\nall published and selectable) and the calling tenant's own rows.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    owner: Restrict to ``platform`` or ``tenant`` rows.\n    status: Restrict to ``draft`` or ``published`` rows.\n    cursor: Opaque cursor from a previous page.\n    limit: Rows per page.\n\nReturns:\n    One page of domain summaries with an exact total.","operationId":"list_domains_v1_domains_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"anyOf":[{"enum":["platform","tenant"],"type":"string"},{"type":"null"}],"description":"Filter by ownership: `platform` (standard) or `tenant` (yours).","title":"Owner"},"description":"Filter by ownership: `platform` (standard) or `tenant` (yours)."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["draft","published"],"type":"string"},{"type":"null"}],"description":"Filter by lifecycle status.","title":"Status"},"description":"Filter by lifecycle status."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_DomainSummary_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"post":{"tags":["domains"],"summary":"create_domain","description":"Create a tenant-owned draft. Cost class: fast.\n\nThe draft is editable and **unusable** until published. Validation runs on\nevery write and is returned every time, so a caller never has to guess\nwhether a publish will succeed.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant, who will own the new domain.\n    request: The slug, display name, and taxonomy.\n\nReturns:\n    The created draft and its validation.\n\nRaises:\n    PlatformError: ``reserved_domain_slug`` or ``domain_in_use``.","operationId":"create_domain_v1_domains_post","security":[{"APIKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/domains/{domain_id}":{"get":{"tags":["domains"],"summary":"get_domain","description":"Read one domain version, with inheritance already resolved. Cost class: cacheable.\n\nA caller reading a domain wants the vocabulary that will actually be applied,\nnot a delta they have to merge themselves.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    domain_id: The domain version to read.\n\nReturns:\n    The domain and its effective taxonomy.\n\nRaises:\n    PlatformError: ``domain_not_found`` when it does not exist or belongs to\n        another tenant.","operationId":"get_domain_v1_domains__domain_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"domain_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Domain version identifier.","title":"Domain Id"},"description":"Domain version identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"patch":{"tags":["domains"],"summary":"update_domain","description":"Edit a draft, or spin a published version into the next draft. Cost class: fast.\n\nEditing a ``draft`` mutates it. Editing a ``published`` domain creates version\n*n+1* and leaves version *n* untouched. Existing workspaces remain pinned to\nthe version selected at creation; the new version is available only to future\nworkspaces.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    request: Any subset of the create request.\n    domain_id: The domain version to edit.\n\nReturns:\n    The resulting draft (which may be a new version) and its validation.\n\nRaises:\n    PlatformError: ``domain_not_found``, or ``access_denied`` for a\n        platform-owned row.","operationId":"update_domain_v1_domains__domain_id__patch","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"domain_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Domain version identifier.","title":"Domain Id"},"description":"Domain version identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDomainRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/domains/generate":{"post":{"tags":["domains"],"summary":"generate_domain","description":"Draft a taxonomy from a description or Parse job. Cost class: slow.\n\nSynchronous and **non-persisting**: the model proposes a taxonomy the author\nedits, then posts to ``POST /v1/domains``. Nothing is written to the\ndatabase and no job is created. Kept off MCP because authoring is a reviewed\nhuman act, not an agent-loop step.\n\nArgs:\n    session: Database session used only to resolve a caller-owned Parse job.\n    caller: The authenticated tenant (authorization only — no domain row is owned yet).\n    request: The description or Parse-result source and optional identity hints.\n\nReturns:\n    Normalized taxonomy, suggested identity fields, and publish-gate validation\n    for the draft.\n\nRaises:\n    PlatformError: ``upstream_unavailable`` when the model call fails, or\n        ``job_timeout`` when it times out (both retryable).","operationId":"generate_domain_v1_domains_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDomainRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDomainResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"504":{"description":"Gateway Timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/domains/suggest-description":{"post":{"tags":["domains"],"summary":"suggest_domain_description","description":"Draft a classifier-facing description from a domain name. Cost class: slow.\n\nSynchronous and **non-persisting**. The console uses this to prefill the\nGenerate tab. An unrecognized name returns an empty description rather than\nan error so the author can type their own. Kept off MCP because authoring\nis a reviewed human act, not an agent-loop step.\n\nArgs:\n    caller: The authenticated tenant (authorization only).\n    request: The domain display name to describe.\n\nReturns:\n    A suggested description, or an empty string when the name is unusable.\n\nRaises:\n    PlatformError: ``upstream_unavailable`` when the model call fails, or\n        ``job_timeout`` when it times out (both retryable).","operationId":"suggest_domain_description_v1_domains_suggest_description_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestDomainDescriptionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestDomainDescriptionResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"504":{"description":"Gateway Timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/domains/{domain_id}/publish":{"post":{"tags":["domains"],"summary":"publish_domain","description":"Freeze a draft version and make it selectable by workspaces. Cost class: fast.\n\nThe gate rejects empty or oversized taxonomies, duplicate\n``group/subgroup`` paths, and attempts to redefine ``other``.\n\nThere is no delete route — a workspace whose domain vanished could not\nexplain its own categories. Move workspaces to a newer version instead.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    domain_id: The draft to publish.\n\nReturns:\n    The published domain and its validation.\n\nRaises:\n    PlatformError: ``domain_validation_failed`` carrying the validation list\n        in ``detail``, ``domain_not_found``, or ``access_denied``.","operationId":"publish_domain_v1_domains__domain_id__publish_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"domain_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Domain version identifier.","title":"Domain Id"},"description":"Domain version identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/access-labels":{"get":{"tags":["access-labels"],"summary":"list_access_labels","description":"List the caller's reusable access labels. Cost class: cacheable.","operationId":"list_access_labels_v1_access_labels_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AccessLabelCatalogEntry_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"post":{"tags":["access-labels"],"summary":"create_access_label","description":"Add a label to the tenant catalog.","operationId":"create_access_label_v1_access_labels_post","security":[{"APIKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccessLabelRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessLabelCatalogEntry"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/access-labels/{access_label_id}":{"get":{"tags":["access-labels"],"summary":"get_access_label","description":"Fetch one catalog label.","operationId":"get_access_label_v1_access_labels__access_label_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"access_label_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Access Label Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessLabelCatalogEntry"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"patch":{"tags":["access-labels"],"summary":"update_access_label","description":"Update a catalog label's description.","operationId":"update_access_label_v1_access_labels__access_label_id__patch","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"access_label_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Access Label Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAccessLabelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessLabelCatalogEntry"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["access-labels"],"summary":"delete_access_label","description":"Delete a catalog label. Refused with 409 when any workspace, grant, or file still uses the name.","operationId":"delete_access_label_v1_access_labels__access_label_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"access_label_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Access Label Id"}}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extraction-schemas":{"get":{"tags":["extraction-schemas"],"summary":"list_extraction_schemas","description":"List the latest version of every schema family visible to the caller.\n\nCost class: cacheable. Tenant schemas and platform schemas are both listed;\nwhen both share a ``schema_id``, the tenant row wins.","operationId":"list_extraction_schemas_v1_extraction_schemas_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ExtractionSchemaSummary_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"post":{"tags":["extraction-schemas"],"summary":"create_extraction_schema","description":"Create version 1 of a new tenant-owned schema family with a generated ``sch_...`` id.","operationId":"create_extraction_schema_v1_extraction_schemas_post","security":[{"APIKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExtractionSchemaRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionSchema"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extraction-schemas/{schema_id}":{"get":{"tags":["extraction-schemas"],"summary":"get_extraction_schema","description":"Return the latest visible version of a schema family.","operationId":"get_extraction_schema_v1_extraction_schemas__schema_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"schema_id","in":"path","required":true,"schema":{"type":"string","description":"Stable schema family id (``sch_...``).","title":"Schema Id"},"description":"Stable schema family id (``sch_...``)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionSchema"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["extraction-schemas"],"summary":"delete_extraction_schema","description":"Delete a schema family you created, with every version. Cost class: fast.\n\nThe family stops listing and resolving at once: ``GET`` answers 404, and an\nExtract naming it fails ``schema_not_found``. Jobs accepted before the delete\nkeep the copy of the schema they took at accept time and finish normally;\ntheir results still name the ``schema_id`` and ``schema_version`` they used.\nDeleting a family that is already deleted succeeds again. Platform schemas,\nand another tenant's or another external account's, answer 404.","operationId":"delete_extraction_schema_v1_extraction_schemas__schema_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"schema_id","in":"path","required":true,"schema":{"type":"string","description":"Stable schema family id (``sch_...``).","title":"Schema Id"},"description":"Stable schema family id (``sch_...``)."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extraction-schemas/{schema_id}/versions":{"get":{"tags":["extraction-schemas"],"summary":"list_extraction_schema_versions","description":"Page the immutable version history of one visible schema family.","operationId":"list_extraction_schema_versions_v1_extraction_schemas__schema_id__versions_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"schema_id","in":"path","required":true,"schema":{"type":"string","description":"Stable schema family id (``sch_...``).","title":"Schema Id"},"description":"Stable schema family id (``sch_...``)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ExtractionSchema_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"post":{"tags":["extraction-schemas"],"summary":"create_extraction_schema_version","description":"Validate and append the next immutable integer version of a tenant-owned family.","operationId":"create_extraction_schema_version_v1_extraction_schemas__schema_id__versions_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"schema_id","in":"path","required":true,"schema":{"type":"string","description":"Stable schema family id (``sch_...``).","title":"Schema Id"},"description":"Stable schema family id (``sch_...``)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExtractionSchemaVersionRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionSchema"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extraction-schemas/{schema_id}/versions/{version}":{"get":{"tags":["extraction-schemas"],"summary":"get_extraction_schema_version","description":"Return one immutable version of a visible schema family.","operationId":"get_extraction_schema_version_v1_extraction_schemas__schema_id__versions__version__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"schema_id","in":"path","required":true,"schema":{"type":"string","description":"Stable schema family id (``sch_...``).","title":"Schema Id"},"description":"Stable schema family id (``sch_...``)."},{"name":"version","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Immutable integer version within the family.","title":"Version"},"description":"Immutable integer version within the family."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionSchema"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces":{"post":{"tags":["workspaces"],"summary":"create_workspace","description":"Provision a new workspace. Cost class: fast.\n\nEvery field has a sensible default so a caller who knows nothing creates a\nworking workspace with just a name. The workspace is immediately usable for\ningestion after this call; no activation step is needed.\n\nRetry with the same Idempotency-Key and body after an interrupted response.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant who will own the workspace.\n    request: Creation parameters.\n\nReturns:\n    The created workspace with a ``201`` status.\n\nRaises:\n    PlatformError: ``domain_not_found`` or ``domain_not_published``.","operationId":"create_workspace_v1_workspaces_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"get":{"tags":["workspaces"],"summary":"list_workspaces","description":"Page through the caller's workspaces, oldest-first. Cost class: fast.\n\nKeyset-paginated on ``(created_at, id)``; the cursor is opaque.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    name_contains: Substring filter on the workspace name.\n    cursor: Opaque cursor from a previous page's ``next_cursor``.\n    limit: Rows per page.\n\nReturns:\n    One page of workspaces with an exact total.","operationId":"list_workspaces_v1_workspaces_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"name_contains","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive name filter.","title":"Name Contains"},"description":"Case-insensitive name filter."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_Workspace_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}":{"get":{"tags":["workspaces"],"summary":"get_workspace","description":"Read one workspace. Cost class: fast.\n\nArgs:\n    context: Resolved workspace plus caller access predicate.\n    session: Database session.\n\nReturns:\n    The workspace.\n\nRaises:\n    PlatformError: ``workspace_not_found``.","operationId":"get_workspace_v1_workspaces__workspace_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"patch":{"tags":["workspaces"],"summary":"update_workspace","description":"Change a workspace's mutable configuration. Cost class: fast.\n\nPresence-aware, and whole-block: an omitted field is left alone, a supplied\none replaces its block entirely. Read the workspace, edit the block, send it\nback — partial blocks fall back to the schema defaults, which is how a caller\nflipping ``auto_build`` would otherwise wipe its own exclusion rules.\n\nGraph builds are explicit by default: a build happens when\n``POST /v1/workspaces/{id}/knowledge-graph/builds`` asks for one. Turning\n``knowledge_graph.auto_build`` on hands that trigger to ingestion instead, for\na workspace that wants a graph over everything it ingests and accepts the bill\nfor one per ingestion. Either way a build already in flight is unaffected —\ncancel it if that is what you meant.\n\n``currency`` follows the same whole-block rule, so ``{}`` is how its policy is\ncleared. Setting ``currency.default`` changes how the *next* ingestion reads\namounts marked with a symbol that names several currencies ($, ¥, kr);\namounts already extracted as ambiguous stay that way until their file is\nre-ingested, because the catalog records what a past extraction could read.\n\nOrdinary workspace names are mutable without changing identity or storage;\nplatform-provisioned workspace names remain fixed.\nThe domain and label list are deliberately not mutable here. They are part of the versioned config record stamped\nonto every derived artifact, so editing them in place would re-describe\nmaterial that was derived under the old one.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    request: The name and/or blocks to replace.\n\nReturns:\n    The workspace as it now stands.\n\nRaises:\n    PlatformError: ``workspace_not_found``, ``workspace_deleting`` when a\n        teardown is in flight; ``workspace_name_taken`` for an occupied name,\n        ``invalid_request`` for a system-workspace rename, ``access_denied``\n        when a shared member attempts a rename.","operationId":"update_workspace_v1_workspaces__workspace_id__patch","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["workspaces"],"summary":"delete_workspace","description":"Permanently delete a workspace and all of its content. Cost class: job.\n\nThis is an irreversible, tenant-wide destructive action.\n\n``confirm_name`` must equal the workspace's name exactly; this is a\ndeliberate friction point, not a formality. The teardown (storage prefix,\nsearch index, graph nodes) runs asynchronously; poll the returned job.\n\n**Not exposed over MCP.** An irreversible tenant-wide deletion does not\nbelong in a model's action space. Surface suppression is a per-method\nregistry flag on the MCP descriptor, not a special case at this layer.\n\nArgs:\n    session: Database session.\n    context: Resolved workspace plus caller access predicate.\n    request: Must carry ``confirm_name`` equal to the workspace name.\n    response: Response object; status is set to 202.\n    idempotency_key: Optional replay key.\n    wait_seconds: Bounded inline wait (rarely useful for a deletion).\n\nReturns:\n    Nothing; the accepted job is written directly to the response body by\n    ``start_job`` setting the appropriate status code.\n\nRaises:\n    PlatformError: ``workspace_deleting`` when a teardown job is still\n        queued or running, or ``invalid_request`` when the confirmation\n        name does not match.","operationId":"delete_workspace_v1_workspaces__workspace_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteWorkspaceRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceDeleteJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/shares":{"get":{"tags":["workspaces"],"summary":"get_workspace_shares","description":"Return the workspace owner and every explicitly shared user.","operationId":"get_workspace_shares_v1_workspaces__workspace_id__shares_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceShares"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"put":{"tags":["workspaces"],"summary":"replace_workspace_shares","description":"Replace the complete explicit share set in one atomic write.","operationId":"replace_workspace_shares_v1_workspaces__workspace_id__shares_put","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceWorkspaceSharesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceShares"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/stats":{"get":{"tags":["workspaces"],"summary":"get_workspace_stats","description":"Compute workspace content statistics. Cost class: fast.\n\nReturns file counts, byte totals, ingestion timestamps, and expiry\ninformation — enough for a caller to determine whether the workspace needs\ningestion or a re-ingest without paging through ``list_files``.\n\n``kg_nodes`` / ``kg_edges`` describe the workspace's published knowledge\ngraph, and are zero until a build has finished one. They come from the\nbuild's own record rather than the graph itself, so this stays a fast read;\nan unreachable graph store reports zero rather than failing the request.\n\nArgs:\n    session: Database session.\n    context: Resolved workspace plus caller access predicate.\n\nReturns:\n    The stats bag.","operationId":"get_workspace_stats_v1_workspaces__workspace_id__stats_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceStats"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files":{"post":{"tags":["files"],"summary":"upload_file","description":"Upload a source file into the workspace. Cost class: **job**.\n\nThe one route with two credentials: the tenant's ``X-API-Key``, or a\nshort-lived ``X-Upload-Token`` grant minted by ``create_upload_grant`` —\nwhich is how a customer's end client uploads directly without ever\nholding the key. A grant redeems the multipart path only, within the\nconstraints frozen into it (workspace, optional pinned path, byte cap).\n\nTwo content paths, per the ``UploadFileRequest`` contract:\n\n* ``multipart/form-data`` — file bytes in a ``file`` part, request\n  parameters as a JSON string in a ``metadata`` form field.\n* ``application/json`` — an ``UploadFileRequest`` body whose ``source``\n  carries a ``UrlSource``; the bytes are fetched server-side and then\n  take the exact same storage/ledger path as multipart.\n\n**Upload does NOT ingest.**  The file lands with\n``ingestion_status = discovered`` and is not searchable.  Making it\nsearchable requires a separate ``POST .../ingestions`` call.  This keeps\nthe cost model honest: a caller can upload a thousand files and choose to\ningest fifty.\n\nArgs:\n    upload_auth: The resolved workspace context, plus the upload grant\n        when the caller redeemed one instead of sending an API key.\n    session: Database session.\n    request: The raw request, for the JSON (URL-source) content path.\n    file: The file bytes, as an ``UploadFile`` from the multipart body.\n    metadata: JSON-encoded ``UploadFileRequest`` from the multipart body.\n    wait_seconds: Accepted for uniformity; the work is already done.\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A ``succeeded`` ``Job`` whose result is an ``UploadFileResult``.\n\nRaises:\n    PlatformError: ``invalid_request`` when the body is malformed, the\n        metadata JSON is invalid, or a URL source is refused or answers\n        with an error status.\n    PlatformError: ``path_conflict`` when ``on_conflict=\"reject\"`` and a\n        different file already occupies the destination path.\n    PlatformError: ``file_too_large`` when the upload exceeds\n        ``NDI_MAX_UPLOAD_BYTES`` or the grant's tighter ``max_bytes``.\n        Larger tabular files must use ``POST .../upload-sessions``.\n    PlatformError: ``access_denied`` when an upload grant is redeemed\n        outside its constraints (URL source, or a pinned-path mismatch).\n    PlatformError: ``unauthorized`` when a single-use grant is replayed.","operationId":"upload_file_v1_workspaces__workspace_id__files_post","security":[{"APIKeyHeader":[]},{"UploadGrantHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_v1_workspaces__workspace_id__files_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadFileJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"get":{"tags":["files"],"summary":"list_files","description":"List source files with exact totals and access-filtered coverage.\n\nCost class: **fast** (structured-metadata predicates only; no index lookup).\n\nThe sanctioned completeness instrument: ``total_count`` is exact and\naccess-filtered; ``coverage`` says how many candidates the access gate\nwithheld and which labels would have been needed.  A caller that cannot\nreconcile ``total_count`` with their own ledger knows the gap is\nlabelled content rather than a missing file.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    path_prefix: Only files whose path starts with this string.\n    ingestion_status: Restrict to these ingestion statuses.\n    categories: Restrict to these categories.\n    file_types: Restrict to these file extensions (e.g. ``[\"pdf\", \"xlsx\"]``).\n    modified_after: Only files updated after this timestamp.\n    modified_before: Only files updated before this timestamp.\n    cursor: Opaque keyset cursor from the previous page's ``next_cursor``.\n    limit: Rows per page.\n\nReturns:\n    ``FileListPage`` with items, paging metadata, and access coverage.","operationId":"list_files_v1_workspaces__workspace_id__files_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"path_prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Restrict to paths starting with this prefix.","title":"Path Prefix"},"description":"Restrict to paths starting with this prefix."},{"name":"ingestion_status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/IngestionStatus"}},{"type":"null"}],"description":"Restrict to these ingestion statuses.","title":"Ingestion Status"},"description":"Restrict to these ingestion statuses."},{"name":"categories","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Restrict to these categories.","title":"Categories"},"description":"Restrict to these categories."},{"name":"file_types","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Restrict to these file extensions.","title":"File Types"},"description":"Restrict to these file extensions."},{"name":"modified_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only files updated after this timestamp.","title":"Modified After"},"description":"Only files updated after this timestamp."},{"name":"modified_before","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only files updated before this timestamp.","title":"Modified Before"},"description":"Only files updated before this timestamp."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileListPage"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/upload-grants":{"post":{"tags":["files"],"summary":"create_upload_grant","description":"Mint a short-lived grant an end client redeems to upload directly. Cost class: **fast**.\n\nThe customer's backend holds the API key; the end user's browser must\nnever see it. This mints an HMAC-signed token that authorizes exactly one\nthing — ``upload_file`` into this workspace, optionally pinned to one\ndestination path and a byte cap — until ``expires_at``. The holder sends\nit in the ``X-Upload-Token`` header of a multipart ``POST`` to\n``upload_url``, so the bytes travel end-client → NDI once instead of\nend-client → customer → NDI twice.\n\nThe grant is stateless (no DB row); its short TTL stands in for\nrevocation, except that revoking the minting API key kills its\noutstanding grants immediately. Where the deployment runs Redis the grant\nis additionally single-use.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    body: Optional path pin, byte cap, and TTL.\n\nReturns:\n    ``UploadGrantResponse`` with the token, the upload URL, and expiry.\n\nRaises:\n    PlatformError: ``invalid_request`` when ``max_bytes`` exceeds the\n        service-wide upload cap.","operationId":"create_upload_grant_v1_workspaces__workspace_id__upload_grants_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadGrantRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadGrantResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files/{file_id}":{"get":{"tags":["files"],"summary":"get_file","description":"Return a file plus a short-lived presigned download URL. Cost class: **fast**.\n\nNo separate ``GET .../content`` route: the presigned URL keeps raw bytes\noff the API path.  The URL expires after ``DOWNLOAD_URL_TTL_SECONDS``\nseconds; fetch it promptly.\n\nA direct read of a named file is the one case where hard denial\n(``403 access_denied``) is correct: the caller named the file, so there\nis nothing to narrow and nothing to infer — they already knew it existed.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The file to fetch.\n\nReturns:\n    ``FileDetail`` including the presigned ``download_url``.\n\nRaises:\n    PlatformError: ``file_not_found`` when the file does not exist.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"get_file_v1_workspaces__workspace_id__files__file_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileDetail"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"put":{"tags":["files"],"summary":"replace_file","description":"Replace a file's content atomically. Cost class: **job**.\n\nThe replacement is atomic from a reader's perspective: the old version is\nstamped ``replaced_at`` and the new version is live in the same commit.\n\nRe-ingests only if the file was ingested before (``ingestion_status``\nbecomes ``stale``); a never-ingested file returns to ``discovered``.\nThe actual cascade (retiring outputs, queuing re-ingestion) is the\n``dispatch`` seam in the job service.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The file to replace.\n    file: The replacement file bytes.\n    metadata: JSON-encoded ``ReplaceFileRequest`` from the multipart body.\n    wait_seconds: Accepted for uniformity; the row write is already done.\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A ``succeeded`` ``Job`` whose result is a ``ReplaceFileResult``.\n\nRaises:\n    PlatformError: ``file_not_found`` when the file does not exist.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.\n    PlatformError: ``file_too_large`` when the upload exceeds\n        ``NDI_MAX_UPLOAD_BYTES``.","operationId":"replace_file_v1_workspaces__workspace_id__files__file_id__put","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_replace_file_v1_workspaces__workspace_id__files__file_id__put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceFileJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["files"],"summary":"delete_file","description":"Soft-delete a file and run the cross-representation cascade as a job.\n\nThe file is soft-deleted (``deleted_at`` stamped) so lineage questions\nstay answerable after the cascade.  The cascade job then retires index\ndocuments and output rows, drops the sibling folder from storage, cancels\nin-flight ingestion jobs that name the file, and independently re-checks\nevery representation.  ``DeleteFileResult.counts`` exist so this is\nauditable rather than assumed, and ``verified: false`` is a failed cascade\nthat must alert.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The file to delete.\n    wait_seconds: Bounded inline wait.\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n    temporal: Temporal client, which runs the cascade workflow.\n\nReturns:\n    A ``Job`` whose result, once succeeded, is a ``DeleteFileResult``\n    with per-representation counts and a ``verified`` flag.\n\nRaises:\n    PlatformError: ``file_not_found`` when the file does not exist.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"delete_file_v1_workspaces__workspace_id__files__file_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteFileJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files/{file_id}/metadata":{"get":{"tags":["files"],"summary":"get_file_metadata","description":"Return ingestion-derived metadata for a file. Cost class: **fast**.\n\n``representations`` answers \"is this file actually searchable right now\",\nwhich ``ingestion_status`` alone cannot: a file can be ingested while its\ngraph generation is still building.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The file to inspect.\n\nReturns:\n    ``FileMetadata`` with outputs, representation state, and ingestion\n    metadata (mostly empty until the ingestion pipeline writes them).\n\nRaises:\n    PlatformError: ``file_not_found`` when the file does not exist.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"get_file_metadata_v1_workspaces__workspace_id__files__file_id__metadata_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMetadata"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files/{file_id}/outputs/{output_id}":{"get":{"tags":["files"],"summary":"get_file_output","description":"Return a live derived-file output plus short-lived download URLs. Cost class: **fast**.\n\nOnly ``derived_file`` outputs live as objects in the workspace store.\nSearch-index and knowledge-graph outputs carry opaque keys and cannot be\nfetched this way.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The source file that owns the output.\n    output_id: The output to fetch.\n\nReturns:\n    ``ArtifactOutputDetail`` including ``download_url`` and ``preview_url``.\n\nRaises:\n    PlatformError: ``file_not_found`` when the source file or output is gone.\n    PlatformError: ``invalid_request`` when the output is not a ``derived_file``.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"get_file_output_v1_workspaces__workspace_id__files__file_id__outputs__output_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"output_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Output Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOutputDetail"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files/{file_id}/outputs/{output_id}/members":{"get":{"tags":["files"],"summary":"list_output_members","description":"List the objects inside a derived-output folder, each presigned inline. Cost class: **fast**.\n\nA recording's ``frames/`` folder is registered as a single ``derived_file``\noutput, not one row per frame, so this browses the folder straight from\nstorage. A leaf output (a single markdown/json file) has no members and\nreturns an empty page.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The source file that owns the output.\n    output_id: The derived-file output whose folder is listed.\n    offset: Members to skip.\n    limit: Maximum members to return in this page.\n\nReturns:\n    ``ArtifactOutputMembersPage`` — this page plus the folder's total count.\n\nRaises:\n    PlatformError: ``file_not_found`` when the source file or output is gone.\n    PlatformError: ``invalid_request`` when the output is not a ``derived_file``.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"list_output_members_v1_workspaces__workspace_id__files__file_id__outputs__output_id__members_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"output_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Output Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Members to skip, for paging a large folder.","default":0,"title":"Offset"},"description":"Members to skip, for paging a large folder."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactOutputMembersPage"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/files/{file_id}/versions":{"get":{"tags":["files"],"summary":"get_file_versions","description":"Return a newest-first page of version history for a file. Cost class: **fast**.\n\nMetadata only — bytes from superseded versions are not retained by\ndefault (customer opt-in).  ``is_current`` is ``true`` only on the latest\nversion.\n\nArgs:\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    file_id: The file whose history to page through.\n    cursor: Opaque keyset cursor from the previous page.\n    limit: Rows per page.\n\nReturns:\n    ``Page[FileVersion]`` with version metadata, newest first.\n\nRaises:\n    PlatformError: ``file_not_found`` when the file does not exist.\n    PlatformError: ``access_denied`` when the caller does not hold the\n        required access label.","operationId":"get_file_versions_v1_workspaces__workspace_id__files__file_id__versions_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"File Id"}},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_FileVersion_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/upload-sessions":{"post":{"tags":["files"],"summary":"create_upload_session","description":"Open a chunked upload for a large file. Cost class: **fast**.\n\nSame auth as ``upload_file`` — an ``X-API-Key`` or a short-lived\n``X-Upload-Token`` grant — but redeemed exactly once, here. Every later\nrequest against the session (parts, status, complete, abort) presents\nthe ``session_token`` this returns instead, in the same ``X-Upload-Token``\nheader.\n\nUpload every part with ``PUT .../upload-sessions/{session_id}/parts/{n}``\nat exactly ``chunk_size`` bytes (the final part may be shorter), then\ncall ``POST .../complete``. ``GET`` the session at any point to see which\nparts have already landed, e.g. after a dropped connection.\n\nArgs:\n    session: Database session.\n    body: Destination path, declared total size, and conflict policy —\n        the same fields ``upload_file`` takes, minus the bytes.\n    upload_auth: The resolved workspace context, plus the upload grant\n        when the caller redeemed one instead of sending an API key.\n    idempotency_key: Replaying with the same key returns the original\n        session rather than opening a second one.\n\nReturns:\n    A :class:`CreateUploadSessionResponse` with the session token.\n\nRaises:\n    PlatformError: ``file_too_large`` when ``total_size_bytes`` exceeds\n        the effective byte cap.\n    PlatformError: ``access_denied`` when a path-pinned grant is used to\n        create a session at a different path.\n    PlatformError: ``unauthorized`` when a single-use grant is replayed.","operationId":"create_upload_session_v1_workspaces__workspace_id__upload_sessions_post","security":[{"APIKeyHeader":[]},{"UploadGrantHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadSessionRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadSessionResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/upload-sessions/{session_id}/parts/{part_number}":{"put":{"tags":["files"],"summary":"upload_session_part","description":"Upload one part of a chunked upload. Cost class: **fast**.\n\nExempt from the tenant's per-minute rate limit (unlike every other\nupload-session route): a multi-GB file at ``chunk_size`` is already\ndozens of requests, and each part is bounded and byte-for-byte\nrevalidated at ``complete`` anyway, so RPM protection would only add\nfriction here without protecting anything.\n\nIdempotent: re-PUTing the same ``part_number`` overwrites it, so a\nretried part after a dropped connection is always safe.\n\nArgs:\n    request: The raw request; the part's bytes are its whole body.\n    part_number: Which part this is, 0-based.\n    auth: The resolved session context and row.\n\nReturns:\n    An :class:`UploadSessionPartResponse` confirming the bytes received.\n\nRaises:\n    PlatformError: ``session_busy`` while a ``complete`` is in flight.\n    PlatformError: ``upload_expired`` once completed, aborted, or past\n        its TTL.\n    PlatformError: ``invalid_request`` when ``part_number`` is out of\n        range for this session's declared size.\n    PlatformError: ``file_too_large`` when the body exceeds ``chunk_size``.","operationId":"upload_session_part_v1_workspaces__workspace_id__upload_sessions__session_id__parts__part_number__put","security":[{"UploadSessionTokenHeader":[]}],"parameters":[{"name":"part_number","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"0-based part index.","title":"Part Number"},"description":"0-based part index."},{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Upload session identifier.","title":"Session Id"},"description":"Upload session identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionPartResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/upload-sessions/{session_id}":{"get":{"tags":["files"],"summary":"get_upload_session","description":"Read a chunked upload's lifecycle state and landed parts. Cost class: **fast**.\n\nThe resume entry point: after a dropped connection (or a page reload),\ndiff ``parts`` against what was already sent and PUT only what is\nmissing — never re-derive part numbers, and never resend a part that\nalready landed.\n\nArgs:\n    auth: The resolved session context and row.\n\nReturns:\n    An :class:`UploadSessionStatusResponse`.","operationId":"get_upload_session_v1_workspaces__workspace_id__upload_sessions__session_id__get","security":[{"UploadSessionTokenHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Upload session identifier.","title":"Session Id"},"description":"Upload session identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionStatusResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["files"],"summary":"abort_upload_session","description":"Abort a chunked upload and reclaim its staged parts. Cost class: **fast**.\n\nIdempotent: a session that already completed or was already aborted\nanswers 204 without touching anything — this only ever removes staged\n*parts*, never a landed artifact.\n\nArgs:\n    session: Database session.\n    auth: The resolved session context and row.","operationId":"abort_upload_session_v1_workspaces__workspace_id__upload_sessions__session_id__delete","security":[{"UploadSessionTokenHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Upload session identifier.","title":"Session Id"},"description":"Upload session identifier."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/upload-sessions/{session_id}/complete":{"post":{"tags":["files"],"summary":"complete_upload_session","description":"Concatenate every part and write the ledger row. Cost class: **job**.\n\nRejects unless the landed parts exactly cover ``[0, total_parts)`` at\ntheir exact expected sizes — nothing about completeness is trusted on\nthe client's word. The concatenation itself runs as a job, never inline:\nthe artifact only becomes visible once it commits, exactly as\n``upload_file`` — a caller polling this job's ``status`` sees the same\ncontract either way.\n\nArgs:\n    session: Database session.\n    response: Injected by FastAPI for status-code management.\n    temporal: Temporal client, which runs the completion workflow.\n    auth: The resolved session context and row.\n    wait_seconds: Bounded inline wait.\n    idempotency_key: Replaying with the same key returns the original job.\n\nReturns:\n    A ``Job`` whose result, once succeeded, is an ``UploadFileResult``.\n\nRaises:\n    PlatformError: ``session_busy`` when another ``complete`` is already\n        in flight for this session.\n    PlatformError: ``upload_expired`` when the session was aborted or its\n        TTL passed before every part landed.\n    PlatformError: ``invalid_request`` when parts are missing or the\n        wrong size.\n    PlatformError: ``path_conflict`` when ``on_conflict=\"reject\"`` and a\n        different file already occupies the destination path.","operationId":"complete_upload_session_v1_workspaces__workspace_id__upload_sessions__session_id__complete_post","security":[{"UploadSessionTokenHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Upload session identifier.","title":"Session Id"},"description":"Upload session identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionCompleteJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/artifacts/content":{"get":{"tags":["artifacts"],"summary":"get_artifact_content","description":"Stream current artifact bytes by exact workspace-relative path.","operationId":"get_artifact_content_v1_workspaces__workspace_id__artifacts_content_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"path","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":1024,"pattern":"^[^/]","description":"Exact workspace-relative path of a live source, derivative, or query-result artifact.","title":"Path"},"description":"Exact workspace-relative path of a live source, derivative, or query-result artifact."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional single HTTP byte range, for example `bytes=0-1023`.","title":"Range"},"description":"Optional single HTTP byte range, for example `bytes=0-1023`."}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"416":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Requested Range Not Satisfiable"}}}},"/v1/workspaces/{workspace_id}/artifacts/rows":{"get":{"tags":["artifacts"],"summary":"get_artifact_rows","description":"One page of a parquet, csv or jsonl artifact's rows, in file order, by exact workspace-relative path.","operationId":"get_artifact_rows_v1_workspaces__workspace_id__artifacts_rows_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"path","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":1024,"pattern":"^[^/]","description":"Exact workspace-relative path of a live source, derivative, or query-result artifact.","title":"Path"},"description":"Exact workspace-relative path of a live source, derivative, or query-result artifact."},{"name":"start_row","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"File row number of the first row in the page, 0-based.","default":0,"title":"Start Row"},"description":"File row number of the first row in the page, 0-based."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."},{"name":"ranges","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":8400,"pattern":"^\\d+-\\d+(,\\d+-\\d+)*$"},{"type":"null"}],"description":"Ascending, non-overlapping inclusive row ranges to read instead of a contiguous window, e.g. '3-3,17-19'. Replaces start_row/limit; the ranges may cover at most as many rows as the page limit allows.","title":"Ranges"},"description":"Ascending, non-overlapping inclusive row ranges to read instead of a contiguous window, e.g. '3-3,17-19'. Replaces start_row/limit; the ranges may cover at most as many rows as the page limit allows."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactRowsPage"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/ingestions":{"post":{"tags":["ingestion"],"summary":"ingest","description":"Queue an ingestion run for one file, a batch, or an entire folder.\n\nCost class: **job** (pipeline compute per file; billed on completion).\n\nPass a :class:`~ndi_service.app.platform_api.contracts.IngestionSelection`\nto say what to process:\n\n* ``{\"type\": \"file_ids\", \"file_ids\": [...]}`` — explicit file list.\n* ``{\"type\": \"path_prefix\", \"path_prefix\": \"reports/\"}`` — a folder;\n  ``stale_only=true`` restricts the run to files whose hash diverged.\n\nThe ingestion lane (PDF, Excel, audio, …) is chosen per file from its type;\na caller does not name a lane.\n\n**Per-file outcomes, not a single verdict.** A file already ingested at\nthe same hash is ``skipped_unchanged`` (free) unless ``reingest_unchanged``\nis set. A valid zero-row raw Parquet file is ``skipped_empty`` (free) and\nproduces no searchable table. One corrupt file in a folder of 400 does not\nfail the run. It appears as a ``failed`` entry in ``result.outcomes``.\nA job where every attempted file failed is ``failed``. Its ``error.code``\nis taken from the files, and ``error.detail`` carries the per-file reasons.\nThat job has no ``result``. Partial failures stay outcomes on a succeeded job.\n\nThis is the **only call that makes files searchable**. Uploading a file to\nthe workspace ledger registers it; ingesting it builds the representations\n(search index, knowledge-graph nodes) that queries read.\n\nArgs:\n    body: Ingestion parameters: selection and reingest flag.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`. On success the\n    result is an :class:`~ndi_service.app.platform_api.results.IngestionResult`\n    with per-file outcomes.","operationId":"ingest_v1_workspaces__workspace_id__ingestions_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestionJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/reconciliations":{"post":{"tags":["ingestion"],"summary":"reconcile","description":"Detect divergence between storage and the file ledger; optionally act on it.\n\nCost class: **job** (storage listing + hash comparison; billed on completion).\n\nReconciliation compares the customer-visible storage tree against the ledger\nand records the result there. The scan itself never modifies stored bytes or\nderived representations. It marks:\n\n* ``discovered`` — objects in storage with no ledger row.\n* ``stale`` — rows whose ``observed_hash`` no longer matches the stored object.\n* ``orphans`` — rows whose object is gone from storage.\n\nSet ``auto_ingest=true`` to chain a ``POST /workspaces/{id}/ingestions``\nautomatically when divergence is found. Without it, reconciliation still\nupdates the ledger but starts no ingestion. The ``ingestion_job_id`` in the\nresult points to that job so you can poll it separately.\n\n``selection.stale_only`` on the chained ingestion is the routine case:\nit re-ingests exactly the stale files and is a no-op when nothing diverged.\n\n``path_prefix`` scopes the scan; omit it (or pass ``null``) to scan the\nwhole workspace.\n\nArgs:\n    body: Reconciliation parameters: optional path scope and auto-ingest flag.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`. On success the\n    result is a :class:`~ndi_service.app.platform_api.results.ReconciliationResult`\n    with counts and file-id lists. ``ingestion_job_id`` is set when\n    ``auto_ingest`` was requested.","operationId":"reconcile_v1_workspaces__workspace_id__reconciliations_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconcileRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconciliationJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/knowledge-graph/builds":{"post":{"tags":["knowledge-graph"],"summary":"build_knowledge_graph","description":"Build (or rebuild) the workspace's knowledge graph from its ingested files.\n\nCost class: **job** (corpus-level extraction and entity resolution; billed on\ncompletion).\n\nThe graph is built over every **ingested** file in the workspace at once —\nentity resolution links entities *across* documents, so it cannot be a per-file\noperation the way parsing or categorization are. Files that are not yet ingested\nare not in the corpus. Ingest them first, then build. A workspace with no\ningested files is refused with ``invalid_request`` before a job is created.\nThat check runs after an idempotent replay, so a retry of a build that\nalready started still returns the original job. A workspace whose ingested\nfiles are all excluded by graph rules still starts a job. The workflow\nfails that job. A rebuild resumes from the durable store, re-paying only\nfor what changed since the last build. ``force`` clears the store and\nrebuilds from scratch.\n\nOnce built, query the graph with the ``kg-info`` / ``kg-search`` / ``kg-walk``\ncontext tools. A file's ``representations.knowledge_graph`` reads true once a\nbuild that covered it has finalized.\n\nArgs:\n    body: Build parameters — currently just ``force``.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``). A real build\n        far outlasts any sync window, so callers normally poll the returned job.\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`. On success the result\n    is a :class:`~ndi_service.app.platform_api.results.KnowledgeGraphBuildResult`.\n\nRaises:\n    PlatformError: ``invalid_request`` when the workspace has no ingested files.\n        Raised after an idempotent replay, and before a job row or workflow\n        is created.","operationId":"build_knowledge_graph_v1_workspaces__workspace_id__knowledge_graph_builds_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeGraphBuildRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeGraphBuildJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/uploads/{upload_id}":{"delete":{"tags":["document-operations"],"summary":"delete_upload","description":"Erase an unused upload. A used upload must be removed by deleting its consuming jobs.","operationId":"delete_upload_v1_uploads__upload_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"upload_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Upload Id"}}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/uploads":{"post":{"tags":["document-operations"],"summary":"create_upload","description":"Stage bytes for document operations and return a handle.\n\nCost class: **fast** (upload I/O only; no processing units charged here).\n\nThe returned ``upload_id`` is passed as ``{\"type\": \"upload\", \"upload_id\":\n\"<id>\"}`` in any subsequent document-operation request.  Uploads are\nretained until explicit deletion of the upload, consuming jobs or tenant.\nZero retention refuses standalone uploads with ``422 invalid_request``;\nuse a workspace bound to your own S3 or Azure storage.\n\nUploads are workspace-free: this is the entry point for callers that want\nto use granular operations without onboarding to the full ingestion model.\n\nArgs:\n    caller: Authenticated tenant (resolved from ``X-API-Key``).\n    session: Database session.\n    file: The document bytes.\n\nReturns:\n    An :class:`UploadResponse` with the opaque handle, file name, byte\n    count, SHA-256 content hash, and expiry timestamp.\n\nRaises:\n    PlatformError: ``file_too_large`` when the upload exceeds\n        ``NDI_MAX_UPLOAD_BYTES``; ``rate_limited`` when a service key's\n        account or tenant is over its request budget.","operationId":"create_upload_v1_uploads_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_upload_v1_uploads_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__platform_api__document_operations__schemas__UploadResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"504":{"description":"Gateway Timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/parse":{"post":{"tags":["document-operations"],"summary":"parse","description":"Parse a document into structured text, Markdown, or block JSON.\n\nCost class: **job** (processing units proportional to page count and OCR\nload; billed on completion).\n\nAccepts any source a granular operation can read — a staged upload, an\n``https://`` URL, a workspace file, or a prior Parse job.  Returns ``202`` with\na queued :class:`~ndi_service.app.platform_api.results.Job` immediately;\npass ``?wait_seconds=N`` to block up to N seconds for the result inline.\n\nOCR is applied automatically when the document needs it; the result's\n``ocr_applied`` flag reports whether it ran.\n\nArgs:\n    body: Parse parameters: source, optional page range, and desired\n        output formats.\n    caller: Authenticated tenant.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI to set the response status code.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`; read ``status``\n    regardless of whether the response is ``200`` or ``202``.","operationId":"parse_v1_parse_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/split":{"post":{"tags":["document-operations"],"summary":"split","description":"Split a document by page ranges or a spreadsheet by worksheet.\n\nSpreadsheet splitting is deterministic, does not classify tabs, and always\nreturns one materialized single-sheet XLSX artifact per segment.\n\nCost class: **job** (document parsing/inference when needed, or workbook\nnormalization and tab materialization; billed on completion).","operationId":"split_v1_split_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SplitRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SplitJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/classify":{"post":{"tags":["document-operations"],"summary":"classify","description":"Classify one document against caller-provided classes.\n\nCost class: **job** (model inference per document; billed on completion).\n\nThe canonical p0 input is one document, matching the routing use case and\ncommon industry shape.\n\nReturns ``202`` immediately unless ``?wait_seconds=N`` is set; the result\ncarries ranked label units for the requested document or page granularity.\n\nArgs:\n    body: Classify parameters: one source, classes, unknown policy, and\n        output options.\n    caller: Authenticated tenant.\n    session: Database session.\n    wait_seconds: Bounded inline wait.\n    idempotency_key: Idempotent replay key.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`.","operationId":"classify_v1_classify_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassifyRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ClassifyJob"},{"$ref":"#/components/schemas/CategorizeJob"}],"title":"Response Classify V1 Classify Post"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extract":{"post":{"tags":["document-operations"],"summary":"extract","description":"Extract schema-shaped structured data from a document.\n\nCost class: **job** (LLM inference + parsing; billed on completion).\n\nProvide an inline ``schema`` or a registered ``schema_id``. The effective\nschema is validated before the job is accepted; use\n``POST /v1/extract/schema-validation`` to pre-check yours. Exactly one of\n``schema_id`` or ``schema`` must be present. Optional ``schema_version``\npins a registry version when ``schema_id`` is set.\n\nCitations are enabled by default (``citations.enabled=true``). Located\nfields carry :class:`~ndi_service.app.platform_api.contracts.Citation`\nentries (``location`` + optional ``source_text``). A field the model could\nnot find is returned as ``status=not_found``, never silently omitted.\n\nArgs:\n    body: Extraction parameters: source, schema, and citation preference.\n    caller: Authenticated tenant.\n    session: Database session.\n    wait_seconds: Bounded inline wait.\n    idempotency_key: Idempotent replay key.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`.\n\nRaises:\n    PlatformError: ``schema_not_found`` when ``schema_id`` is unknown;\n        ``invalid_schema`` when the inline or registered ``schema`` fails\n        the same compiler check the extraction pipeline applies.","operationId":"extract_v1_extract_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/extract/schema-validation":{"post":{"tags":["document-operations"],"summary":"validate_extract_schema","description":"Validate an extraction schema without creating a job or consuming credits.\n\nCost class: **fast** (pure validation, no I/O, no model inference).\n\nUse this before submitting an ``extract`` job to catch schema errors up\nfront.  On success ``valid=True`` and ``normalized_schema`` carries the\ncompiled form the extraction pipeline will use.  On failure ``valid=False``\nand ``errors`` lists every violation — the whole list, not just the first.\n\nArgs:\n    body: Exactly one of ``schema_id`` or ``schema``. Optional\n        ``schema_version`` pins a registry version when ``schema_id`` is set.\n    caller: Authenticated tenant used to resolve tenant/platform schemas.\n    session: Database session.\n\nReturns:\n    An :class:`ExtractSchemaValidationResponse`.\n\nRaises:\n    PlatformError: ``schema_not_found`` when ``schema_id`` is unknown.","operationId":"validate_extract_schema_v1_extract_schema_validation_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__platform_api__document_operations__schemas__ExtractSchemaValidationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__platform_api__document_operations__schemas__ExtractSchemaValidationResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"504":{"description":"Gateway Timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/ground":{"post":{"tags":["document-operations"],"summary":"ground","description":"Locate caller-provided target text in a document.\n\nCost class: **job** (retrieval + model inference per target; billed on\ncompletion).\n\nEach target is located independently and returns an honest location status:\n``found``, ``not_found``, or ``failed``.  Ground does not verify claims and\ndoes not produce contradiction verdicts.\n\nUp to MAX_CLAIM_BATCH targets or legacy claims per call; all are grounded\nagainst the same ``source``.\n\nArgs:\n    body: Ground parameters: source and the targets to locate.\n    caller: Authenticated tenant.\n    session: Database session.\n    wait_seconds: Bounded inline wait.\n    idempotency_key: Idempotent replay key.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A :class:`~ndi_service.app.platform_api.results.Job`.","operationId":"ground_v1_ground_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/tools/locate":{"post":{"tags":["tools"],"summary":"locate","description":"Find the pages and tables that hold a piece of information.\n\n**Cost class: medium** — a few seconds on a workspace the navigator has seen; the first call after an\ningestion change reads the workspace's ingestion outputs first.\n\nA decision model walks the workspace's files, sections and pages (built at ingestion) and names the pieces to\nread, best first, with the tables to query — the locate NDI's own navigate-mode agent runs. ``text`` is that\nagent's reply, word for word. Only files the key may see are considered, cut to ``path_prefix`` / ``paths``.\n\nStateless: send back the pieces a previous call offered (``exclude``) and what you have read (``already_read``)\nto be shown something new.\n\nArgs:\n    body: The need, the question it belongs to, the piece count, scope and exclusions.\n    workspace: Resolved workspace and caller access predicate.  A\n        non-existent workspace returns ``workspace_not_found`` before the\n        body executes.\n    session: Database session.","operationId":"locate_v1_workspaces__workspace_id__tools_locate_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocateResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/tools/folder-metadata":{"post":{"tags":["tools"],"summary":"folder_metadata","description":"List one folder of the workspace: file counts, categories, subfolders, and the files' exact paths.\n\n**Cost class: fast.**\n\nExplore in steps instead of listing everything at once:\n\n1. Call with the defaults on ``/`` (the workspace root): the folder's own\n   files plus one summary per subfolder (file count, top categories,\n   failed-ingestion count).\n2. Descend with ``directory=<folder>``, or narrow with ``name_contains=``\n   (find a file by part of its name), ``category=``, ``ingestion_status=``\n   (e.g. ``failed``) or ``kind=``. Counts and listing narrow together, and\n   a narrow covers the whole subtree unless ``recursive=false`` is sent.\n3. Pass a ``file_entries[].path`` to ``file-metadata`` to see what is inside\n   that file, then ask with ``qa-file`` or ``query-tables``.\n\nEvery path is relative to the workspace root and never includes the\nworkspace id. ``name_contains`` finds files by what they are called — files\nwhose ingestion failed included; the search tools find them by what they\ncontain.\n\nA ``directory`` that names a file is refused with ``invalid_request``\npointing at ``file-metadata``. An unfiltered call that matches nothing\nanswers with a ``hint`` naming the nearest existing folder and what it\nholds, so a mistyped folder is not a dead end.\n\n``file_entries`` comes one ``page_size`` page at a time, sorted by path;\n``files_truncated`` reports a cut — resume with ``start_after=<last path>``\nor narrow. Counts and listing only include files the caller's access\nlabels allow; ``coverage`` says how many were withheld.\n\nArgs:\n    body: Folder, recursion flag, the narrows (category, ingestion_status,\n        kind, name_contains), page size, cursor.\n    workspace: Resolved workspace and caller access predicate.  A\n        non-existent workspace returns ``workspace_not_found`` before the\n        body executes.\n    session: Database session.","operationId":"folder_metadata_v1_workspaces__workspace_id__tools_folder_metadata_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderMetadataRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderMetadataResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/tools/file-metadata":{"post":{"tags":["tools"],"summary":"file_metadata","description":"Describe one uploaded file without opening it: what it is, its category, and the parts you can ask about.\n\n**Cost class: fast.**\n\n``path`` is the file's full path relative to the workspace root, exactly\nas it was uploaded and as ``folder-metadata``, ``GET .../files`` and search\nresults (``source_path``) print it — for example\n``evidence/doc-7f83/contract.pdf``. A bare file name (``contract.pdf``), a\nfolder, a file id, or a path that starts with the workspace id is not\nfound. ``file_not_found`` is final for that value: do not retry it or guess\nvariants — list the folder with ``folder-metadata`` (``name_contains=`` a\npart of the name) and use the path it prints.\n\nThe response gives the file's ``category``, a ``summary`` of its first\nsection or tab, page or tab counts, and its ``components``: each section,\ntab, image or recording with its own summary, categories, page range or\ntable shape, and ``key_terms`` — keywords whose role the source states\n(who a name is, what a date marks). A recording reports its duration.\n``readable`` means ``qa-file`` can answer from the component's text;\n``queryable`` means it is a table ``query-tables`` can compute over. Pass a\ncomponent's ``name`` as ``component`` to scope either tool to it.\n\n``component`` narrows this response to one section or tab by name; a name\nthat matches nothing is refused with ``invalid_request`` listing the valid\nnames. A file that is not ingested yet answers 200 with its\n``ingestion_status`` and no components; a failed one carries\n``ingestion_error``.\n\nArgs:\n    body: The uploaded file's path, and optionally one component name to\n        scope the response to.\n    workspace: Resolved workspace and caller access predicate.  A\n        non-existent workspace returns ``workspace_not_found`` before the\n        body executes.\n    session: Database session.","operationId":"file_metadata_v1_workspaces__workspace_id__tools_file_metadata_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMetadataRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMetadataToolResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/tools/read-file":{"post":{"tags":["tools"],"summary":"read_file","description":"Read the text of one uploaded file.\n\n**Cost class: fast.**\n\n``path`` names an **uploaded source file** — the only namespace this tool\nserves.  A workspace-internal path is refused with ``invalid_request``\nnaming the uploaded file to use instead.\n\nA file with several components (a spreadsheet's tabs, a pdf's sections)\nanswers with their text concatenated in the file's own order, each part\nunder a one-line header naming the component; ``components_returned`` and\n``components_omitted`` report exactly what made it into the budget.  Scope\nthe read with ``component=<name>`` (the names ``file_metadata`` lists)\nwhen only one tab or section matters, and with ``pages`` (1-based) for\npaged documents — spreadsheets have no pages, so scope those by component\ninstead.  Images are refused — ask about them with ``qa_file``.\n\nArgs:\n    body: Source path, optional component name, optional page list, and\n        character limit.\n    workspace: Resolved workspace and caller access predicate.  A\n        non-existent workspace returns ``workspace_not_found`` before the\n        body executes.\n    session: Database session.","operationId":"read_file_v1_workspaces__workspace_id__tools_read_file_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/tools/qa-file":{"post":{"tags":["tools"],"summary":"qa_file","description":"Answer a natural-language question about one uploaded file — document, media, image, or table.\n\n**Cost class: slow.**\n\n``path`` names an **uploaded source file** — the same full path\n``file_metadata`` takes, exactly as ``folder_metadata`` lists it; a bare\nfile name is not found, and a workspace-internal path is refused with\n``invalid_request``.\n\nThe engine is picked from what the file (or the selected component) *is*:\nan image goes to vision QA, and text — of any length — to a recursive LLM\nbuilt for long documents.  A file with several parts (a pdf split into\nsections, a workbook with several tabs, a recording with attachments) or\nwith rows (a spreadsheet tab, a csv/parquet/jsonl upload, a pdf's long\ntable) is worked by a QA agent that searches within the file, reads the\nrelevant parts, and writes its own SQL over the file's tables.  The\nresponse's ``engine`` field reports which one ran.\n\nScope the question with ``component=<name>`` (the names ``file_metadata``\nlists) to ask about one section directly.  Use this when you need a\ndirect, cited answer about a file's contents rather than search hits.\n\nExecution survives HTTP disconnects. By default the route waits and returns\nthe original answer shape. Send ``Prefer: respond-async`` to return a Job\nimmediately, then poll its ``Location`` URL. ``Idempotency-Key`` recovers the\nsame job after a lost response. Only explicit job cancellation stops it.\n\nArgs:\n    body: Source path, the natural-language question, whether to include\n        citations, and the optional component scope.\n    workspace: Resolved workspace and caller access predicate.  A\n        non-existent workspace returns ``workspace_not_found`` before the\n        body executes.\n    session: Database session.\n    temporal: Temporal client, used to dispatch the durable qa-file job.\n    response: The response, whose status and job headers the submission sets.\n    prefer: ``respond-async`` returns the accepted job instead of waiting.\n    idempotency_key: Recovers the same job after a lost response.","operationId":"qa_file_v1_workspaces__workspace_id__tools_qa_file_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"prefer","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefer"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QaFileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QaFileResponse"},{"$ref":"#/components/schemas/Job"}],"title":"Response Qa File V1 Workspaces  Workspace Id  Tools Qa File Post"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"description":"Durable qa-file accepted; poll the Location URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}}}}},"/v1/workspaces/{workspace_id}/tools/query-tables":{"post":{"tags":["tools"],"summary":"query_tables","description":"Answer a natural-language question over uploaded table files — one or several.\n\n**Cost class: slow.**\n\n``paths`` is a list of selection rows — ``{\"path\": ...}`` for a whole file,\n``{\"path\": ..., \"component\": <tab>}`` for one tab of one workbook (repeat\nthe path to select several tabs).  Every path must be a **table file** —\na spreadsheet (xlsx, xls, xlsm, xlsb, ods) or record file (csv, tsv,\nparquet, jsonl, ndjson, json); a document, media, or image path is\nrefused with ``invalid_request`` naming ``qa-file``.  Every tab is askable whatever its ingestion produced:\nselections whose tabs all have extracted rows are answered by the SQL\nengine — the answer keeps full result parquet storage outside the response\nand returns bounded previews plus authenticated workspace result-file\ncitations — while a selection holding tabs with only a rendered sheet is\nanswered by a QA agent that reads renderings and queries row extractions\ntogether (no result previews on that lane; citations quote the sheets).\n\n``component`` names are workbook-local — the same strings ``file-metadata``\nand ``filtered-search`` publish as ``component``, matched exact-name first,\nthen the unambiguous sanitized alias.  A name that matches nothing on its\nown workbook — or any ``component`` on a single-table upload\n(csv/jsonl/parquet), which has no named parts — is ``invalid_request``.  A\nselected tab with no usable content at all is reported in ``unavailable``\nrather than silently dropped.\n\nExecution survives HTTP disconnects. By default the route waits and returns\nthe original answer shape. Send ``Prefer: respond-async`` to return a Job\nimmediately, then poll its ``Location`` URL. ``Idempotency-Key`` recovers the\nsame job after a lost response. Only explicit job cancellation stops it.","operationId":"query_tables_v1_workspaces__workspace_id__tools_query_tables_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"prefer","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prefer"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryTablesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QueryTablesResponse"},{"$ref":"#/components/schemas/Job"}],"title":"Response Query Tables V1 Workspaces  Workspace Id  Tools Query Tables Post"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"description":"Durable table QA accepted; poll the Location URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}}}}},"/v1/workspaces/{workspace_id}/tools/run-sql":{"post":{"tags":["tools"],"summary":"run_sql","description":"Run one caller-authored read-only SELECT over the workspace's tables.\n\n**Cost class: fast.** No planner and no answering agent — the statement\nruns directly in the guarded SQL engine, against every queryable tab in\nthe workspace registered as a view under the ``table_name`` that\n``file-metadata`` and the folder-metadata table census publish. Joins\nacross files are ordinary SQL joins; earlier run-sql results are\nregistered too, so a returned ``res_…`` handle can be joined, aggregated,\nor paged with LIMIT/OFFSET in the next statement.\n\nThe full result is retained as parquet whatever the preview shows —\n``result_citation.result_file.download_url`` fetches it whole. A\nstatement that is not a read, or reads an unregistered table, is refused\nwith ``invalid_request`` naming the rule broken and the registered\ntables. For a natural-language question — or when the answer should be\ncomposed and cited for you — use ``query-tables`` instead.","operationId":"run_sql_v1_workspaces__workspace_id__tools_run_sql_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunSqlRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunSqlResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/deep-search":{"post":{"tags":["intelligent-search"],"summary":"deep_search","description":"Run an agentic search over a workspace. Cost class: **job**.\n\nThe caller receives a ``202`` with a queued\n:class:`~ndi_service.app.platform_api.results.Job` immediately, and polls\n``GET /jobs/{id}`` for the result once the job succeeds.\n\nEvery run uses one configuration: a reasoning engine with a thinking\nbudget, the internal CLI tool surface, and the workspace's knowledge graph\nwhen one is built (the 2026-09 five-lane evaluation picked it as the most\naccurate lane).\n\nOne implementation serves every scope: the source-level\nagent (``deep_search_v2``). It browses, reads, and computes over the\nuploaded files exactly as an API caller would, writes its own SQL over the\ntables in scope, and every executed statement lands on the result as a\nreceipt (``sql_receipts``) — a figure and the query behind it travel\ntogether. (Jobs created before the 2026-09 consolidation may carry the\nretired classic loop's ``intelligent_search`` kind; they stay readable via\n``GET /jobs``.)\n\nScope never changes the configuration: ``paths`` scopes the run to exactly\nthose uploaded files — every tool the agent runs (search, listings, reads,\nask-file, SQL, the shell's ``ndi`` commands) sees only them and the\ncontent ingested from them, enforced server-side against the stored job.\nEach entry must name a visible uploaded source file (``file_not_found`` /\n``access_denied`` otherwise, before any job is created). With ``path_prefix``\nthe two add up: the run covers the folder's files plus the named ones.\n\nPass the result's ``session_id`` to ask a follow-up. With the same\nfolder/file scope and access grants, the agent resumes that transcript.\nChanging either starts a fresh conversation and returns its new\n``session_id``, so prior tool results cannot cross the new scope boundary.\nOlder transcripts without a scope snapshot also restart. Classic thread\nids return ``session_not_found``; retrying the original request with its\nidempotency key still returns that historical job.\n\n``allow_clarification`` lets the agent ask instead of guessing on a genuinely\nambiguous query: the succeeded result then carries the questions in\n``clarification_questions`` (and as text in ``clarification``) with\n``answer`` null. Answer them in the same thread — send the result's\n``session_id`` with the same ``query`` and ``clarification_answers``, or with\nany refined query. Off (the default) the agent never asks back.\n\nRetrieval only: this job never grounds.  To pin a quote to a region of its\nsource document, call document-operations ``ground`` on the file the\ncitation names with its quote as the target text — separately, and only\nfor the citations you actually need a locator for.\n\n``exhausted: true`` means the step budget ran out before the agent\nfinished — a successful, partial response, not a failure.\n\nArgs:\n    body: Search parameters: query, context, allow_clarification,\n        clarification_answers, path_prefix, paths, session_id.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n    temporal: Temporal client used to dispatch the workflow.\n    search_model: Internal engine pin; overrides the configuration's engine,\n        never its tooling.\n    search_playbook: Internal procedure pin; retired with the classic loop — refused.\n    report_usage: Internal usage-accounting switch.\n    postprocessing: Internal optional-postprocessing mode; ``none`` skips\n        the detached presentation/grounding sidecars after commit.\n\nReturns:\n    A queued :class:`~ndi_service.app.platform_api.results.Job`.  On\n    success the result is a\n    :class:`~ndi_service.app.platform_api.results.DeepSearchV2Result`,\n    naming itself in ``result_type``.","operationId":"deep_search_v1_workspaces__workspace_id__deep_search_post","deprecated":true,"security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepSearchRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepSearchJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/fact-search":{"post":{"tags":["intelligent-search"],"summary":"fact_search","description":"Run the fixed single-shot search pipeline over a workspace. Cost class: **job**.\n\nOne retrieval pass (hybrid search, plus the knowledge graph when the\nworkspace has one, fused when both legs return candidates), targeted page\nreads or retrieved passages for prose (specialized engines for tables or\nimages), then one answering pass — so it returns in seconds where\n``deep-search`` may take minutes.  The caller receives a ``202`` with a\nqueued :class:`~ndi_service.app.platform_api.results.Job` and polls\n``GET /jobs/{id}`` for the\n:class:`~ndi_service.app.platform_api.results.IntelligentSearchResult` —\nthe identical result shape ``deep-search`` lands, evidences and coverage\nincluded.\n\nSingle-shot: a fact-search run keeps no conversation, so the result's\n``session_id`` is always ``null`` and the request body has no\n``session_id`` field.  For a thread you can ask follow-ups in, call\n``deep-search``.  It always answers — the result carries a direct grounded\n``answer``, with ``reasoning`` stating how the pipeline read the query —\nand never asks back: the body has no ``allow_clarification`` either (a\nfixed pipeline has no agent who could pose the question).\n\n``paths`` scopes the run to exactly those uploaded files: every retrieval\nleg sees only them and the content ingested from them, enforced\nserver-side against the stored job. Each entry must name a visible\nuploaded source file (``file_not_found`` / ``access_denied`` otherwise,\nbefore any job is created). With ``path_prefix`` the two add up: the run\ncovers the folder's files plus the named ones.\n\nRetrieval only: this job never grounds.  To pin a quote to a region of its\nsource document, call document-operations ``ground`` on the file the evidence\nnames (``source_file_id``) with its ``quote`` as the target text.\n\nArgs:\n    body: Search parameters: query, context, path_prefix, paths, top_k.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    response: Injected by FastAPI for status-code management.\n\nReturns:\n    A queued :class:`~ndi_service.app.platform_api.results.Job`.  On\n    success the result is an\n    :class:`~ndi_service.app.platform_api.results.IntelligentSearchResult`\n    with evidences, the answer and reasoning, coverage, and the\n    pipeline's step trace.","operationId":"fact_search_v1_workspaces__workspace_id__fact_search_post","deprecated":true,"security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FactSearchRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntelligentSearchJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/automatic-search":{"post":{"tags":["intelligent-search"],"summary":"automatic_search","description":"Answer one query with fact search or the automatic search agent. Cost class: **job**.\n\nWith ``mode`` ``auto`` (the default), the service reads the query and optional\ncontext before retrieval and chooses a one-pass fact search for focused\nlookups, or an agent that locates the pages and tables it needs with a\nnavigator over the workspace's files (on a workspace in a bring-your-own\nbucket or customer storage, by searching it), then reads documents, queries\ntables, and selects documents from the metadata catalog. When it chooses fact search and fact\nsearch cannot settle the question (it finds no answer while a table it was\ngiven was not read whole, such as a Parquet table or one too large to read, or\nit cites nothing, grades its answer low or speculative, or fails), the agent\nanswers instead: ``routing.selected`` stays ``fact`` and ``routing.final``\nreads ``agent``. When fact search finds no answer in material it read whole,\nthat is the answer, with no hand-over.\nIn any mode, a query that asks for nothing (a keyboard mash, say) and none of\nwhose words a document contains is answered so without a search or a charge.\n``mode`` ``fact`` or ``agent`` runs that route directly, with no\nrouting step to bill and no hand-over. This single-shot route does not\nask clarification questions. Every route enforces\nthe caller's access and its scope: ``path_prefix`` and ``paths`` resolve to one\nfile set, the same one fact search and the agent (its catalog commands included)\nfilter by. Each ``paths`` entry must name a visible uploaded source file.\n\nThe result contains the chosen route's output and its owning `output_job_id`,\nplus routing details. When the agent answers from the catalog, its output also\ncarries the catalog table, whose `next_cursor` continues through\n`filtered-search` with a page request, without another routing decision.","operationId":"automatic_search_v1_workspaces__workspace_id__automatic_search_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomaticSearchRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomaticSearchJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/qa":{"post":{"tags":["intelligent-search"],"summary":"qa","description":"Ask a question about a workspace, as one turn of a conversation. Cost class: **job**.\n\nEvery turn runs the automatic search agent on its own — no router, no fixed\npipeline, no opening search. The agent finds what the turn needs itself, in\nthe light of the conversation so far: it asks a navigator over the\nworkspace's files, sections and pages, or, on a workspace in a\nbring-your-own bucket or customer storage, searches it. It then reads\ndocuments, queries tables, and selects documents from the metadata catalog\nuntil it can answer. Every tool enforces\nthe caller's access and the conversation's scope: ``path_prefix`` and\n``paths`` resolve to one file set.\n\nPass a result's ``session_id`` to ask a follow-up: the agent resumes the\nconversation, so \"and for 2023?\" or \"why?\" means what it means in context.\nWhen a question is genuinely ambiguous the agent may ask back instead\n(``allow_clarification``, on by default): the result then carries\n``clarification_questions`` with ``answer`` null; reply with\n``clarification_answers`` and the same ``session_id``, or rephrase.\n\nA conversation's first question that asks for nothing (a keyboard mash, say)\nand none of whose words a document contains is answered so without running\nthe agent or a charge, and starts no conversation.\n\nThe result is the agent's answer — citations, SQL receipts, confidence — plus,\nwhen it answered from a catalog query, the catalog table, whose\n``next_cursor`` continues through ``filtered-search``.","operationId":"qa_v1_workspaces__workspace_id__qa_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QaRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QaJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/filtered-search":{"post":{"tags":["filtered-search"],"summary":"filtered_search","description":"Run a structured filter/rank/count query over the workspace's metadata catalog. Cost class: **job**.\n\nSend ``{type: \"query\", query, context?, path_prefix?, paths?, allow_clarification?}``\nto start a search. ``path_prefix`` and ``paths`` resolve to one file set: only\ncatalog entries extracted from those files can match. Each ``paths`` entry must\nname a visible uploaded source file. Then an agent translates the request into a validated catalog\nquery, and the result is a table — typed columns, matching components as\nrows (each named by its uploaded file), an exact ``total_matches``, and\nevidence citations per extracted value. Count-style questions return the\ntotal with no rows; \"top N\" questions return exactly N rows with the\npre-cutoff total. With ``allow_clarification`` set, a genuinely ambiguous request\nmay come back as a rejection instead: the succeeded result carries one\nquestion in ``clarification`` (no rows, no ``applied_query``, ``exhaustive``\nfalse) — filtered search keeps no session, so answer it by sending a new\ninitial query.\n\nSend ``{type: \"page\", cursor}`` with an earlier result's ``next_cursor``\nto fetch the next page. Pages re-execute the original query against the\n**current** catalog under your current access — no agent runs, and\nconcurrent ingestion or deletion may shift later pages (the result's\n``catalog_drifted`` says the underlying data changed). Only the API key\nthat ran the original query may page it; an expired or purged parent job\nreturns ``invalid_request``.\n\nRead ``exhaustive`` before treating a result as a census: when false, the\nmatches shown are valid but completeness is not guaranteed (uncataloged\nfiles in scope, degraded extractions, or a residual content condition).\nRead ``field_readability`` alongside it: a non-empty entry means the\npredicate could not be evaluated on part of the population, so an empty or\nthin result may reflect unreadable data rather than absence.\nMonetary values always carry their ISO currency and are never converted;\ncomparing amounts across currencies is unsupported in this version.\n\nArgs:\n    body: The discriminated request — an initial query or a page cursor.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    response: Injected by FastAPI for status-code management.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n\nReturns:\n    A queued :class:`~ndi_service.app.platform_api.results.Job`. On success\n    the result is a\n    :class:`~ndi_service.app.platform_api.results.FilteredSearchResult`.","operationId":"filtered_search_v1_workspaces__workspace_id__filtered_search_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InitialFilteredSearch"},{"$ref":"#/components/schemas/FilteredSearchPage"}],"title":"Body"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilteredSearchJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/workspaces/{workspace_id}/je-testing":{"post":{"tags":["je-testing"],"summary":"je_testing","description":"Run journal-entry testing over a workspace's ledger package. Cost class: **job**.\n\nThe caller receives a ``202`` with a queued\n:class:`~ndi_service.app.platform_api.results.Job` immediately and polls\n``GET /jobs/{id}`` for the\n:class:`~ndi_service.app.platform_api.results.JetResult`.\n\nThe agent orients itself in the tables the workspace holds, writes SQL over\nthem itself, and answers with ``sql_receipts``: every statement it ran, the\ntables each one registered (path, tab, and the view name the SQL used), and\na bounded result. A figure in the answer is meant to be readable out of one\nof those receipts, and a receipt carries everything needed to re-run it.\n\n``paths`` scopes the run to exactly the files of the package under test;\n``path_prefix`` scopes it to a folder, and the two add up: the run tests\nthe folder's files plus the named ones. Omit both to test the whole workspace: the agent orients\nover every queryable file the caller can see and finds the ledger package\nitself, the same way ``deep-search`` behaves when unscoped. A run keeps its\nconversation: pass the result's ``session_id`` on a later request to ask a\nfollow-up in the same thread.\n\n``reasoning_effort`` controls the thinking budget without changing the\nengine. Omit it for the route's default; null keeps the catalogue prescription.\n\n``allow_clarification`` lets the agent stop and ask instead of answering —\nearly, for what the data cannot tell it (a threshold, the period or entity in\nscope, the client's definition of a term), or mid-run, for an ambiguity the\nwork turned up. The succeeded result then carries the questions in\n``clarification_questions`` with ``answer`` null. Answer them on the same\n``session_id`` with the same ``query`` and ``clarification_answers``, or with\nany follow-up query. Off (the default) the agent never asks.\n\n``exhausted: true`` means the step budget ran out before the procedure\nfinished — a successful, partial response, not a failure.\n\nArgs:\n    body: Testing parameters: query, context, reasoning_effort, path_prefix, paths, session_id,\n        allow_clarification, clarification_answers.\n    context: Resolved workspace plus the caller's access predicate.\n    session: Database session.\n    response: Injected by FastAPI for status-code management.\n    temporal: Temporal client used to dispatch the workflow.\n    wait_seconds: Bounded inline wait (``0`` → immediate ``202``).\n    idempotency_key: Replaying with the same key returns the original job.\n    search_model: Internal engine pin.\n    report_usage: Internal usage-accounting switch.\n    postprocessing: Internal optional-postprocessing mode; ``none`` skips\n        the detached presentation/grounding sidecars after commit.\n\nReturns:\n    A queued :class:`~ndi_service.app.platform_api.results.Job`. On success\n    the result is a :class:`~ndi_service.app.platform_api.results.JetResult`.","operationId":"je_testing_v1_workspaces__workspace_id__je_testing_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Workspace identifier.","title":"Workspace Id"},"description":"Workspace identifier."},{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"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.","title":"Idempotency-Key"},"description":"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."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JeTestingBody"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JeTestingJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs":{"get":{"tags":["operations"],"summary":"list_jobs","description":"List jobs for the authenticated tenant, newest first. Cost class: fast.\n\n``workspace_id`` narrows to workspace-scoped jobs; omitting it returns\ndocument-operation jobs too.  ``kind`` is the idiomatic way to list all\ningestion runs without a dedicated resource.\n\nPagination is keyset on ``(created_at, id)`` — OFFSET would silently miss\nor duplicate rows when new jobs arrive between pages.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    workspace_id: When set, restrict to one workspace.\n    kind: One or more job kinds to include.\n    status: One or more job statuses to include.\n    created_after: Lower bound on ``created_at`` (exclusive).\n    project_id: When set, restrict to jobs sharing this grouping id.\n    include_result: Deprecated single-result compatibility mode for old console builds.\n    cursor: Opaque cursor from a previous page's ``next_cursor``.\n    limit: Requested rows per page, capped at JOB_LIST_PAGE_SIZE for legacy clients.\n\nReturns:\n    One page of jobs with an exact total under the same filters.","operationId":"list_jobs_v1_jobs_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Restrict to jobs that run in or read from this workspace. Omit to also include workspace-free document-operation jobs.","title":"Workspace Id"},"description":"Restrict to jobs that run in or read from this workspace. Omit to also include workspace-free document-operation jobs."},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/JobKind"}},{"type":"null"}],"description":"Filter by job kind. Filtering by kind makes a separate 'ingestion runs' resource unnecessary.","title":"Kind"},"description":"Filter by job kind. Filtering by kind makes a separate 'ingestion runs' resource unnecessary."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/JobStatus-Input"}},{"type":"null"}],"description":"Filter by job status.","title":"Status"},"description":"Filter by job status."},{"name":"created_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Restrict to jobs created strictly after this timestamp (UTC).","title":"Created After"},"description":"Restrict to jobs created strictly after this timestamp (UTC)."},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Restrict to jobs sharing this caller-minted project id (the console's grouped runs).","title":"Project Id"},"description":"Restrict to jobs sharing this caller-minted project id (the console's grouped runs)."},{"name":"include_result","in":"query","required":false,"schema":{"type":"boolean","description":"Lists return metadata only. During the console rollout, true is a deprecated compatibility mode limited to one result per page; read complete results with GET /jobs/{job_id}.","deprecated":true,"default":false,"title":"Include Result"},"description":"Lists return metadata only. During the console rollout, true is a deprecated compatibility mode limited to one result per page; read complete results with GET /jobs/{job_id}.","deprecated":true},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":20,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_Job_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}":{"get":{"tags":["operations"],"summary":"get_job","description":"Read a single job. Cost class: fast.\n\nThe poll target for every ``202``, and the only way an MCP agent tracks\nprogress.  A late poll returns the job with a ``result_state``, never a\n404 — \"this expired\" and \"this never existed\" are a scheduling problem and\na bug respectively, and a 404 would make them identical.\n``result_expired`` (410) is deliberately NOT used here because the row still\nexists and still answers for billing.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    job_id: The job to read.\n\nReturns:\n    The current job, including ``result`` when it is retained.\n\nRaises:\n    PlatformError: ``job_not_found`` when no such job exists for this key.","operationId":"get_job_v1_jobs__job_id__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"patch":{"tags":["operations"],"summary":"update_job","description":"Rename a job. Cost class: fast.\n\n``name`` is the only mutable caller-facing field — the console uses it to\nrename a run (\"project\") after submission. Terminal jobs rename too: a\nfinished run's display name is presentation, not state.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    body: The new name; an explicit ``null`` clears the custom name. Public\n        document runs then display their stable server fallback.\n    job_id: The job to rename.\n\nReturns:\n    The job with its updated name.\n\nRaises:\n    PlatformError: ``job_not_found`` when no such job exists for this key.","operationId":"update_job_v1_jobs__job_id__patch","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJobRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["operations"],"summary":"delete_job","description":"Hide a job from listings and delete its content, keeping it for billing. Cost class: fast.\n\nThe row survives with its content-free billing fields, so ``units`` keep\nanswering and ``GET /v1/usage`` still counts the work; ``GET /v1/jobs`` stops\nreturning it. Reading it by id still works, with ``deleted_at`` set — the\nsame reasoning as an expired payload, where a 404 would conflate \"gone\" with\n\"never existed\".\n\nThe job's ``input``, ``result``, artifact files and source snapshot are\nremoved by the reaper's content-deletion leg on its next sweep (minutes), with\nthe same for an automatic search's delegated child: the delete only marks\nthe payload as expired now, so slow storage work stays out of the request.\nAfterwards the job reads as ``result_state=\"expired\"`` (a zero-retention job\nkeeps ``not_retained``). The same sweep deletes the perception-cache\nentries this job produced or consumed; one that another retained job of\nthe same tenant still reads stops serving hits and goes once that job's\ncontent is deleted.\n``input`` and ``result`` always go at that sweep. Only artifact files that\nanother retained job of the same tenant still uses (it reused this job's\nParse result, whose URLs point at them) are kept until that job's content\nis deleted; a later sweep deletes them. A job still queued or running that\nreuses this job's Parse result fails ``result_expired``. Bring-your-own-bucket\nfiles are never deleted.\n\nA job still queued or running is **cancelled first**, so hitting delete\nstops the compute rather than paying for a run nobody will ever see. A job\nthat finished under us is simply hidden: there was nothing left to stop, and\nrefusing the delete over a race the caller cannot see would be noise.\n\n``Temporal`` is not declared as a dependency here because asking for the\nclient connects: most deletes are of finished runs and need it for nothing,\nso an outage must not fail work that is entirely in Postgres.\n\nThere is no project-level route to pair with ``?project_id=``: a run's\nfan-out is one job per file, and the console deletes the group the same way\nit renames it — per job, over the ids it already holds.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    job_id: The job to hide.\n\nRaises:\n    PlatformError: ``job_not_found`` when no such job exists for this key.","operationId":"delete_job_v1_jobs__job_id__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/request":{"get":{"tags":["operations"],"summary":"get_job_request","description":"Read back the request a document operation ran under. Cost class: fast.\n\nWhat a finished run was *asked* for — the page selection, the schema, the\ntargets — so a caller can show the settings that produced a result, rebuild\nthe call that made it, or submit it again. ``Job.source`` names the document;\nthis names everything else.\n\nIts own route rather than a field on ``Job``: an extract schema or a ground\ntarget list is large, and ``GET /v1/jobs`` returns up to 200 rows.\n\nRetention is the same as the result's — the request is read from the stored\npayload, so it dies with it rather than outliving it.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    job_id: The job whose request to read.\n\nReturns:\n    The stored request, tagged with ``request_type`` (always equal to the\n    job's ``kind``).\n\nRaises:\n    PlatformError: ``job_not_found`` when no such job exists for this key;\n        ``invalid_request`` for a kind that carries no single document\n        request; ``result_expired`` once the payload is gone.","operationId":"get_job_request_v1_jobs__job_id__request_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ParseRequestEcho"},{"$ref":"#/components/schemas/SplitRequestEcho"},{"$ref":"#/components/schemas/ClassifyRequestEcho"},{"$ref":"#/components/schemas/CategorizeRequestEcho"},{"$ref":"#/components/schemas/ExtractRequestEcho"},{"$ref":"#/components/schemas/GroundRequestEcho"}],"discriminator":{"propertyName":"request_type","mapping":{"parse":"#/components/schemas/ParseRequestEcho","split":"#/components/schemas/SplitRequestEcho","classify":"#/components/schemas/ClassifyRequestEcho","categorize":"#/components/schemas/CategorizeRequestEcho","extract":"#/components/schemas/ExtractRequestEcho","ground":"#/components/schemas/GroundRequestEcho"}},"title":"Response Get Job Request V1 Jobs  Job Id  Request Get"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/split-artifacts/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_split_artifact_content","description":"Stream a materialized Split segment after checking access to its owning job.","operationId":"get_split_artifact_content_v1_jobs__job_id__split_artifacts__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/ground-crops/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_ground_crop_content","description":"Stream a Ground crop after reauthorizing it against the owning job.","operationId":"get_ground_crop_content_v1_jobs__job_id__ground_crops__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/ground-transcript/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_ground_transcript_content","description":"Stream a Ground transcript after reauthorizing it against the owning job.","operationId":"get_ground_transcript_content_v1_jobs__job_id__ground_transcript__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/parse-transcript/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_parse_transcript_content","description":"Stream a Parse transcript after reauthorizing it against the owning job.","operationId":"get_parse_transcript_content_v1_jobs__job_id__parse_transcript__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/parse-images/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_parse_image_content","description":"Stream an embedded picture after checking job ownership and membership.","operationId":"get_parse_image_content_v1_jobs__job_id__parse_images__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/converted-pdf/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_converted_pdf_content","description":"Stream the office-conversion PDF after reauthorizing it against the owning job.\n\nArgs:\n    session: Request-scoped database session.\n    caller: Authenticated client (API key); must own the job.\n    artifact_ref: Opaque artifact ref from the job's ``converted_pdf_url``.\n    job_id: The parse job the PDF belongs to.\n    range_header: Optional HTTP ``Range`` header for partial content.\n\nReturns:\n    A ``StreamingResponse`` carrying the PDF bytes.\n\nRaises:\n    PlatformError: ``not_found`` when the job is not the caller's\n        succeeded parse or the ref does not name its converted PDF.","operationId":"get_converted_pdf_content_v1_jobs__job_id__converted_pdf__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/spreadsheet-cell-maps/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_spreadsheet_cell_map_content","description":"Stream a Parse cell map after reauthorizing it against the owning job.","operationId":"get_spreadsheet_cell_map_content_v1_jobs__job_id__spreadsheet_cell_maps__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Range","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/spreadsheet-content/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_spreadsheet_content","description":"Stream complete Markdown for an oversized sheet after job authorization.","operationId":"get_spreadsheet_content_v1_jobs__job_id__spreadsheet_content__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}},"description":"Accepted"}}}},"/v1/jobs/{job_id}/document-content/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_document_content","description":"Stream complete reduced-layout Markdown after job authorization.","operationId":"get_document_content_v1_jobs__job_id__document_content__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}},"description":"Accepted"}}}},"/v1/jobs/{job_id}/cancel":{"post":{"tags":["operations"],"summary":"cancel_job","description":"Cancel a queued or running job. Cost class: fast.\n\nReturns the job in ``cancelled`` status.  ``cancelled`` is a first-class\nterminal status, not a ``failed`` variant — conflating them makes\nerror-rate metrics lie and forces every client to string-match an error\ncode.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    body: Optional cancellation reason.\n    job_id: The job to cancel.\n\nReturns:\n    The job in ``cancelled`` status.\n\nRaises:\n    PlatformError: ``job_not_found`` when the job does not exist.\n        ``job_not_cancellable`` (409) when it already reached a terminal\n        state — a terminal job cannot be un-done, only read.","operationId":"cancel_job_v1_jobs__job_id__cancel_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CancelJobRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/events":{"get":{"tags":["operations"],"summary":"stream_job_events","description":"Stream job progress as Server-Sent Events. Cost class: fast.\n\nEach frame is a :class:`~ndi_service.app.platform_api.results.JobEvent`\nserialised as ``data: <json>\\n\\n`` with a monotonic ``id: <sequence>``.\nFrames are emitted by polling the job row — the row is the event source,\nso a frame appears whenever ``status`` or ``progress`` changes and the\nstream closes once the job is terminal (or after the same ceiling as the\ninline wait, for a job nothing is advancing).\n\n**REST and CLI only.** MCP has no streaming shape; an MCP agent polls\n``get_job`` instead.\n\n``Last-Event-ID`` offsets the sequence numbering so a reconnecting client\nkeeps a monotonic ``id``; the current state is always re-emitted as the\nfirst frame, because there is no event log to replay from.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    job_id: The job whose events to stream.\n    last_event_id: Resume cursor from the ``Last-Event-ID`` header.\n\nReturns:\n    A ``text/event-stream`` response.\n\nRaises:\n    PlatformError: ``job_not_found`` when the job does not exist.","operationId":"stream_job_events_v1_jobs__job_id__events_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"Last-Event-ID","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last-Event-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/usage":{"get":{"tags":["operations"],"summary":"get_usage","description":"Aggregate job units for a billing period. Cost class: fast.\n\n``credits`` is what the period bills; ``units`` are measured work, including\nfailed and cancelled jobs that are not billed. The admission allowance also counts failed and cancelled\nwork and in-flight reservations, so a ``quota_exceeded`` ``credits_used`` can\nexceed ``credits_total``.\n\n``pages`` and ``bytes_ingested`` aggregate the per-job processing volume\nthe workers record at completion time. ``credits`` sums only jobs whose\nusage is final; ``unfinalized_jobs`` counts the ones still open.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    period_start: Start of the billing window (inclusive).\n    period_end: End of the billing window (inclusive).\n    workspace_id: When set, restrict aggregation to one workspace.\n    group_by: Aggregation key: ``day`` (default), ``kind``,\n        ``workspace``, or ``tenant`` (a partner's roll-up over its child\n        tenants, keyed by ``external_ref``).\n\nReturns:\n    A usage report with per-bucket breakdowns and a total unit count.\n\nRaises:\n    PlatformError: ``invalid_request`` when ``period_end < period_start``,\n        or when ``group_by=tenant`` comes from anything but a partner key\n        acting as itself or names a workspace; ``tenant_required`` when a\n        partner key without ``X-NDI-Tenant`` asks for any other grouping.","operationId":"get_usage_v1_usage_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"period_start","in":"query","required":true,"schema":{"type":"string","format":"date","description":"Start of the billing window, inclusive.","title":"Period Start"},"description":"Start of the billing window, inclusive."},{"name":"period_end","in":"query","required":true,"schema":{"type":"string","format":"date","description":"End of the billing window, inclusive.","title":"Period End"},"description":"End of the billing window, inclusive."},{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Restrict to one workspace.  Omit to aggregate all jobs for this API key.","title":"Workspace Id"},"description":"Restrict to one workspace.  Omit to aggregate all jobs for this API key."},{"name":"group_by","in":"query","required":false,"schema":{"enum":["day","kind","workspace","tenant"],"type":"string","description":"Aggregation key: calendar day, job kind, or workspace. `tenant` is for a partner key sent without `X-NDI-Tenant`: one bucket per child tenant, keyed by its `external_ref`.","default":"day","title":"Group By"},"description":"Aggregation key: calendar day, job kind, or workspace. `tenant` is for a partner key sent without `X-NDI-Tenant`: one bucket per child tenant, keyed by its `external_ref`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ndi_service__app__platform_api__operations__schemas__UsageResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/usage/overview":{"get":{"tags":["operations"],"summary":"get_usage_overview","description":"Dashboard figures for documents processed, in-flight jobs, and latency.\n\nCost class: fast. Documents are succeeded document-operation jobs\n(parse / split / classify / categorize / extract / ground / qa_file)\nfinished in the window. Active and queued counts are a point-in-time\nsnapshot of every job kind. The series is zero-filled so a chart can\nplot it without filling gaps.\n\nArgs:\n    session: Database session.\n    caller: The authenticated tenant.\n    window: Rolling window ending today (UTC).\n\nReturns:\n    Headline figures for the window, the matching prior window, and a\n    daily series of documents processed.","operationId":"get_usage_overview_v1_usage_overview_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"window","in":"query","required":false,"schema":{"enum":["7d","30d","90d"],"type":"string","description":"Rolling window ending today (UTC): 7, 30, or 90 days.","default":"7d","title":"Window"},"description":"Rolling window ending today (UTC): 7, 30, or 90 days."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageOverviewResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/download-links":{"post":{"tags":["operations"],"summary":"create_job_download_link","description":"Sign a short-lived link to one file a succeeded job's result names.\n\nThe file is authorized exactly as its stable ``/jobs/{job_id}/{resource}/{ref}``\nURL authorizes it (per tenant, and for a service key per external account); the link then\nfetches the bytes without API-key headers until ``expires_at``: from S3\nwhen presigned, or from the API's token download on the local backend.","operationId":"create_download_link_v1_jobs__job_id__download_links_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobDownloadLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobDownloadLink"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/content-download":{"post":{"tags":["operations"],"summary":"create_parse_content_download","description":"Start or poll Markdown generation; return a download grant when ready.","operationId":"get_content_download_v1_jobs__job_id__content_download_post","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"sheet_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sheet name; omit for document content.","title":"Sheet Name"},"description":"Sheet name; omit for document content."},{"name":"retry","in":"query","required":false,"schema":{"type":"boolean","description":"Restart a failed Markdown export.","default":false,"title":"Retry"},"description":"Restart a failed Markdown export."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContentDownload"}}},"description":"Accepted"}}}},"/v1/jobs/{job_id}/spreadsheet-rows/{artifact_ref}":{"get":{"tags":["operations"],"summary":"get_parse_rows","description":"Read only the requested rows from the exact Parquet snapshot used by Parse.","operationId":"get_parse_rows_v1_jobs__job_id__spreadsheet_rows__artifact_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"artifact_ref","in":"path","required":true,"schema":{"type":"string","title":"Artifact Ref"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"start_row","in":"query","required":false,"schema":{"type":"integer","maximum":9007199254740991,"minimum":0,"description":"Zero-based first source row.","default":0,"title":"Start Row"},"description":"Zero-based first source row."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum rows to return.","default":50,"title":"Limit"},"description":"Maximum rows to return."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactRowsPage"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/tenants":{"get":{"tags":["tenants"],"summary":"list_tenants","description":"List the partner's tenants, oldest first, disabled ones included. Cost class: cacheable.","operationId":"list_tenants_v1_tenants_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page.","title":"Cursor"},"description":"Opaque cursor from a previous page's `next_cursor`. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Rows per page.","default":50,"title":"Limit"},"description":"Rows per page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_Tenant_"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/tenants/{external_ref}":{"put":{"tags":["tenants"],"summary":"put_tenant","description":"Create the tenant, or update the one with this ``external_ref``.\n\nAnswers 201 when it was created and 200 when it already existed, so it is\nsafe to repeat. Limits above the partner's own are lowered to them.\nCost class: write.","operationId":"put_tenant_v1_tenants__external_ref__put","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"external_ref","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^\\S(.*\\S)?$","description":"The partner's own reference for the tenant, such as its account id.","title":"External Ref"},"description":"The partner's own reference for the tenant, such as its account id."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PutTenantRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"201":{"description":"The tenant was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}}}},"get":{"tags":["tenants"],"summary":"get_tenant","description":"Read one tenant. Cost class: cacheable.","operationId":"get_tenant_v1_tenants__external_ref__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"external_ref","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^\\S(.*\\S)?$","description":"The partner's own reference for the tenant, such as its account id.","title":"External Ref"},"description":"The partner's own reference for the tenant, such as its account id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["tenants"],"summary":"delete_tenant","description":"Disable the tenant and keep its data (default), or with ``purge=true`` delete all of it. Cost class: write.\n\nA disabled tenant is re-enabled with ``PUT`` and ``disabled: false``. A purge cannot be undone: the\ntenant is disabled at once, its jobs are cancelled, and every workspace, file, result, cache entry and\nkey is deleted. Only the content-free billing record (job ids, kinds, timestamps, units, credits) is\nkept. A purge already queued or running is returned as is; one that failed or ended unverified is\nstarted again. Once a purge has verified clean the ``external_ref`` no longer resolves, so a repeat of\nthis call answers ``tenant_not_found`` and a later ``PUT`` creates a new, empty tenant.","operationId":"delete_tenant_v1_tenants__external_ref__delete","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"external_ref","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^\\S(.*\\S)?$","description":"The partner's own reference for the tenant, such as its account id.","title":"External Ref"},"description":"The partner's own reference for the tenant, such as its account id."},{"name":"purge","in":"query","required":false,"schema":{"type":"boolean","description":"True permanently deletes the tenant's data instead of disabling it. Answers 202 with a `tenant_purge` job to poll on GET /v1/jobs/{job_id} without X-NDI-Tenant.","default":false,"title":"Purge"},"description":"True permanently deletes the tenant's data instead of disabling it. Answers 202 with a `tenant_purge` job to poll on GET /v1/jobs/{job_id} without X-NDI-Tenant."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/Tenant"},{"$ref":"#/components/schemas/TenantPurgeJob"}],"title":"Response Delete Tenant V1 Tenants  External Ref  Delete"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"},"202":{"description":"The purge was accepted, or is already running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantPurgeJob"}}}}}}},"/v1/jobs/{job_id}/activity":{"get":{"tags":["operations"],"summary":"get_job_activity","description":"Read bounded private agent activity. Requires the initiating key and unchanged workspace access.","operationId":"get_job_activity_v1_jobs__job_id__activity_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitySnapshot"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/activity/events":{"get":{"tags":["operations"],"summary":"stream_job_activity","description":"Stream thinking and tools. Trimmed cursors reset to a snapshot; the final snapshot carries authoritative job status.","operationId":"stream_job_activity_v1_jobs__job_id__activity_events_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Job identifier.","title":"Job Id"},"description":"Job identifier."},{"name":"last-event-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Replay cursor from a previous activity event or snapshot.","title":"Last-Event-Id"},"description":"Replay cursor from a previous activity event or snapshot."}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/parse-progress":{"get":{"tags":["operations"],"summary":"get_parse_progress","description":"Read bounded ready-unit metadata. Preview content is fetched individually.","operationId":"get_parse_progress_v1_jobs__job_id__parse_progress_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParsePreviewSnapshot"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/parse-progress/events":{"get":{"tags":["operations"],"summary":"stream_parse_progress","description":"Stream current snapshots. Replaying one replaces units by immutable revision.","operationId":"stream_parse_progress_v1_jobs__job_id__parse_progress_events_get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/jobs/{job_id}/parse-progress/parts/{generation}/{revision}":{"get":{"tags":["operations"],"summary":"get_parse_progress_unit","description":"Read one checked preview after rechecking live source and destination access.","operationId":"get_parse_progress_unit_v1_jobs__job_id__parse_progress_parts__generation___revision__get","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"generation","in":"path","required":true,"schema":{"type":"string","title":"Generation"}},{"name":"revision","in":"path","required":true,"schema":{"type":"string","title":"Revision"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParsePreviewContent"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/systemone":{"post":{"tags":["systemone"],"summary":"evaluate_systemone","description":"Answer typed questions about a state in one call, with probabilities.\n\nEach question is a yes/no (`noul`), a pick among named options (`choice`), or a\nposition on an ordered scale (`score`). Nothing is stored and no job is created.\nA deployment without a decision model answers `501 not_implemented`.","operationId":"evaluate_systemone_v1_systemone_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemOneRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemOneResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/cli/device/code":{"post":{"tags":["cli"],"summary":"issue_device_code","operationId":"issue_device_code_v1_cli_device_code_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/cli/device/token":{"post":{"tags":["cli"],"summary":"poll_device_token","operationId":"poll_device_token_v1_cli_device_token_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/playground/parse":{"post":{"tags":["playground"],"summary":"playground_parse","description":"Parse a document under the anonymous playground try budget.","operationId":"playground_parse_v1_playground_parse_post","parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"cf-turnstile-response","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_playground_parse_v1_playground_parse_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/playground/extract":{"post":{"tags":["playground"],"summary":"playground_extract","description":"Extract structured fields under the anonymous playground try budget.","operationId":"playground_extract_v1_playground_extract_post","parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"cf-turnstile-response","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_playground_extract_v1_playground_extract_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/playground/ground":{"post":{"tags":["playground"],"summary":"playground_ground","description":"Locate caller-provided text under the anonymous playground try budget.","operationId":"playground_ground_v1_playground_ground_post","parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"cf-turnstile-response","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_playground_ground_v1_playground_ground_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/playground/split":{"post":{"tags":["playground"],"summary":"playground_split","description":"Split a packet under the anonymous playground try budget.","operationId":"playground_split_v1_playground_split_post","parameters":[{"name":"wait_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":0,"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`.","default":0,"title":"Wait Seconds"},"description":"Bounded inline wait. 0 (the default) returns 202 immediately. Above 0 the route returns 200 with a terminal job if the work finished in time, and 202 with the still-running job if it did not. Either way, read `status`."},{"name":"cf-turnstile-response","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_playground_split_v1_playground_split_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SplitJob"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}},"/v1/playground/quota":{"get":{"tags":["playground"],"summary":"playground_quota","description":"Remaining free tries for this anonymous visitor. Does not consume a try.","operationId":"playground_quota_v1_playground_quota_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaygroundQuota"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request Entity Too Large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"410":{"description":"Gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"424":{"description":"Failed Dependency","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"501":{"description":"Not Implemented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"504":{"description":"Gateway Timeout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/playground/jobs/{job_id}":{"get":{"tags":["playground"],"summary":"playground_get_job","description":"Read a playground job owned by this anonymous visitor.","operationId":"playground_get_job_v1_playground_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}},"delete":{"tags":["playground"],"summary":"playground_delete_job","description":"Cancel and erase the requesting anonymous visitor's job and its uploaded bytes.","operationId":"playground_delete_job_v1_playground_jobs__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"204":{"description":"Successful Response"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Request Entity Too Large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal Server Error"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service Unavailable"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone"},"424":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Failed Dependency"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too Many Requests"},"501":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not Implemented"},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gateway Timeout"}}}}},"components":{"schemas":{"AccessConfig":{"properties":{"labels":{"items":{"$ref":"#/components/schemas/AccessLabel"},"type":"array","maxItems":16,"title":"Labels"},"default_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Label","description":"Applied when the classifier cannot decide. Required whenever labels is non-empty."}},"additionalProperties":false,"type":"object","title":"AccessConfig","description":"A workspace's access-control setting, chosen once at creation.\n\n``labels = []`` is the default and means **no filtering at all** — no\nclassification pass at ingestion, no filter clause at retrieval, and\n``Coverage`` reports nothing. A workspace that does not need document-level\naccess control should not pay for a classification that always returns the\nsame answer.\n\nCoverage reporting is always strict: whenever the gate withholds candidates,\nthe response says so in counts and label names. A silently narrowed answer\nis the failure mode this platform exists to prevent, so there is no opt-out."},"AccessLabel":{"properties":{"name":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Name"},"description":{"type":"string","title":"Description","description":"This string IS the classifier's prompt."}},"additionalProperties":false,"type":"object","required":["name","description"],"title":"AccessLabel","description":"One label in a workspace's unordered list."},"AccessLabelCatalogEntry":{"properties":{"access_label_id":{"type":"string","format":"uuid","title":"Access Label Id"},"name":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Name"},"description":{"type":"string","maxLength":2000,"minLength":1,"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["access_label_id","name","description","created_at","updated_at"],"title":"AccessLabelCatalogEntry","description":"One reusable label in the tenant catalog."},"AccessLabelSource":{"type":"string","enum":["inherited","classified","mirrored"],"title":"AccessLabelSource","description":"Which mechanism produced a document's label.\n\nThe ``default_label`` fallback records as ``inherited``, so an audit can\ntell a real classification from a fallback."},"ActionCounts":{"properties":{"parse":{"$ref":"#/components/schemas/StatusCounts"},"ground":{"$ref":"#/components/schemas/StatusCounts"},"extract_region":{"$ref":"#/components/schemas/StatusCounts"}},"additionalProperties":false,"type":"object","title":"ActionCounts","description":"Per-action status breakdown."},"ActivityDetail":{"properties":{"name":{"type":"string","title":"Name","description":"The tool input being described."},"value":{"type":"string","title":"Value","description":"A bounded, displayable value of the input."}},"additionalProperties":false,"type":"object","required":["name","value"],"title":"ActivityDetail"},"ActivitySnapshot":{"properties":{"type":{"type":"string","const":"snapshot","title":"Type","default":"snapshot"},"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"The job whose agent work is shown."},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Authoritative job state, independent of the trace's availability."},"activities":{"items":{"$ref":"#/components/schemas/AgentActivity"},"type":"array","title":"Activities","description":"Observed work in chronological order."},"cursor":{"type":"string","title":"Cursor","description":"Opaque replay cursor for subscribing after this snapshot.","default":"0-0"},"incomplete":{"type":"boolean","title":"Incomplete","description":"Whether some activity could not be captured or recovered.","default":false}},"additionalProperties":false,"type":"object","required":["job_id","status"],"title":"ActivitySnapshot"},"AgentActivity":{"properties":{"id":{"type":"string","title":"Id","description":"Stable identity of this activity within the job."},"revision":{"type":"integer","title":"Revision","description":"Increasing version of this activity, used to ignore duplicated or older updates.","default":0},"execution_id":{"type":"string","title":"Execution Id","description":"Agent execution that produced this activity."},"step_id":{"type":"string","title":"Step Id","description":"Model request or tool call this activity belongs to."},"attempt":{"type":"integer","title":"Attempt","description":"Execution attempt; a retry never appends to an earlier attempt's thinking."},"kind":{"type":"string","enum":["thinking","tool","message","answer"],"title":"Kind","description":"Whether this is model thinking, a tool, model commentary, or the answer as the agent writes it. An answer is a draft while running, accepted once completed, replaced by a retry once superseded, and handed over when it is an automatic search's fact answer the agent was then asked to settle; the job's result is the published answer."},"name":{"type":"string","title":"Name","description":"Tool name or agent activity label."},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Human-facing description of a recognized tool operation."},"status":{"type":"string","enum":["running","completed","failed","retrying","interrupted","superseded","handed_over"],"title":"Status","description":"The observed state of this activity. Interrupted and superseded activities are incomplete. A handed-over answer is complete but is not the job's: fact search wrote it before the automatic search handed the question to the agent, whose activities follow it."},"started_at":{"type":"string","format":"date-time","title":"Started At","description":"When the activity was first observed."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the activity finished, when known."},"text":{"type":"string","title":"Text","description":"Bounded thinking, commentary, or tool result text.","default":""},"details":{"items":{"$ref":"#/components/schemas/ActivityDetail"},"type":"array","title":"Details","description":"Allowlisted tool inputs, suitable for an expanded view."},"truncated":{"type":"boolean","title":"Truncated","description":"Whether the activity exceeded the retained text budget.","default":false}},"additionalProperties":false,"type":"object","required":["id","execution_id","step_id","attempt","kind","name","status","started_at"],"title":"AgentActivity"},"AnswerCacheInfo":{"properties":{"served_from_cache":{"type":"boolean","title":"Served From Cache","description":"True when this result was re-served from a previously derived answer rather than computed by this run. Always true where this block appears at all."},"source_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Source Job Id","description":"The job whose run originally derived this answer. Null when that job's row has since been reaped — the answer outlives the record of the run that produced it."},"cached_at":{"type":"string","format":"date-time","title":"Cached At","description":"When the answer was originally derived. Read it as the age of the evidence: the workspace may have changed since, which is what the re-check below is for."},"verified_at":{"type":"string","format":"date-time","title":"Verified At","description":"When this run re-checked the cached answer's citations against the workspace and accepted them. Always this run's own time — a cached answer is never served unchecked."}},"additionalProperties":false,"type":"object","required":["served_from_cache","cached_at","verified_at"],"title":"AnswerCacheInfo","description":"How a search answer relates to the workspace's semantic answer cache.\n\nPresent only on a run that served a previously derived answer instead of\nderiving a new one. Everything else on the result — the evidences, the\nreasoning, the tool-call trace, the receipts — describes that ORIGINAL\nderivation, which is what this block exists to say out loud: the answer was\ncomputed once, for a question near enough to this one, under an identical\nscope and an identical access gate, and re-checked against the workspace\nbefore it was handed back. A result with no ``cache`` block was derived by\nthe run that returned it."},"AppliedDecisionWire":{"properties":{"kind":{"type":"string","enum":["role_slot","parse_signature","period_mapping","encoding_mapping"],"title":"Kind","description":"Which kind of reviewable thing it was about."},"key":{"type":"string","title":"Key","description":"The binding slot, or the parse signature — the same key the decision was written under."},"outcome":{"type":"string","enum":["applied","orphaned","conflict"],"title":"Outcome","description":"'applied': folded in. 'orphaned': this reading has nothing open under that key, usually because the data now settles it. 'conflict': the question stands but the answer is not one of the alternatives it offers, so re-answering it is what clears this."},"detail":{"type":"string","title":"Detail","description":"Why, when the outcome is not 'applied'.","default":""}},"additionalProperties":false,"type":"object","required":["kind","key","outcome"],"title":"AppliedDecisionWire","description":"What one reading did with one stored human decision.\n\nPublished because the three outcomes are three different things for a\nreviewer to do next, and an answer that silently had no effect is the one\nstate a review surface must never show as settled."},"ApproveDeviceRequest":{"properties":{"organization_id":{"type":"string","format":"uuid","title":"Organization Id"}},"type":"object","required":["organization_id"],"title":"ApproveDeviceRequest","description":"Which organization the CLI is being authorized for.\n\nRequired, with no default: the approver may belong to several organizations,\nand a guessed one would hand a CLI a credential for the wrong customer."},"ArtifactOutputDetail":{"properties":{"output_id":{"type":"string","format":"uuid","title":"Output Id"},"kind":{"$ref":"#/components/schemas/ArtifactOutputKind"},"path":{"type":"string","title":"Path"},"generation":{"type":"integer","title":"Generation","description":"The file version this output was produced from."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"download_url":{"type":"string","title":"Download Url","description":"Time-limited presigned GET URL that saves the derivative's bytes to disk."},"preview_url":{"type":"string","title":"Preview Url","description":"Time-limited presigned GET URL that a browser renders inline."},"download_url_expires_at":{"type":"string","format":"date-time","title":"Download Url Expires At","description":"When the presigned URLs stop being valid."}},"additionalProperties":false,"type":"object","required":["output_id","kind","path","generation","created_at","download_url","preview_url","download_url_expires_at"],"title":"ArtifactOutputDetail","description":"A live ``derived_file`` output plus short-lived presigned URLs for its bytes.\n\nSearch-index and knowledge-graph outputs are not downloadable this way —\ntheir ``path`` is an opaque index key, not an object in the workspace store."},"ArtifactOutputKind":{"type":"string","enum":["opensearch_doc","kg_document","derived_file"],"title":"ArtifactOutputKind","description":"Where a derivation landed, for the deletion cascade."},"ArtifactOutputMember":{"properties":{"path":{"type":"string","title":"Path","description":"Workspace-relative path of the member object."},"file_name":{"type":"string","title":"File Name","description":"The member's base name."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Object size in bytes."},"download_url":{"type":"string","title":"Download Url","description":"Time-limited presigned GET URL that saves the member to disk."},"preview_url":{"type":"string","title":"Preview Url","description":"Time-limited presigned GET URL that a browser renders inline."}},"additionalProperties":false,"type":"object","required":["path","file_name","size_bytes","download_url","preview_url"],"title":"ArtifactOutputMember","description":"One object inside a derived-output folder, with short-lived fetch URLs.\n\nA recording's ``frames/`` output is registered as one folder, not one row\nper JPEG (root ``AGENTS.md`` → media lane). This is how a caller browses\nthat folder's members without the ledger carrying thousands of rows: the\nobjects are listed from storage on demand and presigned inline."},"ArtifactOutputMembersPage":{"properties":{"members":{"items":{"$ref":"#/components/schemas/ArtifactOutputMember"},"type":"array","title":"Members"},"total_count":{"type":"integer","title":"Total Count","description":"Objects in the folder, across all pages."},"download_url_expires_at":{"type":"string","format":"date-time","title":"Download Url Expires At","description":"When the presigned URLs stop being valid."}},"additionalProperties":false,"type":"object","required":["members","total_count","download_url_expires_at"],"title":"ArtifactOutputMembersPage","description":"A page of the objects inside a derived-output folder.\n\n``total_count`` is the whole folder; ``members`` is the requested window,\nso a large ``frames/`` folder streams into the console a page at a time\ninstead of presigning thousands of URLs at once."},"ArtifactOutputRef":{"properties":{"output_id":{"type":"string","format":"uuid","title":"Output Id"},"kind":{"$ref":"#/components/schemas/ArtifactOutputKind"},"path":{"type":"string","title":"Path"},"generation":{"type":"integer","title":"Generation","description":"The file version this output was produced from."},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"additionalProperties":false,"type":"object","required":["output_id","kind","path","generation","created_at"],"title":"ArtifactOutputRef","description":"One thing a source file produced outside the file store."},"ArtifactRowRun":{"properties":{"start":{"type":"integer","title":"Start","description":"First matched row of the run, 0-based and inclusive."},"end":{"type":"integer","title":"End","description":"Last matched row of the run, 0-based and inclusive."}},"additionalProperties":false,"type":"object","required":["start","end"],"title":"ArtifactRowRun","description":"One inclusive 0-based run of matched rows in the pageable artifact."},"ArtifactRowsPage":{"properties":{"path":{"type":"string","title":"Path"},"start_row":{"type":"integer","title":"Start Row"},"limit":{"type":"integer","title":"Limit"},"total_rows":{"type":"integer","title":"Total Rows"},"columns":{"items":{"$ref":"#/components/schemas/QueryTableColumn"},"type":"array","title":"Columns"},"rows":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Rows"}},"additionalProperties":false,"type":"object","required":["path","start_row","limit","total_rows","columns","rows"],"title":"ArtifactRowsPage","description":"One page of rows from a tabular workspace artifact.\n\nRows are returned in file order, so ``start_row`` is both the request\noffset and the file row number of ``rows[0]`` — callers can label each\nrow with its source row number without another lookup."},"AudioRange":{"properties":{"kind":{"type":"string","const":"audio_range","title":"Kind","default":"audio_range"},"start_ms":{"type":"integer","title":"Start Ms"},"end_ms":{"type":"integer","title":"End Ms"}},"additionalProperties":false,"type":"object","required":["start_ms","end_ms"],"title":"AudioRange"},"AudioRangeMatch":{"properties":{"match_type":{"type":"string","const":"audio_range","title":"Match Type","default":"audio_range"},"start_ms":{"type":"integer","title":"Start Ms"},"end_ms":{"type":"integer","title":"End Ms"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["start_ms","end_ms"],"title":"AudioRangeMatch"},"AutoConfirmation":{"properties":{"candidate_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidate Index","description":"Validated nomination chosen for automatic measurement, if any."},"reason":{"type":"string","title":"Reason","description":"Why discovery confirmed the package or requires review."},"selection_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Selection Id","description":"Confirmed source selection used by the follow-up run."}},"additionalProperties":false,"type":"object","required":["reason"],"title":"AutoConfirmation"},"AutoDecisionWire":{"properties":{"slot":{"type":"string","title":"Slot","description":"Binding question addressed by the automatic checkpoint."},"outcome":{"type":"string","enum":["accepted_sole","accepted_model","suggested","refused","unanswered","nominated"],"title":"Outcome","description":"Checkpoint outcome after deterministic validation; a nominated journal identity was sent to complete-population measurement, which alone can accept it."},"choice":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Choice","description":"Offered alternative selected or suggested."},"confidence":{"anyOf":[{"type":"string","enum":["high","medium","low"]},{"type":"null"}],"title":"Confidence","description":"Model confidence before validation."},"rationale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rationale","description":"Model explanation of its choice."},"detail":{"type":"string","title":"Detail","description":"Validation reason or deterministic evidence.","default":""}},"additionalProperties":false,"type":"object","required":["slot","outcome"],"title":"AutoDecisionWire"},"AutomaticAgentResult":{"properties":{"result_type":{"type":"string","const":"automatic_agent","title":"Result Type","description":"Identifies an automatic search agent result.","default":"automatic_agent"},"answer":{"$ref":"#/components/schemas/DeepSearchV2Result","description":"The agent's grounded answer."},"catalog":{"anyOf":[{"$ref":"#/components/schemas/FilteredSearchResult"},{"type":"null"}],"description":"The catalog entries the agent selected, when it answered with a catalog query."}},"additionalProperties":false,"type":"object","required":["answer"],"title":"AutomaticAgentResult","description":"The automatic search agent's answer, plus its published catalog selection when it made one.\n\n``answer`` is a complete source-level deep-search result (citations, SQL\nreceipts, confidence). ``catalog`` is present when the agent answered with a\nmetadata-catalog query: the server re-executed it authoritatively, and its\n``next_cursor`` pages through this job."},"AutomaticLlmRouter":{"properties":{"kind":{"type":"string","const":"llm","title":"Kind","default":"llm"}},"additionalProperties":false,"type":"object","title":"AutomaticLlmRouter","description":"An LLM chose the route. Its explanation is the routing's ``reason``."},"AutomaticNaceDmRouter":{"properties":{"kind":{"type":"string","const":"nacedm","title":"Kind","default":"nacedm"},"p_agent":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"P Agent","description":"NaceDM's probability that the query needs the investigating agent rather than one fact-search pass; 1 - p_agent is the probability that fact search settles it. Null when the request was too long for NaceDM to score, which routes to the agent."},"decision_point":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Decision Point","description":"The agent runs when ``p_agent`` is at or above this; fact search runs below it."}},"additionalProperties":false,"type":"object","required":["p_agent","decision_point"],"title":"AutomaticNaceDmRouter","description":"NaceDM, the decision model, chose the route by scoring how likely the query needs the agent."},"AutomaticRequestedRouter":{"properties":{"kind":{"type":"string","const":"requested","title":"Kind","default":"requested"}},"additionalProperties":false,"type":"object","title":"AutomaticRequestedRouter","description":"No router ran: the request's ``mode`` named the route, or the workspace had no ingested files."},"AutomaticSearchJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"intelligent_search","title":"Kind","description":"Automatic search orchestration job.","default":"intelligent_search"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/AutomaticSearchResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"AutomaticSearchJob"},"AutomaticSearchRequest":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"The question to answer from the workspace. Surrounding whitespace is stripped; a blank query is refused."},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context","description":"Optional free-form background for the model. It does not change access or retrieval scope."},"path_prefix":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Path Prefix","description":"Narrow the search to this workspace subtree. Omit to search the whole workspace."},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Scope the run to exactly these uploaded files. Every retrieval leg and agent tool sees only these files and the content ingested from them, so nothing else can be read or cited. Each entry names an uploaded source file (never a folder — scope folders with path_prefix; the two add up, so the run covers the folder's files plus these). No limit on how many. Unknown or inaccessible paths are refused up front."},"top_k":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Top K","description":"How many evidences fact search returns, best first; omitted means 6, and the ceiling is 50. A cap on the citation list, not on how much is read. Applies only when fact search answers: the agent chooses its own evidences."},"mode":{"type":"string","enum":["auto","fact","agent"],"title":"Mode","description":"Which route answers. `auto` (the default) lets the router choose fact search for a focused lookup or the agent for anything that needs investigating; when it chooses fact search and fact search cannot settle the question, the agent answers instead, but a 'not found' over material it read whole stands. `fact` runs fact search and `agent` runs the agent, with no routing step and no hand-over. The agent opens on what a navigator over the workspace's files, sections and pages located for the query, then reads, queries tables and locates again until the question is answered; on a workspace in a bring-your-own bucket or customer storage, it opens on what a search of the workspace found and explores with search and file listings instead.","default":"auto"},"output_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Output Schema","description":"A 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."}},"additionalProperties":false,"type":"object","required":["query"],"title":"AutomaticSearchRequest","description":"Body for ``POST /workspaces/{workspace_id}/automatic-search``.\n\nSingle-shot query, optional context, and folder and file scope. In ``auto`` mode the fixed\nrouter selects fact search or the automatic search agent before retrieval, and a fact search\nthat cannot settle the question hands the query to the agent, while a \"not found\" over\nmaterial it read whole stands; ``fact`` and ``agent`` run that route directly, with no\nhand-over. Execution settings are resolved by the service; this\nroute has no effort or clarification controls."},"AutomaticSearchResult":{"properties":{"result_type":{"type":"string","const":"automatic_search","title":"Result Type","description":"Identifies an automatic search result.","default":"automatic_search"},"output":{"oneOf":[{"$ref":"#/components/schemas/IntelligentSearchResult"},{"$ref":"#/components/schemas/AutomaticAgentResult"},{"$ref":"#/components/schemas/DeepSearchV2Result"},{"$ref":"#/components/schemas/FilteredSearchResult"}],"title":"Output","description":"The selected pipeline's native result, preserving citations, completeness, and pagination.","discriminator":{"propertyName":"result_type","mapping":{"automatic_agent":"#/components/schemas/AutomaticAgentResult","deep_search_v2":"#/components/schemas/DeepSearchV2Result","filtered_search":"#/components/schemas/FilteredSearchResult","intelligent_search":"#/components/schemas/IntelligentSearchResult"}}},"output_job_id":{"type":"string","format":"uuid","title":"Output Job Id","description":"Job that owns the output's receipts and cursors; use it to read retained result rows."},"routing":{"$ref":"#/components/schemas/AutomaticSearchRouting","description":"The selected pipeline and the router's explanation."},"usage":{"anyOf":[{"$ref":"#/components/schemas/SearchLlmUsage"},{"type":"null"}],"description":"Complete combined LLM usage when available; null when any stage is unmetered."}},"additionalProperties":false,"type":"object","required":["output","output_job_id","routing"],"title":"AutomaticSearchResult"},"AutomaticSearchRouting":{"properties":{"selected":{"type":"string","enum":["fact","agent","deep","filtered"],"title":"Selected","description":"The route the router chose, the one the request's `mode` named, or `fact` when nothing was searched: the workspace had no ingested files, or the query asked for nothing that a document contains."},"final":{"type":"string","enum":["fact","agent","deep","filtered"],"title":"Final","description":"The pipeline that produced the returned output. It differs from `selected` only in `auto` mode, when the router chose fact search, fact search could not settle the question, and the agent answered instead."},"reason":{"type":"string","title":"Reason","description":"The router's explanation of its decision, or why no router ran."},"router_model":{"type":"string","title":"Router Model","description":"The model used to choose the search pipeline; `none` when no router ran."},"router":{"oneOf":[{"$ref":"#/components/schemas/AutomaticLlmRouter"},{"$ref":"#/components/schemas/AutomaticNaceDmRouter"},{"$ref":"#/components/schemas/AutomaticRequestedRouter"}],"title":"Router","description":"Which router decided, and what it measured: an LLM (its explanation is ``reason``), NaceDM (its probability and decision point), or `requested` when no router ran: the request's `mode` was `fact` or `agent`, or the workspace had no ingested files. Results routed before this field existed read as the LLM.","discriminator":{"propertyName":"kind","mapping":{"llm":"#/components/schemas/AutomaticLlmRouter","nacedm":"#/components/schemas/AutomaticNaceDmRouter","requested":"#/components/schemas/AutomaticRequestedRouter"}}},"router_wall_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Router Wall Ms","description":"Wall time spent selecting the initial route."},"fact_wall_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fact Wall Ms","description":"Wall time spent running fact search, when selected."},"delegated_wall_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delegated Wall Ms","description":"Wall time spent preparing and running the native deep or filtered job."}},"additionalProperties":false,"type":"object","required":["selected","final","reason","router_model"],"title":"AutomaticSearchRouting"},"BasisWire":{"properties":{"name":{"type":"string","title":"Name","description":"The package's own name for this basis, or 'primary' where it labels none."},"shape":{"type":"string","enum":["signed","debit_credit_pair","magnitude_with_direction"],"title":"Shape","description":"The source amount representation."},"debit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Debit","description":"The debit column of the pair, where the basis is a pair."},"credit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Credit","description":"The credit column of the pair, where the basis is a pair."},"signed":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed","description":"The single signed amount column, where the basis has no pair."},"magnitude":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Magnitude","description":"Unsigned amount column of a directed basis."},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Direction","description":"Column indicating debit or credit."},"debit_values":{"items":{"type":"string"},"type":"array","title":"Debit Values","description":"Source codes meaning debit."},"credit_values":{"items":{"type":"string"},"type":"array","title":"Credit Values","description":"Source codes meaning credit."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency","description":"Currency-code column associated with the amount."},"currency_scope":{"items":{"type":"string"},"type":"array","title":"Currency Scope","description":"Source dimensions fixing currency when no code is present."},"balances_per_journal":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balances Per Journal","description":"Share of journals netting to zero measured on this basis specifically."},"ties_to_trial_balance":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ties To Trial Balance","description":"Whether this basis' control totals match the trial balance's movement. Null means nothing has measured it; it is never inferred from a closing balance."}},"additionalProperties":false,"type":"object","required":["name","shape"],"title":"BasisWire","description":"One amount basis the package states, and how well it balances."},"Body_create_upload_v1_uploads_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The document to stage for a granular operation."}},"type":"object","required":["file"],"title":"Body_create_upload_v1_uploads_post"},"Body_playground_extract_v1_playground_extract_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"schema":{"type":"string","title":"Schema"},"parse":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parse","description":"Optional JSON object of parse settings, shaped like the `parse` section of the API request."},"cf-turnstile-response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}},"type":"object","required":["file","schema"],"title":"Body_playground_extract_v1_playground_extract_post"},"Body_playground_ground_v1_playground_ground_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"targets":{"type":"string","title":"Targets"},"parse":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parse","description":"Optional JSON object of parse settings, shaped like the `parse` section of the API request."},"cf-turnstile-response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}},"type":"object","required":["file","targets"],"title":"Body_playground_ground_v1_playground_ground_post"},"Body_playground_parse_v1_playground_parse_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"parse":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parse","description":"Optional JSON object of parse settings, shaped like the `parse` section of the API request."},"cf-turnstile-response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}},"type":"object","required":["file"],"title":"Body_playground_parse_v1_playground_parse_post"},"Body_playground_split_v1_playground_split_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"classes":{"type":"string","title":"Classes"},"parse":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parse","description":"Optional JSON object of parse settings, shaped like the `parse` section of the API request."},"cf-turnstile-response":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cf-Turnstile-Response"}},"type":"object","required":["file","classes"],"title":"Body_playground_split_v1_playground_split_post"},"Body_replace_file_v1_workspaces__workspace_id__files__file_id__put":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"metadata":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metadata","description":"JSON-encoded ReplaceFileRequest. Required for multipart uploads."}},"type":"object","title":"Body_replace_file_v1_workspaces__workspace_id__files__file_id__put"},"Body_upload_file_api_v1_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"The document to stage for later parse/categorize/ground."}},"type":"object","required":["file"],"title":"Body_upload_file_api_v1_upload_post"},"Body_upload_file_v1_workspaces__workspace_id__files_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"metadata":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metadata","description":"JSON-encoded UploadFileRequest. Required for multipart uploads."}},"type":"object","title":"Body_upload_file_v1_workspaces__workspace_id__files_post"},"BooleanCell":{"properties":{"kind":{"type":"string","const":"boolean","title":"Kind","default":"boolean"},"value":{"type":"boolean","title":"Value"}},"additionalProperties":false,"type":"object","required":["value"],"title":"BooleanCell"},"BoundColumn":{"properties":{"slot":{"type":"string","title":"Slot","description":"The slot this column fills, dotted: 'journal_key', 'clocks.created', 'amount_bases[reporting].debit', 'accounts.fsli'."},"path":{"type":"string","title":"Path"},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component"},"table_name":{"type":"string","title":"Table Name"},"column":{"type":"string","title":"Column"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"What the slot additionally states about this column — a clock's true grain, that a basis is the one the trial balance ties to, what a calendar date means."}},"additionalProperties":false,"type":"object","required":["slot","path","table_name","column"],"title":"BoundColumn","description":"One column the run pinned to a definitional slot."},"BoundPeriod":{"properties":{"value":{"type":"string","title":"Value"},"role":{"type":"string","title":"Role","description":"'opening', 'month', 'year_end_adj' or 'total_row'."}},"additionalProperties":false,"type":"object","required":["value","role"],"title":"BoundPeriod","description":"One value of the period axis and the role the run gave it, in period order."},"BoundTable":{"properties":{"role":{"type":"string","title":"Role","description":"The slot it fills: 'journal_lines', 'journal_headers', 'trial_balance', …."},"path":{"type":"string","title":"Path","description":"The uploaded file, e.g. 'ledger/journal.xlsx'."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"The tab, when the file contributed more than one table."},"table_name":{"type":"string","title":"Table Name","description":"The view name this run's SQL referenced it by."}},"additionalProperties":false,"type":"object","required":["role","path","table_name"],"title":"BoundTable","description":"One table of the package, and the role the run bound it to."},"BoundValueSet":{"properties":{"slot":{"type":"string","title":"Slot","description":"'encodings.posted', 'encodings.manual', 'layers.book', …."},"name":{"type":"string","title":"Name","description":"The candidate's name, as a test spec cites it."},"path":{"type":"string","title":"Path"},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component"},"table_name":{"type":"string","title":"Table Name"},"column":{"type":"string","title":"Column"},"values":{"items":{"type":"string"},"type":"array","title":"Values","description":"The values of that column which mean this."},"note":{"type":"string","title":"Note","description":"Where this reading came from — a policy sheet, a flag column, a profiled domain.","default":""}},"additionalProperties":false,"type":"object","required":["slot","name","path","table_name","column"],"title":"BoundValueSet","description":"One column-and-values pin: an encoding candidate, or a layer's membership.\n\nNamed even when its slot carries only one, because the name is what a test\ncites when a slot carries two — which is a state this binding may legitimately\nbe in. Two candidates of ``encodings.manual`` published here means the run\nkept both readings of \"manual\" alive and chose between them per test, which is\nwhat the answer's own working will say."},"CancelJobRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"additionalProperties":false,"type":"object","title":"CancelJobRequest","description":"Body for ``POST /jobs/{job_id}/cancel``.\n\n``reason`` is stored in the job's ``error`` payload so an audit trail\nrecords who cancelled and why.  It is surfaced to the caller on the next\npoll rather than lost."},"CatalogColumnDescriptor":{"properties":{"field":{"type":"string","title":"Field"},"kind":{"type":"string","enum":["text","date","money","number","boolean"],"title":"Kind"},"description":{"type":"string","title":"Description","default":""},"repeated":{"type":"boolean","title":"Repeated","description":"Several values may exist per row (parties, signatories).","default":false},"filtered":{"type":"boolean","title":"Filtered","description":"The published query filtered on this column — or ranked by it under a top-N LIMIT, where ranking decides membership (server-extracted from the SQL, never model-authored). These are the values the matches hinge on, and the first cells worth grounding against their source documents.","default":false},"requested":{"type":"boolean","title":"Requested","description":"The user requested this output field; missing values do not exclude a match.","default":false}},"additionalProperties":false,"type":"object","required":["field","kind"],"title":"CatalogColumnDescriptor","description":"One extracted field the result's rows may carry."},"CategorizeJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"categorize","title":"Kind","default":"categorize"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__CategorizeResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"CategorizeJob"},"CategorizeJobRequest":{"properties":{"file":{"$ref":"#/components/schemas/FileInput","description":"File to categorize. Supported extensions: ``.bmp``, ``.csv``, ``.doc``, ``.docm``, ``.docx``, ``.eml``, ``.htm``, ``.html``, ``.jpeg``, ``.jpg``, ``.json``, ``.log``, ``.md``, ``.mdx``, ``.msg``, ``.oft``, ``.parquet``, ``.pdf``, ``.png``, ``.ppt``, ``.pptx``, ``.tif``, ``.tiff``, ``.txt``, ``.vsd``, ``.vsdx``, ``.webp``, ``.xls``, ``.xlsm``, ``.xlsx``, ``.xml``."},"markdown_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Url","description":"Markdown from a prior parse of the same file; skips the internal parse when present."},"taxonomy":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__schemas__public__Taxonomy"},{"type":"null"}],"description":"Category vocabulary to classify against. Omit to use NDI's default taxonomy."},"idempotency_key":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Idempotency Key"}},"additionalProperties":false,"type":"object","required":["file"],"title":"CategorizeJobRequest","description":"Body for ``POST /categorize`` and ``POST /categorize_async``."},"CategorizeRequestEcho":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"Single document to classify. Exactly one of source or sources must be set."},"sources":{"anyOf":[{"items":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"type":"array","maxItems":50,"minItems":1},{"type":"null"}],"title":"Sources","description":"Batch of documents to classify. Exactly one of source or sources must be set."},"taxonomy":{"anyOf":[{"$ref":"#/components/schemas/CategorizeTaxonomy"},{"type":"null"}],"description":"Caller-provided two-level category tree. Omit to use the domain vocabulary."},"vocabulary":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Vocabulary","description":"Legacy flat category list. Prefer taxonomy or a registered domain_id."},"domain_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain Id","description":"Registered domain vocabulary to classify against when taxonomy is omitted."},"allow_unknown":{"type":"boolean","title":"Allow Unknown","description":"When true, the model may assign none of the above if nothing fits confidently.","default":true},"request_type":{"type":"string","const":"categorize","title":"Request Type","default":"categorize"}},"additionalProperties":false,"type":"object","title":"CategorizeRequestEcho","description":"A stored ``categorize`` request, read back."},"CategorizeTaxonomy":{"properties":{"categories":{"items":{"$ref":"#/components/schemas/CategorizeTaxonomyCategory"},"type":"array","minItems":1,"title":"Categories"},"allow_freeform":{"type":"boolean","title":"Allow Freeform","default":false}},"additionalProperties":false,"type":"object","required":["categories"],"title":"CategorizeTaxonomy"},"CategorizeTaxonomyCategory":{"properties":{"key":{"type":"string","title":"Key"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"subcategories":{"items":{"$ref":"#/components/schemas/CategorizeTaxonomySubcategory"},"type":"array","minItems":1,"title":"Subcategories"}},"additionalProperties":false,"type":"object","required":["key","subcategories"],"title":"CategorizeTaxonomyCategory"},"CategorizeTaxonomySubcategory":{"properties":{"key":{"type":"string","title":"Key"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"additionalProperties":false,"type":"object","required":["key"],"title":"CategorizeTaxonomySubcategory"},"CategorizedCategory":{"properties":{"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"is_freeform_subcategory":{"type":"boolean","title":"Is Freeform Subcategory","default":false}},"type":"object","required":["category","subcategory"],"title":"CategorizedCategory"},"CategorizedSegment":{"properties":{"kind":{"type":"string","const":"document_segment","title":"Kind","default":"document_segment"},"file_name":{"type":"string","title":"File Name"},"page_start":{"type":"integer","title":"Page Start"},"page_end":{"type":"integer","title":"Page End"},"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"is_freeform_subcategory":{"type":"boolean","title":"Is Freeform Subcategory","default":false},"summary":{"type":"string","title":"Summary"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"markdown_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Url"}},"type":"object","required":["file_name","page_start","page_end","category","subcategory","summary"],"title":"CategorizedSegment"},"CategorizedSheet":{"properties":{"kind":{"type":"string","const":"sheet","title":"Kind","default":"sheet"},"file_name":{"type":"string","title":"File Name"},"sheet_name":{"type":"string","title":"Sheet Name"},"categories":{"items":{"$ref":"#/components/schemas/CategorizedCategory"},"type":"array","title":"Categories"},"has_freeform_subcategories":{"type":"boolean","title":"Has Freeform Subcategories","default":false},"summary":{"type":"string","title":"Summary"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"markdown_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Url"}},"type":"object","required":["file_name","sheet_name","categories","summary"],"title":"CategorizedSheet"},"CategoryAssignment":{"properties":{"source_index":{"type":"integer","title":"Source Index","description":"Index into the request's sources list."},"file_name":{"type":"string","title":"File Name"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Null when nothing cleared the threshold."},"confidence":{"type":"number","title":"Confidence"},"evidence":{"anyOf":[{"$ref":"#/components/schemas/Evidence"},{"type":"null"}]},"alternatives":{"items":{"$ref":"#/components/schemas/ScoredCategory"},"type":"array","title":"Alternatives"}},"additionalProperties":false,"type":"object","required":["source_index","file_name","confidence"],"title":"CategoryAssignment"},"CategoryCount":{"properties":{"name":{"type":"string","title":"Name","description":"Category path as assigned at ingestion, e.g. `contracts/agreement`."},"count":{"type":"integer","title":"Count","description":"Number of files in scope with this category."}},"additionalProperties":false,"type":"object","required":["name","count"],"title":"CategoryCount","description":"Count of files assigned to a single document category."},"CheckExecutionWire":{"properties":{"check":{"type":"string","title":"Check","description":"Integrity check identifier."},"table":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table","description":"Ledger table the statement concerns."},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope","description":"Statement scope or column, when applicable."},"status":{"type":"string","enum":["completed","failed","skipped","not_run_due_to_resource_failure"],"title":"Status","description":"Execution outcome, not a data-quality verdict."},"resource_failure":{"anyOf":[{"type":"string","enum":["spill_capacity","memory"]},{"type":"null"}],"title":"Resource Failure","description":"Exhausted engine resource, without source paths or values."},"finding_count":{"type":"integer","title":"Finding Count","description":"Findings returned by this statement, including informational totals.","default":0},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Missing prerequisite or execution error."}},"additionalProperties":false,"type":"object","required":["check","status"],"title":"CheckExecutionWire","description":"One statement's result; completed with no findings is still a measurement."},"ChoiceAnswer":{"properties":{"type":{"type":"string","const":"choice","title":"Type","default":"choice"},"choice":{"type":"string","title":"Choice","description":"The most probable option, by its key in the question's criteria."},"confidence":{"type":"number","title":"Confidence","description":"The decision model's average confidence in this answer, from 0 to 1. It tracks the chosen option's probability but is a separate number; do not derive one from the other."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Every option's probability, keyed by option name."}},"additionalProperties":false,"type":"object","required":["choice","confidence","probabilities"],"title":"ChoiceAnswer"},"ChoiceQuestion":{"properties":{"type":{"type":"string","const":"choice","title":"Type"},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instructions","description":"The question that the options answer."},"criteria":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"propertyNames":{"minLength":1},"type":"object","maxProperties":255,"minProperties":1,"title":"Criteria","description":"The options, keyed by the name the answer returns, each with an optional description."}},"additionalProperties":false,"type":"object","required":["type","criteria"],"title":"ChoiceQuestion","description":"Pick one of named options. Its answer is the chosen option and every option's probability."},"Citation":{"properties":{"location":{"oneOf":[{"$ref":"#/components/schemas/PageRegion"},{"$ref":"#/components/schemas/SheetRange"},{"$ref":"#/components/schemas/TextSpan"},{"$ref":"#/components/schemas/RowRange"},{"$ref":"#/components/schemas/TableRegion"},{"$ref":"#/components/schemas/JsonPointer"}],"title":"Location","description":"Where in the source the value was read.","discriminator":{"propertyName":"kind","mapping":{"json_pointer":"#/components/schemas/JsonPointer","page_region":"#/components/schemas/PageRegion","row_range":"#/components/schemas/RowRange","sheet_range":"#/components/schemas/SheetRange","table_region":"#/components/schemas/TableRegion","text_span":"#/components/schemas/TextSpan"}}},"word_anchor":{"anyOf":[{"$ref":"#/components/schemas/WordAnchor"},{"type":"null"}],"description":"Unique literal occurrence in the original DOCX/DOCM text, when native provenance is available."},"source_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Text","description":"Short quote from the source at that location. Null when citations omit source text."}},"additionalProperties":false,"type":"object","required":["location"],"title":"Citation","description":"Where an extracted value was found, with optional quoted source text."},"Claim":{"properties":{"claim_id":{"type":"string","title":"Claim Id"},"text":{"type":"string","title":"Text"},"hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hint"}},"additionalProperties":false,"type":"object","required":["claim_id","text"],"title":"Claim","description":"Legacy input shape for locating text in a document.\n\n``hint`` is an optional free-text description of where in the document\nthe text is expected to appear; it helps the retrieval step focus."},"ClarificationAnswer":{"properties":{"question":{"type":"string","maxLength":4096,"minLength":1,"title":"Question","description":"The question being answered, as the asking result's `clarification_questions[].question` states it."},"answer":{"anyOf":[{"type":"string","maxLength":4096,"minLength":1},{"type":"null"}],"title":"Answer","description":"The answer: one of the question's `options`, or your own words. Null skips the question; the agent then uses its best judgment and states the assumption in its answer."}},"additionalProperties":false,"type":"object","required":["question"],"title":"ClarificationAnswer","description":"The user's answer to one clarifying question a run asked instead of answering."},"ClarifyingQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question, as the run asked it."},"options":{"items":{"type":"string"},"type":"array","title":"Options","description":"Suggested answers, most likely first. Never exhaustive: the user may always answer in their own words, so no option stands for 'Other'. Empty when the run offered none."}},"additionalProperties":false,"type":"object","required":["question"],"title":"ClarifyingQuestion","description":"One question a run asked back instead of answering."},"ClassificationGapFillDisclosure":{"properties":{"code":{"type":"string","const":"classification_gap_fill","title":"Code"},"filled_pages":{"items":{"type":"integer","minimum":1.0},"type":"array","minItems":1,"title":"Filled Pages","description":"Exact 1-based pages assigned a fallback label because the model left them unclassified."},"fallback_label":{"type":"string","title":"Fallback Label","description":"The classification label applied to every page in filled_pages."}},"additionalProperties":false,"type":"object","required":["code","filled_pages","fallback_label"],"title":"ClassificationGapFillDisclosure","description":"Pages left unclassified by the model were assigned a fallback label.\n\nThe classification still succeeded. Gap-filled pages should be treated\nas lower-confidence assignments rather than absences. One disclosure is\nemitted per distinct fallback label; ``filled_pages`` in that disclosure\nare exactly the pages that received ``fallback_label``."},"ClassificationUnreadPagesDisclosure":{"properties":{"code":{"type":"string","const":"classification_unread_pages","title":"Code"},"unread_pages":{"items":{"type":"integer","minimum":1.0},"type":"array","minItems":1,"title":"Unread Pages","description":"Exact 1-based pages that never entered any model prompt and are returned unknown because no model produced a label for them."}},"additionalProperties":false,"type":"object","required":["code","unread_pages"],"title":"ClassificationUnreadPagesDisclosure","description":"Pages never entered any model prompt and are therefore unknown.\n\nThe classification still succeeded. These pages were dropped by the\ndocument-size batch or token cap, so no model produced a label for them.\nThey carry the reserved unknown label regardless of unknown_policy and\nmust not be read as gap-fill (the model never saw them)."},"ClassifyClass":{"properties":{"id":{"type":"string","title":"Id","description":"Stable caller-defined id returned on labels. Not the reserved other group."},"label":{"type":"string","title":"Label","description":"Human-readable class name shown in results."},"description":{"type":"string","title":"Description","description":"What belongs in this class. Used as model guidance.","default":""},"criteria":{"items":{"type":"string"},"type":"array","title":"Criteria","description":"Optional extra rules the model should apply when scoring this class."},"subclasses":{"items":{"$ref":"#/components/schemas/ClassifySubclass"},"type":"array","title":"Subclasses","description":"Optional finer labels nested under this class."}},"additionalProperties":false,"type":"object","required":["id","label"],"title":"ClassifyClass"},"ClassifyContext":{"properties":{"entity_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Entity Name","description":"The audited entity's name, exactly as it would appear on its own letterhead or as the counterparty on a document it did not issue. Omit when the caller does not know it or it does not apply; direction-sensitive categories are then decided without the hint, as they always have been."},"entity_aliases":{"items":{"type":"string","maxLength":200},"type":"array","maxItems":10,"title":"Entity Aliases","description":"Other names the audited entity is known by in its documents (trading names, former names, abbreviations)."}},"additionalProperties":false,"type":"object","title":"ClassifyContext","description":"Caller-supplied context about the document being classified.\n\nToday this carries only the audited entity's name. Direction-sensitive\ncategories (``supplier_invoice`` vs ``sales_invoice``, ``customer_purchase_order``\nvs ``purchase_order``, and similar pairs across the taxonomy) read the same\ndocument two different ways depending on which side of it is the audited\nentity, and the model is never told that otherwise. Naming it here lets the\ndecision read the document's own buyer/supplier or issuer/recipient cues\nagainst the right side."},"ClassifyJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"classify","title":"Kind","default":"classify"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ClassifyResult"},{"type":"null"}],"description":"Present on succeeded while retained. Also present on a running classify job whose labels were published before the reason finished."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"ClassifyJob"},"ClassifyLabel":{"properties":{"class_id":{"type":"string","title":"Class Id","description":"Id of this label. One of the request classes, or the reserved id other when no requested class matched this slice. other can be the top label when the unit is unknown, or a ranked alternative when some pages did not match. Join request classes on this only when the id is in your classes list."},"subclass_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subclass Id","description":"Subclass id when the assignment is a nested class. Null for a top-level class."},"label":{"type":"string","title":"Label","description":"Display name of that class. Copied from the request for a caller-defined class_id; a freeform name when class_id is other."},"rank":{"type":"integer","minimum":1.0,"title":"Rank","description":"1-based position in this unit's labels after classes are sorted by score. 1 is the assigned (or top) class; later ranks are alternatives kept by output.max_alternatives."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Short model explanation for this label, only when output.include_reason is true. For the top label, why that class was chosen. For a later rank on an abstained unit, why that class was close but not the pick."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"DREX's probability for this label, averaged over the menu orders, when DREX decided it. A document label shared by several segments is the page-weighted mean of the probability recorded on each segment, when every label in the unit has one. Labels are ordered by page coverage. Confidence is per label, so a lower rank can carry a higher confidence. An abstained unit's top label is that mean. Its runner-up labels carry DREX's probability for that runner-up option. When any other label in the unit lacks a DREX probability, every such label uses the share of the unit (pages or sheets) assigned that class. Runner-up labels on an abstained unit do not use that share."}},"additionalProperties":false,"type":"object","required":["class_id","label","rank"],"title":"ClassifyLabel"},"ClassifyOutputOptions":{"properties":{"max_alternatives":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Max Alternatives","description":"How many ranked labels to return per unit, including the winner.","default":3},"include_reason":{"type":"boolean","title":"Include Reason","description":"When true, each label may include a short reason string.","default":true},"delivery":{"type":"string","enum":["progressive","complete"],"title":"Delivery","description":"Progressive publishes labels on the running job before the reason finishes. Complete waits for reasons (or their failure) before any result. Only meaningful when include_reason is true. Does not change the final result.","default":"progressive"}},"additionalProperties":false,"type":"object","title":"ClassifyOutputOptions"},"ClassifyPageRange":{"properties":{"start":{"type":"integer","minimum":1.0,"title":"Start","description":"First page of this unit, 1-based and inclusive."},"end":{"type":"integer","minimum":1.0,"title":"End","description":"Last page of this unit, 1-based and inclusive."}},"additionalProperties":false,"type":"object","required":["start","end"],"title":"ClassifyPageRange"},"ClassifyRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to classify. A parse_result reuses the stored text of a succeeded Parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"context":{"anyOf":[{"$ref":"#/components/schemas/ClassifyContext"},{"type":"null"}],"description":"Caller-supplied context about the document, such as the audited entity's name."},"classes":{"items":{"$ref":"#/components/schemas/ClassifyClass"},"type":"array","minItems":1,"title":"Classes","description":"Caller-defined classes to score the document against."},"granularity":{"type":"string","enum":["document","page"],"title":"Granularity","description":"Score the whole document once, or return one unit per selected page.","default":"document"},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200,"minItems":1},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to classify. Omit to use the whole document. Not supported for spreadsheets (.xlsx, .xls, .xlsm, .csv, .parquet)."},"unknown_policy":{"type":"string","enum":["allow","force_best"],"title":"Unknown Policy","description":"allow may mark a unit unknown. force_best commits an ambiguous unit to one of your classes instead of abstaining. A blank or unreadable page the model sees is assigned the closest listed class — the closed decode vocabulary has no page-state tokens. A unit that could not be parsed is still returned unknown, and so is an empty spreadsheet tab. Pages never read by any model because of document size are also returned unknown and disclosed as classification_unread_pages.","default":"allow"},"output":{"$ref":"#/components/schemas/ClassifyOutputOptions","description":"How many alternative labels to keep and whether to include reasons."}},"additionalProperties":false,"type":"object","required":["source","classes"],"title":"ClassifyRequest","description":"Body for canonical ``POST /v1/classify``.\n\nThe canonical p0 surface classifies one document against caller-provided\nclasses. Internally this still adapts onto the shared categorize workflow."},"ClassifyRequestEcho":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to classify. A parse_result reuses the stored text of a succeeded Parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"context":{"anyOf":[{"$ref":"#/components/schemas/ClassifyContext"},{"type":"null"}],"description":"Caller-supplied context about the document, such as the audited entity's name."},"classes":{"items":{"$ref":"#/components/schemas/ClassifyClass"},"type":"array","minItems":1,"title":"Classes","description":"Caller-defined classes to score the document against."},"granularity":{"type":"string","enum":["document","page"],"title":"Granularity","description":"Score the whole document once, or return one unit per selected page.","default":"document"},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200,"minItems":1},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to classify. Omit to use the whole document. Not supported for spreadsheets (.xlsx, .xls, .xlsm, .csv, .parquet)."},"unknown_policy":{"type":"string","enum":["allow","force_best"],"title":"Unknown Policy","description":"allow may mark a unit unknown. force_best commits an ambiguous unit to one of your classes instead of abstaining. A blank or unreadable page the model sees is assigned the closest listed class — the closed decode vocabulary has no page-state tokens. A unit that could not be parsed is still returned unknown, and so is an empty spreadsheet tab. Pages never read by any model because of document size are also returned unknown and disclosed as classification_unread_pages.","default":"allow"},"output":{"$ref":"#/components/schemas/ClassifyOutputOptions","description":"How many alternative labels to keep and whether to include reasons."},"request_type":{"type":"string","const":"classify","title":"Request Type","default":"classify"}},"additionalProperties":false,"type":"object","required":["source","classes"],"title":"ClassifyRequestEcho","description":"A stored ``classify`` request, read back."},"ClassifyResult":{"properties":{"result_type":{"type":"string","const":"classify","title":"Result Type","default":"classify"},"reason_status":{"type":"string","enum":["pending","complete","failed","not_requested"],"title":"Reason Status","description":"Pending means labels are available while the top-label reason is still running. Complete means the top-label reason finished. Failed means labels stand and the top-label reason did not finish. A runner-up reason that does not finish leaves that label empty and does not by itself fail the job. Reasons that finished are kept. Not_requested means include_reason was false. Always read the job status for cancellation or failure. Default complete so stored results from before this field validate unchanged.","default":"complete"},"labels_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Labels At","description":"When NDI published this job's labels, as an ISO 8601 UTC timestamp, on the same clock as started_at and finished_at. Time to labels is labels_at minus created_at. Reason time is finished_at minus labels_at. Those gaps mean the same thing on every lane. Null on a cache replay, and when labels and the reason arrived together."},"units":{"items":{"$ref":"#/components/schemas/ClassifyUnit"},"type":"array","title":"Units","description":"One scored unit per document, or per page when granularity is page."},"unknown_units":{"type":"integer","title":"Unknown Units","description":"Count of units where no requested class won (declined).","default":0},"pages_read_fraction":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Pages Read Fraction","description":"Fraction of expected pages that entered at least one model prompt, from 0 to 1. Equals 1.0 when no pages were unread; otherwise 1 minus unread over expected.","default":1.0},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Parse settings this run accepted but did not apply, each naming the setting and why, for example a page selection on a file with no pages. Left out when empty."},"disclosures":{"items":{"oneOf":[{"$ref":"#/components/schemas/ClassificationGapFillDisclosure"},{"$ref":"#/components/schemas/ClassificationUnreadPagesDisclosure"},{"$ref":"#/components/schemas/ExtractionNullOnSuccessDisclosure"},{"$ref":"#/components/schemas/ParseVendorProvenanceDisclosure"},{"$ref":"#/components/schemas/ParseFidelityDisclosure"},{"$ref":"#/components/schemas/ContentTruncatedDisclosure"},{"$ref":"#/components/schemas/SourceIncompleteDisclosure"}],"discriminator":{"propertyName":"code","mapping":{"classification_gap_fill":"#/components/schemas/ClassificationGapFillDisclosure","classification_unread_pages":"#/components/schemas/ClassificationUnreadPagesDisclosure","content_truncated":"#/components/schemas/ContentTruncatedDisclosure","extraction_null_on_success":"#/components/schemas/ExtractionNullOnSuccessDisclosure","parse_fidelity":"#/components/schemas/ParseFidelityDisclosure","parse_vendor_provenance":"#/components/schemas/ParseVendorProvenanceDisclosure","source_incomplete":"#/components/schemas/SourceIncompleteDisclosure"}}},"type":"array","title":"Disclosures","description":"Structured signals about how this result was produced. Empty when all behaviours matched what the caller would assume without them."}},"additionalProperties":false,"type":"object","required":["units"],"title":"ClassifyResult"},"ClassifySubclass":{"properties":{"id":{"type":"string","title":"Id"},"label":{"type":"string","title":"Label"},"description":{"type":"string","title":"Description","default":""},"criteria":{"items":{"type":"string"},"type":"array","title":"Criteria"}},"additionalProperties":false,"type":"object","required":["id","label"],"title":"ClassifySubclass"},"ClassifyUnit":{"properties":{"granularity":{"type":"string","enum":["document","page"],"title":"Granularity","description":"Whether this unit scores the whole document or one page range.","default":"document"},"page_range":{"anyOf":[{"$ref":"#/components/schemas/ClassifyPageRange"},{"type":"null"}],"description":"Pages this unit covers when granularity is page. Null for a document-level unit."},"unknown":{"type":"boolean","title":"Unknown","description":"True when no requested class won this unit — including reserved other and pages never read by any model — regardless of unknown_policy. False when a requested class won, even if some pages were other."},"labels":{"items":{"$ref":"#/components/schemas/ClassifyLabel"},"type":"array","title":"Labels","description":"Ranked class assignments for this unit, best first."}},"additionalProperties":false,"type":"object","required":["unknown","labels"],"title":"ClassifyUnit"},"ColumnCardWire":{"properties":{"name":{"type":"string","title":"Name","description":"The column name, as the ingested table spells it."},"data_type":{"type":"string","title":"Data Type","description":"The column's SQL type in the ingested table."},"role":{"type":"string","title":"Role","description":"What this column is once the binding draft settled it — one of the ledger role names (journal_id, account, amount_debit, effective_date, preparer, …) — or, where nothing settled it, the shape class the census could defend (identifier, category, date, amount, free_text, unknown)."},"null_count":{"type":"integer","title":"Null Count","description":"Rows where this column is null."},"blank_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Blank Count","description":"Rows whose text trims to empty, where the deep profiler measured it."},"distinct_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Distinct Count","description":"Distinct values, where the census knows the figure."},"distinct_exact":{"type":"boolean","title":"Distinct Exact","description":"Whether distinct_count was recounted exactly rather than sketched at ingest time."},"min_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Value","description":"Smallest value observed, rendered as text."},"max_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Max Value","description":"Largest value observed, rendered as text."},"values":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValueCountWire"},"type":"array"},{"type":"null"}],"title":"Values","description":"The column's whole value domain with row counts, or null when the census does not know it entire. Capped, so a wide domain is reported as null rather than truncated silently."}},"additionalProperties":false,"type":"object","required":["name","data_type","role","null_count","distinct_exact"],"title":"ColumnCardWire","description":"One column as the stage reads it."},"CommandReceipt":{"properties":{"result_id":{"type":"string","title":"Result Id","description":"Job-scoped identity of a recorded shell execution."},"command":{"type":"string","title":"Command","description":"The shell command as executed."},"stdout":{"type":"string","title":"Stdout","description":"The complete standard output of the successful command."},"outputs":{"additionalProperties":{"type":"string"},"type":"object","title":"Outputs","description":"Named scalar outputs parsed from stdout; a scalar output is named value."}},"additionalProperties":false,"type":"object","required":["result_id","command","stdout","outputs"],"title":"CommandReceipt"},"ConfidenceLevel":{"type":"string","enum":["certain","very_high","high","medium","low","speculative"],"title":"ConfidenceLevel","description":"How well the retrieved evidence supports the answer, worst-case wins."},"ConsoleDeviceSessionResponse":{"properties":{"user_code":{"type":"string","title":"User Code"},"status":{"type":"string","title":"Status"}},"type":"object","required":["user_code","status"],"title":"ConsoleDeviceSessionResponse","description":"Pending session metadata for the approve page — never the API key."},"ConsoleKeyResponse":{"properties":{"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"key_prefix":{"type":"string","title":"Key Prefix"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"full_key":{"type":"string","title":"Full Key","description":"The complete API key, shown ONLY once — it is never recoverable."}},"type":"object","required":["organization_id","key_prefix","expires_at","full_key"],"title":"ConsoleKeyResponse","description":"A short-lived data-plane key minted for the signed-in console member."},"ConsoleSessionResponse":{"properties":{"created":{"type":"boolean","title":"Created","description":"True when this sign-in wrote something: a new identity, a membership from an accepted invitation, or the default organization for an identity that belonged nowhere."},"user":{"$ref":"#/components/schemas/ConsoleUserInfo"},"organizations":{"items":{"$ref":"#/components/schemas/OrganizationInfo"},"type":"array","title":"Organizations","description":"Every organization the user belongs to. Empty means they belong to none yet."},"can_create_organization":{"type":"boolean","title":"Can Create Organization","description":"Whether this user may still create an organization themselves."},"can_run_evals":{"type":"boolean","title":"Can Run Evals","description":"Whether this identity may use the eval console (a Nace staff email domain). The console hides the section when false; the routes enforce it regardless.","default":false}},"type":"object","required":["created","user","organizations","can_create_organization"],"title":"ConsoleSessionResponse","description":"Response for ``POST /console/session``."},"ConsoleUserInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","created_at"],"title":"ConsoleUserInfo","description":"The signed-in OIDC identity.\n\nCarries no role: a role is held per organization, so it lives on\n:class:`~ndi_service.app.schemas.organization.OrganizationInfo`."},"ContentConditionMatch":{"properties":{"condition":{"type":"string","title":"Condition","description":"The content condition evaluated after catalog filtering."},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value","description":"Observed source value supporting the match, when available as a short value."},"evidences":{"items":{"$ref":"#/components/schemas/ContentEvidence"},"type":"array","minItems":1,"title":"Evidences","description":"Source passages supporting this row's satisfaction of the condition."}},"additionalProperties":false,"type":"object","required":["condition","evidences"],"title":"ContentConditionMatch","description":"A verified content criterion attached to the matching result row."},"ContentDownload":{"properties":{"status":{"type":"string","enum":["pending","ready","failed"],"title":"Status","description":"Export state; pending requests should be polled again.","default":"ready"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Signed download URL when ready. Treat it as a temporary credential."},"expires_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires At","description":"Expiry of the ready download grant, as Unix epoch seconds."},"retry_after_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Retry After Seconds","description":"Suggested delay before polling a pending export."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Safe export failure explanation, when failed."}},"additionalProperties":false,"type":"object","title":"ContentDownload","description":"Short-lived URL for a native browser download without API-key headers."},"ContentEvidence":{"properties":{"source_path":{"type":"string","title":"Source Path"},"source_file_id":{"type":"string","format":"uuid","title":"Source File Id"},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component"},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page"},"a1_range":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"A1 Range","description":"The exact native cell or range containing this quotation, within component."},"quote":{"type":"string","title":"Quote"}},"additionalProperties":false,"type":"object","required":["source_path","source_file_id","quote"],"title":"ContentEvidence","description":"One passage that satisfied the residual content condition, server-verified."},"ContentTruncatedDisclosure":{"properties":{"code":{"type":"string","const":"content_truncated","title":"Code"},"target":{"$ref":"#/components/schemas/TruncationTarget","description":"Processing area whose input or output was reduced before the result was produced."},"unit":{"$ref":"#/components/schemas/TruncationUnit","description":"Unit shared by original_size and retained_size."},"original_size":{"type":"integer","minimum":1.0,"title":"Original Size","description":"Size of the content before the reduction was applied."},"retained_size":{"type":"integer","minimum":0.0,"title":"Retained Size","description":"Size of the content retained after the reduction was applied."}},"additionalProperties":false,"type":"object","required":["code","target","unit","original_size","retained_size"],"title":"ContentTruncatedDisclosure","description":"A user-visible content field was truncated before being included in the result.\n\nThe result is otherwise complete. ``unit`` states how both size fields\nshould be interpreted."},"ContentVerificationSummary":{"properties":{"condition":{"type":"string","title":"Condition","description":"The content condition checked on catalog-selected candidates."},"candidates":{"type":"integer","minimum":0.0,"title":"Candidates","description":"Catalog candidates considered by the cited content check."},"unverified_candidates":{"type":"integer","minimum":0.0,"title":"Unverified Candidates","description":"Candidates whose condition could neither be established nor ruled out, including bounds or unavailable evidence. These records are excluded from confirmed matches, not treated as non-matches."}},"additionalProperties":false,"type":"object","required":["condition","candidates","unverified_candidates"],"title":"ContentVerificationSummary","description":"Coverage of the bounded content check, separate from catalog coverage."},"ConventionsWire":{"properties":{"ledger_tables":{"items":{"type":"string"},"type":"array","title":"Ledger Tables","description":"The tables that hold the journal lines under test."},"header_table":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Header Table","description":"The journal-header table, where the package has one."},"journal_key":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Journal Key","description":"The columns one journal entry is identified by."},"journal_key_aliases":{"items":{"type":"string"},"type":"array","title":"Journal Key Aliases","description":"Other scalar columns proven to identify exactly the same groups of ledger rows."},"account_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Column","description":"The visible account column selected for journal lines."},"account_columns":{"items":{"type":"string"},"type":"array","title":"Account Columns","description":"The ordered account identity selected for journal lines."},"account_scope_columns":{"items":{"type":"string"},"type":"array","title":"Account Scope Columns","description":"Hidden source dimensions used to keep segmented accounts distinct."},"account_identity_status":{"type":"string","enum":["legacy","scalar","scoped","blocked","unmeasured"],"title":"Account Identity Status","description":"Whether complete-population evidence proved the account identity safe.","default":"legacy"},"account_identity_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Identity Reason","description":"Aggregate account-identity proof or refusal reason."},"bases":{"items":{"$ref":"#/components/schemas/BasisWire"},"type":"array","title":"Bases","description":"Every amount basis the package spells, with its balance measurement."},"date_roles":{"additionalProperties":{"type":"string"},"type":"object","title":"Date Roles","description":"Each date role the stage settled mapped to the column that fills it, using the role vocabulary."},"auxiliary_columns":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Auxiliary Columns","description":"Non-exclusive SAP meanings and their qualified physical columns."},"role_sources":{"additionalProperties":{"$ref":"#/components/schemas/RoleSourceWire"},"type":"object","title":"Role Sources","description":"Physical owner and evidence per settled role."},"unavailable_tests":{"items":{"type":"string"},"type":"array","title":"Unavailable Tests","description":"Tests this package cannot run because a role they need is absent. Stated rather than left silent, since silence about an untested condition reads as a clean result."},"header_columns":{"items":{"type":"string"},"type":"array","title":"Header Columns","description":"Attributes the journal key determines — one value per journal."},"line_columns":{"items":{"type":"string"},"type":"array","title":"Line Columns","description":"Attributes that vary within a single journal."},"entity_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Column","description":"The column carrying the reporting entity, where one is settled."},"entity_values":{"items":{"type":"string"},"type":"array","title":"Entity Values","description":"The entity values present, where the census knows the domain entire."},"period_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Column","description":"The column carrying the accounting period axis."},"period_values":{"items":{"type":"string"},"type":"array","title":"Period Values","description":"The period values present, where the census knows the domain entire."},"layer_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Layer Column","description":"The book or overlay axis, where exactly one column carries one. Its split stays open."},"one_sided_entries":{"type":"string","enum":["none","present","unknown"],"title":"One Sided Entries","description":"Whether the package holds journals that post to one side only, or whether nothing measured it."}},"additionalProperties":false,"type":"object","required":["ledger_tables","bases","date_roles","unavailable_tests","header_columns","line_columns","entity_values","period_values","one_sided_entries"],"title":"ConventionsWire","description":"What this package's numbers mean, in the terms every test is defined in."},"CostLine":{"properties":{"operation":{"type":"string","enum":["parse","split","classify","extract","ground"],"title":"Operation","description":"The work this dollar amount pays for."},"quantity":{"type":"integer","minimum":0.0,"title":"Quantity","description":"The number of page-equivalents or Ground targets priced by this line."},"unit":{"type":"string","enum":["page","item"],"title":"Unit","description":"The quantity's billing unit: page-equivalent or Ground target."},"execution":{"type":"string","enum":["fresh","reused"],"title":"Execution","description":"The price tier: normal work or verified, billing-eligible tenant reuse; not provider token caching."},"unit_price_usd":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,9}0*$","title":"Unit Price Usd","description":"USD per unit under the job's pinned price sheet, serialized as a decimal string."},"amount_usd":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,9}0*$","title":"Amount Usd","description":"This line's USD amount: quantity multiplied by unit_price_usd, serialized as a decimal string."},"reuse_reason":{"anyOf":[{"type":"string","enum":["reused_parse","repeat_of_job"]},{"type":"null"}],"title":"Reuse Reason","description":"Why the lower reuse rate applies; null on a normal-price line."}},"additionalProperties":false,"type":"object","required":["operation","quantity","unit","execution","unit_price_usd","amount_usd"],"title":"CostLine","description":"One independently priced part of a perception job."},"Coverage":{"properties":{"restricted_candidates":{"type":"integer","title":"Restricted Candidates","default":0},"labels_required":{"items":{"type":"string"},"type":"array","title":"Labels Required","description":"Which labels would have been needed to see the withheld candidates."},"request_access_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Access Hint"}},"additionalProperties":false,"type":"object","title":"Coverage","description":"What the access gate withheld, in counts and label names only.\n\nNever a name, path, or fragment of withheld content. Naming the labels\nleaks nothing the caller cannot already read from the workspace config, and\nit turns \"some results were withheld\" into an actionable request."},"CreateAccessLabelRequest":{"properties":{"name":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Name"},"description":{"type":"string","maxLength":2000,"minLength":1,"title":"Description"}},"additionalProperties":false,"type":"object","required":["name","description"],"title":"CreateAccessLabelRequest"},"CreateDomainRequest":{"properties":{"slug":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Slug"},"display_name":{"type":"string","maxLength":200,"minLength":1,"title":"Display Name"},"taxonomy":{"$ref":"#/components/schemas/ndi_service__app__platform_api__domains__schemas__Taxonomy"}},"additionalProperties":false,"type":"object","required":["slug","display_name","taxonomy"],"title":"CreateDomainRequest","description":"Creates a taxonomy ``draft`` at version 1 in the caller's tenant."},"CreateEvalRunRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name"},"params":{"$ref":"#/components/schemas/EvalRunParams"}},"type":"object","title":"CreateEvalRunRequest"},"CreateExtractionSchemaRequest":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"},"schema":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Schema"}},"additionalProperties":false,"type":"object","required":["name","schema"],"title":"CreateExtractionSchemaRequest","description":"Create version 1 of a new schema family with a server-generated id."},"CreateExtractionSchemaVersionRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"},"schema":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Schema"}},"additionalProperties":false,"type":"object","required":["schema"],"title":"CreateExtractionSchemaVersionRequest","description":"Append the next immutable version of an existing tenant-owned family.\n\nOmitted ``name`` / ``description`` inherit the previous version's values so\ncallers can ship a schema-only change without restating metadata."},"CreateInvitationRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"type":"string","enum":["owner","admin","member"],"title":"Role","default":"member"}},"type":"object","required":["email"],"title":"CreateInvitationRequest","description":"Invite an email address. The console emails a seven-day passwordless link."},"CreateKeyRequest":{"properties":{"name":{"type":"string","maxLength":64,"minLength":1,"title":"Name","description":"How this key is identified in listings, e.g. 'ci' or 'ingestion-prod'."},"description":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Description","description":"Optional note about what the key is for, shown under its name in listings."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When the key should stop working, as an offset-aware timestamp. Null means never. Must be in the future."}},"type":"object","required":["name","expires_at"],"title":"CreateKeyRequest","description":"Mint one named key. Both fields are required, ``expires_at`` explicitly so.\n\nSending ``\"expires_at\": null`` is how a caller asks for a key that never\nexpires. It has no default, so a key's lifetime is always a choice somebody\nmade rather than one they never saw.\n\nThe timestamp must carry an offset. Guessing a zone for a bare\n``2030-01-01T00:00:00`` would move a key's death by up to a day, so the\ncaller is asked to say which moment they mean."},"CreateKeyResponse":{"properties":{"key":{"$ref":"#/components/schemas/OrganizationKeyInfo"},"full_key":{"type":"string","title":"Full Key","description":"The complete API key, shown ONLY once — it is never recoverable."}},"type":"object","required":["key","full_key"],"title":"CreateKeyResponse"},"CreateOrganizationRequest":{"properties":{"display_name":{"type":"string","maxLength":128,"minLength":1,"title":"Display Name","description":"What to call it, e.g. 'Acme Audit' or 'Yera Personal'."}},"type":"object","required":["display_name"],"title":"CreateOrganizationRequest","description":"Create an organization owned by the signed-in user. No API key is minted."},"CreateUploadGrantRequest":{"properties":{"path":{"anyOf":[{"type":"string","maxLength":1024,"minLength":1,"pattern":"^[^/]","description":"Pin the upload to exactly this destination path. The platform-reserved '.workspace' subtree is not allowed. Omit to let the holder choose."},{"type":"null"}],"title":"Path"},"max_bytes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Bytes","description":"Per-grant byte cap, tighter than the service-wide cap for the pinned path. Omit to freeze the grant at that cap; an unpinned grant freezes at NDI_MAX_UPLOAD_BYTES."},"total_size_bytes":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total Size Bytes","description":"Exact expected upload size frozen into the grant. Distinct from max_bytes: a short body is rejected even when it fits under the cap."},"ttl_seconds":{"type":"integer","maximum":3600.0,"minimum":1.0,"title":"Ttl Seconds","description":"How long the grant verifies, in seconds.","default":3600}},"additionalProperties":false,"type":"object","title":"CreateUploadGrantRequest","description":"Body for ``POST /workspaces/{workspace_id}/upload-grants``.\n\nEvery field narrows what the grant's holder may do; an empty body mints a\ngrant for one upload anywhere in the workspace with the default TTL."},"CreateUploadSessionRequest":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"pattern":"^[^/]","title":"Path","description":"Destination path inside the workspace. Relative, must not start with '/', and must not use the platform-reserved '.workspace' subtree."},"total_size_bytes":{"type":"integer","exclusiveMinimum":0.0,"title":"Total Size Bytes","description":"Exact total size of the file, across every part."},"source_modified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Source Modified At","description":"Filesystem modification time reported by the uploading client. Informational only: callers control this value, so it is not audit evidence."},"labels":{"additionalProperties":{"type":"string"},"type":"object","title":"Labels","description":"Caller-supplied metadata, stored verbatim."},"graph_inclusion":{"type":"string","enum":["auto","include","exclude"],"title":"Graph Inclusion","description":"Whether this file joins the knowledge-graph corpus. 'auto' follows the workspace's KG exclusion rules; 'include'/'exclude' override them for this file.","default":"auto"},"on_conflict":{"type":"string","enum":["reject","new_version"],"title":"On Conflict","description":"'reject' raises path_conflict at complete-time when a file already exists at this path. 'new_version' increments the version and stamps replaced_at on the previous one.","default":"reject"},"ttl_seconds":{"type":"integer","maximum":5400.0,"minimum":1.0,"title":"Ttl Seconds","description":"How long the session accepts parts before it expires unfinished.","default":5400}},"additionalProperties":false,"type":"object","required":["path","total_size_bytes"],"title":"CreateUploadSessionRequest","description":"Body for ``POST /workspaces/{workspace_id}/upload-sessions``.\n\nSame destination/conflict/labelling contract as ``UploadFileRequest`` —\nthis is the chunked entry point to the exact same ledger write, for a\nfile large enough (or a link flaky enough) that one unretried multipart\nPOST is the wrong shape. ``total_size_bytes`` is required and checked\nbyte-for-byte at ``complete``: nothing here is trusted on faith."},"CreateUploadSessionResponse":{"properties":{"session_id":{"type":"string","format":"uuid","title":"Session Id"},"session_token":{"type":"string","title":"Session Token","description":"Send in the X-Upload-Token header of every subsequent request."},"chunk_size":{"type":"integer","title":"Chunk Size","description":"Upload every part at exactly this size, except a shorter final part."},"total_parts":{"type":"integer","title":"Total Parts","description":"ceil(total_size_bytes / chunk_size) — the parts complete() expects."},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When the session stops accepting parts."}},"additionalProperties":false,"type":"object","required":["session_id","session_token","chunk_size","total_parts","expires_at"],"title":"CreateUploadSessionResponse","description":"A newly created upload session, ready to accept parts.\n\n``session_token`` is sent as ``X-Upload-Token`` on every subsequent\nrequest against this session (parts, status, complete, abort) — the\nupload grant or API key used to create the session is not sent again."},"CreateWorkspaceRequest":{"properties":{"storage":{"anyOf":[{"$ref":"#/components/schemas/ExternalWorkspaceStorageInput"},{"type":"null"}],"description":"Bind validated customer storage; omit to use the tenant default."},"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"domain_slug":{"type":"string","title":"Domain Slug","description":"Domain vocabulary. Resolved to the latest published version unless pinned.","default":"generic"},"domain_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Domain Version","description":"Pin a specific domain version. Omit to take the latest published."},"access":{"$ref":"#/components/schemas/AccessConfig","description":"Access-label configuration. ``labels=[]`` (the default) disables filtering entirely."},"knowledge_graph":{"$ref":"#/components/schemas/KnowledgeGraphConfig","description":"Knowledge-graph build policy. Builds are on demand unless this asks for automatic ones, so a workspace only pays for a graph someone wanted."},"currency":{"$ref":"#/components/schemas/CurrencyPolicy","description":"How to read amounts whose currency the documents leave open. Defaults to USD; send default=null to assume nothing."},"ledger_understanding":{"$ref":"#/components/schemas/LedgerUnderstandingConfig","description":"When to understand the workspace's general ledger — table and column roles, the journal key and its balance proof, and the integrity battery. Runs automatically for a workspace that holds a journal-line table, and costs one that does not nothing."},"global_context":{"type":"string","maxLength":20000,"title":"Global Context","description":"Standing background for every query in this workspace — how its journals are keyed, which entity it covers, what an auditor already knows. A je-testing or search request that omits `context` runs with this text; a request that sends `context` replaces it for that run, and `\"\"` runs with none. Empty means none. Surrounding whitespace is stripped.","default":""}},"additionalProperties":false,"type":"object","required":["name"],"title":"CreateWorkspaceRequest","description":"Provision a new workspace.\n\nEvery field has a default so a caller who knows nothing creates a working\nworkspace with just a name. Creating a workspace ingests nothing and costs\nnothing — it is a namespace plus a configuration."},"CurrencyPolicy":{"properties":{"default":{"anyOf":[{"type":"string","pattern":"^[A-Z]{3}$","description":"ISO 4217 code, e.g. 'USD'."},{"type":"null"}],"title":"Default","description":"Which currency to read when a document marks an amount with a symbol that names several currencies ($ for USD/CAD/AUD/…, ¥ for JPY/CNY, kr for SEK/NOK/…) and states no ISO code anywhere. Defaults to 'USD'; set another ISO code to change it, or null to leave such an amount ambiguous (and so unfilterable). A resolved amount is recorded with 'currency_source: assumed' in the file's metadata so the assumption stays visible. It only ever disambiguates, never invents: an amount written '€900' is still EUR, a '$900' amount in a EUR-default workspace stays ambiguous (a dollar sign is not a way of writing euros), and an amount carrying no currency marker at all is never given one.","default":"USD"}},"additionalProperties":false,"type":"object","title":"CurrencyPolicy","description":"How this workspace's documents should be read where they leave a currency open.\n\nExtraction never converts an amount and never invents a currency: one whose\ncurrency the source does not state is recorded as ``ambiguous`` with no\nvalue, so it matches no amount filter. New workspaces default to\n``DEFAULT_WORKSPACE_CURRENCY`` (USD), so a corpus that writes every total as a\nbare ``$900.00`` and names a currency nowhere is filterable out of the box.\nSet ``default`` to another ISO code to change the reading, or to ``null`` to\nassume nothing — an amount whose currency the source never states then stays\n``ambiguous`` rather than being read as USD."},"DatasetReference":{"properties":{"repository":{"type":"string","title":"Repository"},"revision":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revision"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"qualification":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualification"}},"type":"object","required":["repository"],"title":"DatasetReference","description":"Exact corpus snapshot behind a published checkpoint."},"DateCell":{"properties":{"kind":{"type":"string","const":"date","title":"Kind","default":"date"},"date":{"type":"string","title":"Date","description":"ISO 8601 calendar date."}},"additionalProperties":false,"type":"object","required":["date"],"title":"DateCell"},"DeepSearchClaimReference":{"properties":{"kind":{"type":"string","enum":["result_cell","result_count","result_absence","command_result"],"title":"Kind","description":"How the result supports the claim."},"result_id":{"type":"string","title":"Result Id","description":"The matching result_id in sql_receipts or command_receipts."},"row":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row","description":"0-based result row for a cell claim; null otherwise."},"column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column","description":"Result column for a cell claim; null otherwise."},"cited_value":{"type":"string","title":"Cited Value","description":"The exact value checked against the retained result."}},"additionalProperties":false,"type":"object","required":["kind","result_id","cited_value"],"title":"DeepSearchClaimReference","description":"A claim's address within a published SQL or command execution receipt."},"DeepSearchCoverage":{"properties":{"deliverable_id":{"type":"string","title":"Deliverable Id","description":"Unique id for one requested output."},"description":{"type":"string","title":"Description","description":"Requested output this item accounts for."},"basis":{"type":"string","enum":["sql","document","calculation"],"title":"Basis","description":"Whether support is retained SQL or document retrieval; document absence is not a SQL-verified proof.","default":"sql"},"evidence_indices":{"items":{"type":"integer"},"type":"array","title":"Evidence Indices","description":"Zero-based indices into this result's published evidences supporting a document deliverable."},"status":{"type":"string","enum":["answered","partial","unanswerable"],"title":"Status","description":"Whether the output was fully answerable."},"claim_ids":{"items":{"type":"string"},"type":"array","title":"Claim Ids","description":"Verified claims satisfying this output."},"complete_result_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Complete Result Id","description":"Receipt containing the requested complete listing; page it when its attached breakdown is truncated."},"complete_result":{"anyOf":[{"$ref":"#/components/schemas/JetBreakdown"},{"type":"null"}],"description":"Server-rendered rows from the retained listing, never copied from model prose."},"missing_inputs":{"items":{"type":"string"},"type":"array","title":"Missing Inputs","description":"Inputs preventing a complete answer."},"absence_result_ids":{"items":{"type":"string"},"type":"array","title":"Absence Result Ids","description":"Zero-row receipts proving those inputs absent."}},"additionalProperties":false,"type":"object","required":["deliverable_id","description","status"],"title":"DeepSearchCoverage","description":"How one requested deliverable was answered, partially answered, or refused."},"DeepSearchJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","enum":["intelligent_search","deep_search_v2"],"title":"Kind","description":"deep_search_v2, the source-level agent — every new run, scoped or not. intelligent_search appears only on deep-search jobs created before the 2026-09 consolidation retired the classic scoped loop; those stay readable here."},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/IntelligentSearchResult"},{"$ref":"#/components/schemas/DeepSearchV2Result"},{"type":"null"}],"title":"Result","description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","kind","status","created_at"],"title":"DeepSearchJob","description":"The consolidated deep-search route's response shape.\n\nOne route, one public ``effort`` knob, one implementation: every new run —\nscoped or not — lands the source-level ``deep_search_v2`` result (answer\nplus SQL receipts). ``intelligent_search`` stays in the ``kind`` union only\nso jobs created by the retired classic loop remain readable via\n``GET /jobs``; ``result_type`` inside the result repeats the discriminator,\nso a caller reading only the result payload can still tell them apart."},"DeepSearchRequest":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"What to answer, in the caller's own words. Stripped before its length is checked; a blank query is refused rather than run."},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context","description":"Free-form background for the model — the engagement, the entity, what the caller already knows. It informs the answer; it does not widen or narrow which files the caller may see."},"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Put every uploaded file under one folder subtree, workspace-relative, in the run's scope; `paths`, where the body takes it, adds more files. Omit both for the whole workspace."},"allow_clarification":{"type":"boolean","title":"Allow Clarification","description":"Let the agent finish the run with clarifying questions instead of an answer, when the query is genuinely ambiguous and the ambiguity materially changes the answer. The result then carries the questions in `clarification_questions` (and as text in `clarification`), with `answer` and `reasoning` null and `evidences` empty; answer them in the same thread via the result's `session_id`, with `clarification_answers` or a follow-up query. Off, the default, means the agent always answers with its best reading, stated in the answer.","default":false},"clarification_answers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ClarificationAnswer"},"type":"array","maxItems":2,"minItems":1},{"type":"null"}],"title":"Clarification Answers","description":"Answers to the clarifying questions this thread's last turn asked (its result's `clarification_questions`): one entry per question, in order. Send them with that turn's `session_id` and its `query`; the agent then answers that query with the answers applied, and sees which answer belongs to which of its questions. Any other follow-up query in the thread works too — this field is the structured way to answer. Cannot be combined with `allow_clarification`: a run answering questions does not ask again."},"effort":{"anyOf":[{"type":"string","enum":["high","medium","low"]},{"type":"null"}],"title":"Effort","description":"Deprecated and ignored: the service resolves the run's configuration itself. Accepted so clients released before the effort levels were retired keep working; omit it.","deprecated":true},"use_kg":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Use Kg","description":"Deprecated and ignored: the service decides whether the knowledge graph is consulted. Accepted so clients released before it was retired keep working; omit it.","deprecated":true},"include_answer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Answer","description":"Deprecated and ignored: every run answers. Accepted so clients released before it was retired keep working; omit it.","deprecated":true},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Scope the run to exactly these uploaded files. Every retrieval tool the agent runs — search, listings, reads, table queries, the shell — sees only these files and the content ingested from them; everything else is invisible to the run. Each entry names an uploaded source file (never a folder — scope folders with path_prefix; the two add up, so the run covers the folder's files plus these). No limit on how many. Unknown or inaccessible paths are refused up front."},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"Continue a prior deep-search conversation: the id echoed on an earlier result's `session_id`. With the same folder/file scope and access grants, the agent resumes that thread's context. A changed scope or grants starts a fresh conversation and returns a new `session_id`; older threads without a scope snapshot also restart. Omit to start a new thread. Only the API key that started the thread may continue it; a thread whose turn is still running returns 409 session_busy."},"surface":{"type":"string","enum":["deep_search","qa","workbook"],"title":"Surface","description":"Which console history this run belongs to. It does not pick the agent, the chassis, or the engine: an omitted value is `deep_search` (the public API and the Deep Search page). The NDI console sends `qa` or `workbook` so Activity and thread lists can split those skins. A follow-up (`session_id`) inherits the thread head's surface; a conflicting value on the follow-up body is ignored.","default":"deep_search"},"output_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Output Schema","description":"A 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."}},"additionalProperties":false,"type":"object","required":["query"],"title":"DeepSearchRequest","description":"Body for ``POST /workspaces/{workspace_id}/deep-search`` — every agentic search.\n\nEvery run uses one configuration (see\n:mod:`~ndi_service.app.platform_api.intelligent_search.effort`), so no body\nfield selects a model, a tool surface, a reasoning budget, or an effort level.\n``effort``, ``use_kg`` and ``include_answer`` stay on the body only because\npublished SDK, CLI and MCP releases still send them (see\n:data:`RetiredEffort`): deprecated, accepted, and ignored. ``tier`` never\nshipped in a published client and stays rejected by the strict base.\n\nScope never changes the configuration (NDI-573): every run — scoped by\n``paths``/``path_prefix`` or not — gets the same source-level configuration.\nThe folder and file selectors resolve to one file set that every tool\nenforces server-side against the stored job."},"DeepSearchV2Result":{"properties":{"result_type":{"type":"string","const":"deep_search_v2","title":"Result Type","default":"deep_search_v2"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The direct, grounded answer to the request. Null only on a run that exhausted its budget before authoring one, or that asked `clarification_questions` instead."},"clarification":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clarification","description":"The run's clarifying questions as plain text, instead of an answer. Only ever set when the request carried `allow_clarification` and the run needed the user's input to go on; `answer` is null and `evidences` empty alongside it. The same questions, structured, are in `clarification_questions`."},"clarification_questions":{"anyOf":[{"items":{"$ref":"#/components/schemas/ClarifyingQuestion"},"type":"array","maxItems":2},{"type":"null"}],"title":"Clarification Questions","description":"The questions behind `clarification`, at most 2, each with up to 4 suggested answers. Answer them with a follow-up on `session_id` that repeats the query and carries `clarification_answers` (one entry per question, a null answer skips it), or with any follow-up query in your own words. Null on every run that answered."},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The agent's self-graded confidence in the answer — how well the evidence and executed statements support it, on the shared six-level scale (certain / very_high / high / medium / low / speculative). Deep search publishes an answer that cites no evidence, claim or receipt at medium at most, and JE testing publishes a run with any `incomplete` criterion at medium at most. Null on exhausted runs and on results stored before the field existed."},"population_statement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Population Statement","description":"The population every figure was computed over — file, period, layer, status, basis, grain — in the run's own words. Null only on a run that never authored an answer."},"figures":{"items":{"$ref":"#/components/schemas/JetFigure"},"type":"array","title":"Figures","description":"One entry per criterion tested, each linked to the receipts its figures are readable out of. Empty on a run that answered without testing anything, or that exhausted its budget first."},"criteria":{"items":{"$ref":"#/components/schemas/JetCriterionOutcome"},"type":"array","title":"Criteria","description":"Every requested test and its final disposition, including tests that never reached binding, measurement, or a published figure. Empty only on results stored before this checklist existed."},"discrepancies":{"items":{"type":"string"},"type":"array","title":"Discrepancies","description":"Where the data contradicted the request's premise or a figure it stated. Empty when nothing did — the run is asked for this explicitly, so an empty list is an answer rather than an omission."},"reasoning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning","description":"How the receipted statements chain together into the answer."},"evidences":{"items":{"$ref":"#/components/schemas/SearchEvidence"},"type":"array","title":"Evidences","description":"The material the answer cites, each resolved to the caller's own uploaded file."},"sql_receipts":{"items":{"$ref":"#/components/schemas/SqlReceipt"},"type":"array","title":"Sql Receipts","description":"Every statement the run executed, in execution order — the answer's working."},"binding":{"anyOf":[{"$ref":"#/components/schemas/LedgerBindingWire"},{"type":"null"}],"description":"The definitional layer the run committed and computed under — which column is the period, which values mean posted, which clock a timing test was verbed on. Null on a run that answered without binding a ledger, which is only possible before any statement ran."},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallTrace"},"type":"array","title":"Tool Calls","description":"One entry per tool the run invoked, in execution order — the tool's name, a digest of its arguments, how many results came back, and how long it took. The run's shape, not its content."},"steps_used":{"type":"integer","title":"Steps Used","description":"Legacy procedure-step count retained for compatibility. It is engine-specific and is not a model-request count; agent runs expose completed root-model requests in `agent_usage`. Read it with `exhausted`, which says whether the configured request budget ran out before the run was satisfied.","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"Step budget hit before the run was satisfied. A successful response, not a failure.","default":false},"degraded":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degraded","description":"Why this result is degraded, when it is. The run broke before it could finalize an answer but had already computed real working, so what is published is that working — `sql_receipts` and `binding` — with `figures` empty and `answer` saying so. Null on every run that finished normally, exhausted ones included."},"quality":{"anyOf":[{"$ref":"#/components/schemas/JetQuality"},{"type":"null"}],"description":"Structured execution quality: clean vs recovered-with-warnings vs degraded, plus the fail-open checks, tool-failure counts, and missing audit artifacts that produced that status. JE-testing always sets this on a finished run. Other JetResult subclasses (deep search) leave it null. Null also on results stored before the field existed."},"execution_status":{"anyOf":[{"type":"string","enum":["performed","partially_performed","not_performed"]},{"type":"null"}],"title":"Execution Status","description":"Whether the run tested what it was asked to test: ``performed`` when every figure was computed, ``partially_performed`` when some criteria could not be, ``not_performed`` when none could. Read it alongside `quality`, which grades how well a performed test went. JE-testing always sets this on a finished run; other JetResult subclasses (deep search) leave it null, as do results stored before the field existed."},"agent_usage":{"anyOf":[{"$ref":"#/components/schemas/JetAgentUsage"},{"type":"null"}],"description":"Root-agent model requests split into execution, compaction, and recovery finalization. Null on the fixed pipeline and on results stored before this telemetry existed; use `usage` for all nested LLM cost."},"spec_digest":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Digest","description":"A short fingerprint of what this run committed to TEST — the rows, grain, clock, encoding, thresholds and time window each criterion was pinned to — with the free-text justifications beside those choices excluded. Two runs of the same question carry the same value when they tested the same thing, so an unstable answer can be told apart from an answer to a quietly different question without re-reading either run. Null on a run that committed no test spec, and on other JetResult subclasses."},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"The conversation this run belongs to. Send it back as the request's `session_id` to ask a follow-up in the same thread."},"usage":{"anyOf":[{"$ref":"#/components/schemas/SearchLlmUsage"},{"type":"null"}],"description":"What this run spent on LLM calls. Present only when the request asked for it; null means nothing was measured, not that nothing was spent."},"grounding_job_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Grounding Job Ids","description":"Ground jobs planned for this search's evidences. Empty when postprocessing is disabled for this caller by deployment policy, explicitly disabled for the run, or no evidence is groundable. Absent on older results. When empty or absent, callers may POST /v1/ground explicitly to locate quotes."},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"command_receipts":{"items":{"$ref":"#/components/schemas/CommandReceipt"},"type":"array","title":"Command Receipts","description":"Successful shell calculations cited by this answer."},"claims":{"items":{"$ref":"#/components/schemas/DeepSearchVerifiedClaim"},"type":"array","title":"Claims","description":"Calculated answer values, each bound to the execution that produced it."},"coverage":{"items":{"$ref":"#/components/schemas/DeepSearchCoverage"},"type":"array","title":"Coverage","description":"Complete result tables the answer attached, each with server-rendered rows."},"cache":{"anyOf":[{"$ref":"#/components/schemas/AnswerCacheInfo"},{"type":"null"}],"description":"Set when this answer was re-served from the workspace's answer cache instead of derived by this run, with the provenance of the run that did derive it. Null on every run that computed its own answer."}},"additionalProperties":false,"type":"object","title":"DeepSearchV2Result","description":"The result of one source-level deep-search run (``JobKind.DEEP_SEARCH_V2``).\n\nField-for-field the JET shape — answer, reasoning, evidences, the run's\n``sql_receipts``, the tool-call trace, session handle, usage, exhaustion —\nunder its own discriminator: the two kinds share one agent chassis and one\nfold, and a second field list here would only be a place for them to drift.\nOn this surface a receipt's ``rows`` are the statement's bounded preview;\nthe full result is retained server-side and re-queryable through the\n``res_…`` handle appearing in any statement that pages it."},"DeepSearchVerifiedClaim":{"properties":{"claim_id":{"type":"string","title":"Claim Id","description":"Unique id of this calculation within the result."},"answer_excerpt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Excerpt","description":"Exact displayed answer value selected for its calculation citation."},"answer_occurrence":{"type":"integer","minimum":0.0,"title":"Answer Occurrence","description":"Zero-based occurrence of answer_excerpt in the answer.","default":0},"evidence_indices":{"items":{"type":"integer"},"type":"array","title":"Evidence Indices","description":"Source evidence indices supporting the calculation inputs."},"claim":{"type":"string","title":"Claim","description":"The method or formula behind the calculated value, as the agent wrote it."},"reference":{"$ref":"#/components/schemas/DeepSearchClaimReference","description":"Exact address of the supporting result value."}},"additionalProperties":false,"type":"object","required":["claim_id","claim","reference"],"title":"DeepSearchVerifiedClaim","description":"One calculated answer value, bound to the execution that produced it."},"DeleteFileJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"file_delete","title":"Kind","default":"file_delete"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/DeleteFileResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"DeleteFileJob"},"DeleteFileResult":{"properties":{"result_type":{"type":"string","const":"file_delete","title":"Result Type","default":"file_delete"},"file_id":{"type":"string","format":"uuid","title":"File Id"},"outputs_deleted":{"type":"integer","title":"Outputs Deleted","default":0},"index_documents_deleted":{"type":"integer","title":"Index Documents Deleted","default":0},"kg_nodes_deleted":{"type":"integer","title":"Kg Nodes Deleted","default":0},"kg_edges_deleted":{"type":"integer","title":"Kg Edges Deleted","default":0},"jobs_cancelled":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Jobs Cancelled"},"verified":{"type":"boolean","title":"Verified","description":"False is a failed cascade and must alert."}},"additionalProperties":false,"type":"object","required":["file_id","verified"],"title":"DeleteFileResult","description":"Counts exist so the cascade is auditable rather than assumed."},"DeleteFilesResult":{"properties":{"result_type":{"type":"string","const":"files_delete","title":"Result Type","default":"files_delete"},"requested":{"type":"integer","title":"Requested","description":"How many file ids the batch named, after duplicates were dropped."},"deleted":{"type":"integer","title":"Deleted","description":"How many of them were soft-deleted and cascaded."},"outcomes":{"items":{"$ref":"#/components/schemas/FileDeletionOutcome"},"type":"array","title":"Outcomes","description":"One entry per requested file, in the order requested."},"outputs_deleted":{"type":"integer","title":"Outputs Deleted","description":"Live derived outputs retired across the batch.","default":0},"index_documents_deleted":{"type":"integer","title":"Index Documents Deleted","description":"Search-index documents removed across the batch.","default":0},"catalog_rows_deleted":{"type":"integer","title":"Catalog Rows Deleted","description":"Catalog records and source handles removed across the batch.","default":0},"objects_deleted":{"type":"integer","title":"Objects Deleted","description":"Stored objects removed from the deleted files' sibling folders.","default":0},"jobs_cancelled":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Jobs Cancelled","description":"In-flight jobs that named a deleted file and were cancelled by the cascade."},"unverified_file_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Unverified File Ids","description":"The deleted files whose re-check still found content in some representation."},"verified":{"type":"boolean","title":"Verified","description":"False is a failed cascade and must alert."}},"additionalProperties":false,"type":"object","required":["requested","deleted","outcomes","verified"],"title":"DeleteFilesResult","description":"A batch deletion's per-file outcomes plus the cascade's own counts.\n\nThe counts are summed over the files that were actually deleted, and exist\nfor the same reason ``DeleteFileResult``'s do: a caller that asked for\ndeletion can verify it happened rather than assume it. ``verified`` is the\nconjunction over the batch, and ``unverified_file_ids`` names the files\nbehind a false one — an aggregate flag alone would say a cascade failed\nwithout saying for what."},"DeleteWorkspaceRequest":{"properties":{"confirm_name":{"type":"string","title":"Confirm Name","description":"Must equal the workspace's name exactly."}},"additionalProperties":false,"type":"object","required":["confirm_name"],"title":"DeleteWorkspaceRequest","description":"Confirmation payload for an irreversible workspace deletion."},"DerivationStep":{"properties":{"result_id":{"type":"string","title":"Result Id"},"sql":{"type":"string","title":"Sql"},"kind":{"type":"string","enum":["extraction","transformation"],"title":"Kind"},"label":{"type":"string","title":"Label"},"preview_rows":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Preview Rows"},"reads":{"items":{"type":"string"},"type":"array","title":"Reads","description":"result_ids this step depends on."}},"additionalProperties":false,"type":"object","required":["result_id","sql","kind","label"],"title":"DerivationStep","description":"One SQL step in a table-QA derivation DAG."},"DerivationTrace":{"properties":{"steps":{"items":{"$ref":"#/components/schemas/DerivationStep"},"type":"array","title":"Steps"}},"additionalProperties":false,"type":"object","title":"DerivationTrace","description":"The answer's computation DAG when evidence is derived rather than extracted."},"DerivedTableWire":{"properties":{"name":{"type":"string","title":"Name","description":"The name the table is joined under in generated SQL."},"row_count":{"type":"integer","title":"Row Count","description":"Rows in the published file."},"sha256":{"type":"string","title":"Sha256","description":"Digest of the published bytes, so a reader can tell two generations apart."}},"additionalProperties":false,"type":"object","required":["name","row_count","sha256"],"title":"DerivedTableWire","description":"One Parquet table the parsing pass published beside the report."},"DeviceTokenRequest":{"properties":{"device_code":{"type":"string","maxLength":128,"minLength":8,"title":"Device Code"}},"type":"object","required":["device_code"],"title":"DeviceTokenRequest","description":"``POST /v1/cli/device/token``."},"Domain":{"properties":{"domain_id":{"type":"string","format":"uuid","title":"Domain Id"},"slug":{"type":"string","title":"Slug"},"display_name":{"type":"string","title":"Display Name"},"owner":{"type":"string","enum":["platform","tenant"],"title":"Owner"},"version":{"type":"integer","title":"Version"},"status":{"type":"string","enum":["draft","published"],"title":"Status"},"parent_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Slug","description":"Inheritance lineage for platform domains that extend a base vocabulary."},"class_count":{"type":"integer","title":"Class Count"},"selectable":{"type":"boolean","title":"Selectable","description":"True once published; a workspace may only pin a published version."},"taxonomy":{"$ref":"#/components/schemas/Taxonomy-Output"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"}},"additionalProperties":false,"type":"object","required":["domain_id","slug","display_name","owner","version","status","class_count","selectable","taxonomy"],"title":"Domain","description":"A domain with its effective taxonomy already resolved.\n\nA caller reading a domain wants the taxonomy that will actually be applied,\nnot a delta they have to merge themselves."},"DomainResponse":{"properties":{"domain":{"$ref":"#/components/schemas/Domain"},"validation":{"$ref":"#/components/schemas/DomainValidation"}},"additionalProperties":false,"type":"object","required":["domain","validation"],"title":"DomainResponse"},"DomainSummary":{"properties":{"domain_id":{"type":"string","format":"uuid","title":"Domain Id"},"slug":{"type":"string","title":"Slug"},"display_name":{"type":"string","title":"Display Name"},"owner":{"type":"string","enum":["platform","tenant"],"title":"Owner"},"version":{"type":"integer","title":"Version"},"status":{"type":"string","enum":["draft","published"],"title":"Status"},"parent_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Slug","description":"Inheritance lineage for platform domains that extend a base vocabulary."},"class_count":{"type":"integer","title":"Class Count"},"selectable":{"type":"boolean","title":"Selectable","description":"True once published; a workspace may only pin a published version."}},"additionalProperties":false,"type":"object","required":["domain_id","slug","display_name","owner","version","status","class_count","selectable"],"title":"DomainSummary","description":"A domain without its vocabularies, for listings."},"DomainValidation":{"properties":{"valid":{"type":"boolean","title":"Valid"},"errors":{"items":{"$ref":"#/components/schemas/DomainValidationError"},"type":"array","title":"Errors"},"effective_class_count":{"type":"integer","title":"Effective Class Count"}},"additionalProperties":false,"type":"object","required":["valid","effective_class_count"],"title":"DomainValidation","description":"Returned on every domain write, so a caller never has to guess whether a publish will succeed."},"DomainValidationError":{"properties":{"code":{"type":"string","title":"Code"},"path":{"type":"string","title":"Path"},"message":{"type":"string","title":"Message"}},"additionalProperties":false,"type":"object","required":["code","path","message"],"title":"DomainValidationError"},"EmailCodeRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"The console account's email address."}},"type":"object","required":["email"],"title":"EmailCodeRequest","description":"Ask for a sign-in code to be mailed to an address."},"EmailCodeRequestAccepted":{"properties":{"expires_in_seconds":{"type":"integer","title":"Expires In Seconds","description":"How long a mailed code stays valid."},"resend_after_seconds":{"type":"integer","title":"Resend After Seconds","description":"How long to wait before asking for another code."}},"type":"object","required":["expires_in_seconds","resend_after_seconds"],"title":"EmailCodeRequestAccepted","description":"The same answer whether or not the address has a console account."},"EmailCodeSignInResponse":{"properties":{"created":{"type":"boolean","title":"Created","description":"True when this sign-in wrote something: a new identity, a membership from an accepted invitation, or the default organization for an identity that belonged nowhere."},"user":{"$ref":"#/components/schemas/ConsoleUserInfo"},"organizations":{"items":{"$ref":"#/components/schemas/OrganizationInfo"},"type":"array","title":"Organizations","description":"Every organization the user belongs to. Empty means they belong to none yet."},"can_create_organization":{"type":"boolean","title":"Can Create Organization","description":"Whether this user may still create an organization themselves."},"can_run_evals":{"type":"boolean","title":"Can Run Evals","description":"Whether this identity may use the eval console (a Nace staff email domain). The console hides the section when false; the routes enforce it regardless.","default":false},"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","const":"bearer","title":"Token Type","default":"bearer"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["created","user","organizations","can_create_organization","access_token","expires_at"],"title":"EmailCodeSignInResponse","description":"The signed-in identity plus the same bounded console session an invitation link mints."},"EmailCodeVerifyRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"The address the code was mailed to."},"code":{"type":"string","maxLength":32,"minLength":1,"format":"password","title":"Code","description":"The code from the email.","writeOnly":true}},"type":"object","required":["email","code"],"title":"EmailCodeVerifyRequest","description":"Exchange a mailed code for a console session."},"Error":{"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","title":"Message","description":"Human- and model-readable; says what to do differently."},"detail":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Detail","description":"Structured payload, when the code carries one."},"retryable":{"type":"boolean","title":"Retryable","description":"Whether retrying the identical request could succeed."},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id","description":"Per-request correlation id; matches the ``X-Request-Id`` header. Null only when the error was minted outside any HTTP request, e.g. by a worker."}},"type":"object","required":["code","message","retryable"],"title":"Error","description":"The error object, per spec 12 §1.8."},"ErrorCode":{"type":"string","enum":["storage_connection_not_found","storage_connection_in_use","storage_limit_exceeded","storage_conflict","storage_auth_required","storage_unavailable","scan_required","scan_rejected","scan_unavailable","invalid_request","unsupported_file_type","file_too_large","invalid_schema","invalid_sql","invalid_path_prefix","command_not_permitted","batch_too_large","domain_validation_failed","default_label_required","wait_required_for_zero_retention","ledger_decision_invalid","tenant_required","partner_required","workspace_not_found","file_not_found","job_not_found","upload_not_found","node_not_found","schema_not_found","domain_not_found","session_not_found","access_label_not_found","ledger_understanding_not_found","ledger_table_not_found","tenant_not_found","path_conflict","schema_version_conflict","access_label_name_taken","workspace_name_taken","access_label_in_use","upload_expired","file_not_ingested","workspace_deleting","workspace_not_deletable","ingestion_in_progress","job_not_cancellable","confirmation_required","domain_not_published","domain_in_use","reserved_domain_slug","kg_not_built","kg_build_in_progress","ledger_understanding_in_progress","ledger_understanding_version_outdated","session_busy","tenant_limit_reached","range_not_satisfiable","result_expired","access_denied","tenant_disabled","access_backstop_violation","access_mode_not_implemented","rate_limited","concurrency_limit_reached","quota_exceeded","corrupt_file","zero_byte_file","encrypted_file","csv_dialect_ambiguous","csv_parse_failed","parse_failed","ocr_failed","conversion_failed","sheetless_workbook","unplayable_media","unclassified_pages","job_cancelled","job_timeout","upstream_unavailable","internal_error","unauthorized","not_implemented"],"title":"ErrorCode","description":"Every error the ``/v1`` surface can return.\n\nClients must treat this as an **open** enum: a new member is an additive\nchange (spec 12 §9), and a client that crashes on an unknown code makes\nevery future error a breaking change."},"ErrorDetail":{"properties":{"code":{"type":"string","title":"Code","description":"Stable, machine-readable error code (e.g. ``invalid_payload``)."},"message":{"type":"string","title":"Message","description":"Human-readable detail about the error."},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id","description":"Per-request correlation id; matches the ``X-Request-Id`` header. Null only when the error was minted outside any HTTP request, e.g. by a worker."}},"additionalProperties":false,"type":"object","required":["code","message"],"title":"ErrorDetail","description":"Inner error envelope used by :class:`ErrorResponse`.\n\n``request_id`` is populated on every response served inside a request;\ncallers can quote it back to support so we can correlate against logs\nwithout having to share the underlying Postgres row UUID."},"ErrorEnvelope":{"properties":{"error":{"$ref":"#/components/schemas/Error"}},"type":"object","required":["error"],"title":"ErrorEnvelope","description":"Every non-2xx body on ``/v1``."},"ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"}},"additionalProperties":false,"type":"object","required":["error"],"title":"ErrorResponse","description":"Top-level error body returned by every non-2xx response.\n\nThe OpenAPI schema declares this shape so client SDKs can branch on\n``response.error.code`` deterministically rather than parsing free-form\n``detail`` strings."},"EvalMetric":{"properties":{"metric":{"type":"string","title":"Metric"},"value":{"type":"number","title":"Value"},"threshold":{"type":"number","title":"Threshold"},"passed":{"type":"boolean","title":"Passed"},"errored":{"type":"boolean","title":"Errored","description":"Scoring itself failed (e.g. no judge configured) — not a verdict.","default":false},"notes":{"items":{"type":"string"},"type":"array","title":"Notes"},"questions_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Questions Total"},"questions_correct":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Questions Correct"}},"type":"object","required":["metric","value","threshold","passed"],"title":"EvalMetric","description":"One scored metric. Mirrors ``nace_eval.contracts.MetricResult``."},"EvalMissingPreparedWorkspace":{"properties":{"name":{"type":"string","title":"Name","description":"Portable name without the scheme: `techqa` for `ndi://techqa`."},"reference":{"type":"string","title":"Reference","description":"What a sample's `workspace.prepared` carries: `ndi://techqa`."},"candidates":{"items":{"type":"string"},"type":"array","title":"Candidates","description":"Sources the samples name, best first. More than one means the samples disagree — confirm before using."},"suggested_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suggested Source","description":"The ranked-first candidate, or a builder name when the corpus is rebuilt rather than fetched."},"builder":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Builder","description":"Registered builder that can rebuild this corpus from upstream, when one exists."},"sample_ids":{"items":{"type":"string"},"type":"array","title":"Sample Ids","description":"Samples blocked on this corpus."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Latest provisioning attempt: `running` | `failed`. Null when nothing has been tried."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the last attempt failed."}},"type":"object","required":["name","reference"],"title":"EvalMissingPreparedWorkspace","description":"A corpus the catalog wants, that nothing has provisioned on this endpoint.\n\nCarries what provisioning it needs, so the console can offer a filled-in\nsource rather than asking an operator to know the corpus URIs by heart."},"EvalPreparedWorkspace":{"properties":{"name":{"type":"string","title":"Name","description":"Portable name without the scheme: `techqa` for `ndi://techqa`."},"reference":{"type":"string","title":"Reference","description":"What a sample's `workspace.prepared` carries: `ndi://techqa`."},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"base_url":{"type":"string","title":"Base Url"},"file_count":{"type":"integer","title":"File Count"},"provisioned_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provisioned By Email"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["name","reference","workspace_id","base_url","file_count","created_at"],"title":"EvalPreparedWorkspace","description":"A provisioned corpus workspace samples attach to by portable name."},"EvalPreparedWorkspaceListResponse":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/EvalPreparedWorkspace"},"type":"array","title":"Workspaces"},"missing":{"items":{"$ref":"#/components/schemas/EvalMissingPreparedWorkspace"},"type":"array","title":"Missing","description":"Corpora the catalog's samples ask for that nothing has provisioned yet."}},"type":"object","required":["workspaces","missing"],"title":"EvalPreparedWorkspaceListResponse"},"EvalRolloutsResponse":{"properties":{"sample_id":{"type":"string","title":"Sample Id"},"rollouts":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Rollouts"}},"type":"object","required":["sample_id","rollouts"],"title":"EvalRolloutsResponse","description":"The raw rollouts behind one sample's metrics.\n\nIts own route because a rollout carries whole answers, evidences and tool\ncalls — nobody wants them for every sample in a suite at once."},"EvalRun":{"properties":{"eval_run_id":{"type":"string","format":"uuid","title":"Eval Run Id"},"status":{"type":"string","title":"Status","description":"`queued` | `running` | `succeeded` | `failed`. Open enum — never switch exhaustively."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Who started it. Null once that account is gone; the run's numbers stay."},"params":{"$ref":"#/components/schemas/EvalRunParams"},"workflow_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workflow Id"},"samples_total":{"type":"integer","title":"Samples Total"},"samples_passed":{"type":"integer","title":"Samples Passed"},"samples_failed":{"type":"integer","title":"Samples Failed"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Set when the run itself broke, not when a sample failed its metrics."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"}},"type":"object","required":["eval_run_id","status","params","samples_total","samples_passed","samples_failed","created_at"],"title":"EvalRun"},"EvalRunListResponse":{"properties":{"runs":{"items":{"$ref":"#/components/schemas/EvalRun"},"type":"array","title":"Runs"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"total_count":{"type":"integer","title":"Total Count"}},"type":"object","required":["runs","total_count"],"title":"EvalRunListResponse"},"EvalRunParams":{"properties":{"sample_ids":{"items":{"type":"string"},"type":"array","maxItems":4000,"title":"Sample Ids"},"layer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Layer"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"k_override":{"anyOf":[{"type":"integer","maximum":10.0,"minimum":1.0},{"type":"null"}],"title":"K Override","description":"Overrides each sample's own `k_runs`."},"judge_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Judge Model"},"use_judge":{"type":"boolean","title":"Use Judge","default":true},"timeout_seconds":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Timeout Seconds","description":"Overrides every selected sample's rollout timeout."},"max_concurrent_samples":{"type":"integer","maximum":16.0,"minimum":1.0,"title":"Max Concurrent Samples","default":1}},"type":"object","title":"EvalRunParams","description":"What to run and how. An empty selection means every runnable sample."},"EvalSampleListResponse":{"properties":{"samples":{"items":{"$ref":"#/components/schemas/EvalSampleSummary"},"type":"array","title":"Samples"},"layers":{"items":{"type":"string"},"type":"array","title":"Layers","description":"Every layer present in the catalog, for the picker's filter."},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"Every tag present in the catalog, for the picker's filter."}},"type":"object","required":["samples","layers","tags"],"title":"EvalSampleListResponse"},"EvalSampleResult":{"properties":{"sample_id":{"type":"string","title":"Sample Id"},"layer":{"type":"string","title":"Layer"},"passed":{"type":"boolean","title":"Passed"},"k_requested":{"type":"integer","title":"K Requested"},"k_completed":{"type":"integer","title":"K Completed"},"metrics":{"items":{"$ref":"#/components/schemas/EvalMetric"},"type":"array","title":"Metrics"},"usage":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Usage"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["sample_id","layer","passed","k_requested","k_completed","created_at"],"title":"EvalSampleResult"},"EvalSampleResultListResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/EvalSampleResult"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"EvalSampleResultListResponse"},"EvalSampleSummary":{"properties":{"id":{"type":"string","title":"Id"},"layer":{"type":"string","title":"Layer","description":"Target layer: `parse`, `ground`, `fact_search`, `query_tables`, …"},"implementation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Implementation"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"dataset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dataset","description":"Labelled corpus this sample scores against, when it names one."},"backend":{"type":"string","title":"Backend","description":"Workspace the sample needs: `local` fixtures, or an NDI platform workspace."},"k_runs":{"type":"integer","title":"K Runs"},"timeout_seconds":{"type":"number","title":"Timeout Seconds"},"prepared_workspace":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prepared Workspace","description":"Portable name (`ndi://techqa`) this sample attaches to; null when it seeds its own workspace."},"runnable":{"type":"boolean","title":"Runnable","description":"False when the sample needs a prepared workspace that has not been provisioned on this deployment."},"blocked_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Blocked Reason","description":"Why `runnable` is false."}},"type":"object","required":["id","layer","backend","k_runs","timeout_seconds","runnable"],"title":"EvalSampleSummary","description":"One packaged sample a run can select, as its YAML describes it.\n\nRead without resolving fixtures or downloading corpora, so listing the\ncatalog is cheap and needs no dataset credentials."},"Evidence":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"path":{"type":"string","title":"Path"},"locator":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/TextRange"},{"$ref":"#/components/schemas/VisualRegion"},{"$ref":"#/components/schemas/SpreadsheetRange"},{"$ref":"#/components/schemas/JsonlRecord"},{"$ref":"#/components/schemas/JsonPointer"},{"$ref":"#/components/schemas/AudioRange"},{"$ref":"#/components/schemas/RowRange"}],"discriminator":{"propertyName":"kind","mapping":{"audio_range":"#/components/schemas/AudioRange","json_pointer":"#/components/schemas/JsonPointer","jsonl_record":"#/components/schemas/JsonlRecord","row_range":"#/components/schemas/RowRange","spreadsheet_range":"#/components/schemas/SpreadsheetRange","text_range":"#/components/schemas/TextRange","visual_region":"#/components/schemas/VisualRegion"}}},{"type":"null"}],"title":"Locator","description":"Where the snippet sits, when the producer located it. None means the citation is component-level: ground the snippet against path (sheet=component for spreadsheets) to place it."},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page","description":"The 1-based page the producer attributed the snippet to when it produced no locator; None when unknown or when the locator already carries the page."},"relevance_score":{"type":"number","title":"Relevance Score"},"snippet":{"type":"string","title":"Snippet"},"why":{"type":"string","title":"Why","description":"Which retrieval leg matched, or which graph path led here."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"Public component of the hit, in the vocabulary file-metadata lists and qa-file/read-file accept as component= (tab name for spreadsheets, section for split documents); None for a single-component file or when attribution is unavailable."},"sql_table":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sql Table","description":"The run-sql table name holding the hit's component as rows (a spreadsheet tab's table, or a document's printed long tables); None when the component is not a table or the producer does not say."},"line_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line Start","description":"First line (1-based) of the hit in the text read-file returns for path and component; None when the producer did not place the hit in lines."},"line_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line End","description":"Last line (1-based, inclusive) of the hit, counted like line_start; None with it."}},"additionalProperties":false,"type":"object","required":["file_id","path","relevance_score","snippet","why"],"title":"Evidence","description":"The citation primitive.\n\nEvery result that asserts something about a document or the corpus carries\nit. A synthesised sentence with no evidence behind it is a bug, not a\ndegraded mode.\n\n``path`` is always the uploaded **source** path — that is what every external\naudience (``/v1`` bodies, the console, the search-agent result) is shown. The\ntwo ``exclude=True`` fields below are the host's internal twin of it, for the\naudience that must not see source paths at all (the agent's tools address\ningestion derivatives); they are never serialized, so the ``/v1`` wire shape\nis exactly what it was before they existed.\n\n``component`` closes the loop from a hit back to the file tools: it is the\npublic component name of the hit — exactly the vocabulary ``file-metadata``\nlists and ``qa-file`` / ``read-file`` accept as ``component=`` (the tab name\nfor a spreadsheet, the section/subcategory for a split document). ``None``\nmeans a single-component file or that attribution was unavailable.\n\n``sql_table`` takes the next step for a component that is a table: the name\n``run-sql`` queries it under — a spreadsheet tab's table, or the table every\nrow a document prints in its long tables lands in. Search sets it so a hit\ncan go straight to SQL; other producers leave it ``None``.\n\n``locator`` is present only when the producer actually located the snippet.\n``None`` is not a degraded mode: an engine that answered from a whole\ncomponent (the QA agent's quotes, the DuckDB agent's SQL receipts) asserts\nthe file and ``component``, nothing finer. Pinning such a snippet to a\nregion — a page bbox, a sheet cell range — is a separate ``ground`` call on\n``path`` with ``snippet`` as the target text (and ``component`` as the\n``sheet`` hint when the file is a spreadsheet)."},"ExampleFile":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"file_name":{"type":"string","title":"File Name"},"source_url":{"type":"string","title":"Source Url","description":"``ndi://file/<id>`` handle; never expires. Use as source_url on any action."},"page_count":{"type":"integer","title":"Page Count"}},"additionalProperties":false,"type":"object","required":["file_id","file_name","source_url","page_count"],"title":"ExampleFile","description":"The tenant's copy of the canonical sample document."},"ExampleJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"},"request":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Request","description":"Verbatim request body for the action endpoint (prefill editors; POST it to re-run)."}},"additionalProperties":false,"type":"object","required":["job_id","request"],"title":"ExampleJob","description":"One pre-computed example job plus the request that produced it."},"ExampleJobs":{"properties":{"parse":{"$ref":"#/components/schemas/ExampleJob"},"extract":{"$ref":"#/components/schemas/ExampleJob"},"categorize":{"$ref":"#/components/schemas/ExampleJob"},"ground":{"$ref":"#/components/schemas/ExampleJob"}},"additionalProperties":false,"type":"object","required":["parse","extract","categorize","ground"],"title":"ExampleJobs"},"ExampleResponse":{"properties":{"file":{"$ref":"#/components/schemas/ExampleFile"},"examples":{"$ref":"#/components/schemas/ExampleJobs"}},"additionalProperties":false,"type":"object","required":["file","examples"],"title":"ExampleResponse","description":"Response for ``GET /example``."},"ExternalWorkspaceStorage":{"properties":{"type":{"type":"string","const":"external","title":"Type","default":"external"},"connection_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Connection Id","description":"Reusable storage connection bound permanently to this workspace; each workspace has its own exclusive namespace. Null when the caller cannot view the storage connection."},"provider":{"anyOf":[{"type":"string","enum":["s3","azure_blob"]},{"type":"null"}],"title":"Provider","description":"Customer object storage provider. Null when the caller cannot view the storage connection."},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Exclusive namespace containing this workspace's durable objects. Null when the caller cannot view the storage connection."},"health":{"anyOf":[{"type":"string","enum":["draft","ready","degraded","revoked"]},{"type":"null"}],"title":"Health","description":"Current connection authorization state. Null when the caller cannot view the storage connection."}},"additionalProperties":false,"type":"object","title":"ExternalWorkspaceStorage"},"ExternalWorkspaceStorageInput":{"properties":{"type":{"type":"string","const":"external","title":"Type","default":"external"},"connection_id":{"type":"string","format":"uuid","title":"Connection Id","description":"Validated storage connection owned by this caller."}},"additionalProperties":false,"type":"object","required":["connection_id"],"title":"ExternalWorkspaceStorageInput"},"ExtractCitationOptions":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"When true, each extracted field includes source locations.","default":true},"include_source_text":{"type":"boolean","title":"Include Source Text","description":"When true, citations include a short quote from the source alongside the location.","default":true}},"additionalProperties":false,"type":"object","title":"ExtractCitationOptions"},"ExtractJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"extract","title":"Kind","default":"extract"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__ExtractResult"},{"type":"null"}],"description":"Present on succeeded while retained. Also present on a running extract job whose values were published before enrichment finished."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"ExtractJob"},"ExtractJobRequest":{"properties":{"file":{"$ref":"#/components/schemas/FileInput","description":"File to extract from. Supported extensions: ``.bmp``, ``.csv``, ``.doc``, ``.docm``, ``.docx``, ``.eml``, ``.htm``, ``.html``, ``.jpeg``, ``.jpg``, ``.json``, ``.log``, ``.md``, ``.mdx``, ``.msg``, ``.oft``, ``.pdf``, ``.png``, ``.ppt``, ``.pptx``, ``.tif``, ``.tiff``, ``.txt``, ``.vsd``, ``.vsdx``, ``.webp``, ``.xls``, ``.xlsm``, ``.xlsx``, ``.xml``."},"schema":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Schema","description":"JSON Schema describing the data to extract. Root must be an object with properties; nesting is bounded; composition keywords ($ref/anyOf/oneOf/allOf/not) are not supported. A field may use one type string or a nullable two-member type such as [\"string\", \"null\"]. Closed objects may use additionalProperties: false; true or schema-valued additionalProperties are not supported. Field descriptions directly guide extraction accuracy. Top-level arrays are extracted segment-by-segment across long documents and concatenated.","examples":[{"additionalProperties":false,"properties":{"invoice_number":{"description":"Invoice identifier.","type":"string"},"inspection_year":{"description":"Inspection year, or null when the document does not establish one.","type":["integer","null"]}},"type":"object"}]},"markdown_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Url","description":"Markdown from a prior parse of the same file; skips the internal parse when present."},"idempotency_key":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Idempotency Key"}},"additionalProperties":false,"type":"object","required":["file","schema"],"title":"ExtractJobRequest","description":"Body for ``POST /extract`` and ``POST /extract_async``."},"ExtractRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"delivery":{"type":"string","enum":["complete","progressive"],"title":"Delivery","description":"Progressive publishes extracted values on the running job before citation enrichment finishes. Poll GET /v1/jobs/{job_id} for the completed result; complete waits for all enrichment. Parquet currently returns only a complete result in either mode.","default":"complete"},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to extract from: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"schema_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schema Id","description":"Catalog schema family id (sch_...). Mutually exclusive with an inline schema."},"schema_version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Schema Version","description":"Pin a published catalog version. Omit with schema_id to use the latest version."},"schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Schema","description":"Inline JSON Schema of fields to extract. Mutually exclusive with schema_id."},"resolved_schema_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved Schema Id","description":"Server-set at accept time when a registry schema_id was resolved."},"resolved_schema_version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Resolved Schema Version","description":"Server-set at accept time alongside resolved_schema_id."},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instructions","description":"Optional guidance for how to fill the declared schema. Cannot add undeclared result fields."},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to extract. Omit to use the whole document."},"citations":{"$ref":"#/components/schemas/ExtractCitationOptions","description":"Whether extracted fields include locations and quoted source text."}},"additionalProperties":false,"type":"object","required":["source"],"title":"ExtractRequest","description":"Body for canonical ``POST /v1/extract`` (and the hidden legacy alias).\n\nExactly one of ``schema_id`` or ``schema`` is required. A legacy\n``json_schema`` alias is still accepted server-side for compatibility.\nOptional ``schema_version`` pins a registry version when ``schema_id`` is\nset; omit it to resolve latest. Accept-time freeze clears the wire\n``schema_id`` / ``schema_version``, stores the effective ``schema``, and\nrecords the resolved identity on ``resolved_schema_id`` /\n``resolved_schema_version`` for result audit metadata."},"ExtractRequestEcho":{"additionalProperties":true,"type":"object"},"ExtractedField":{"properties":{"path":{"type":"string","title":"Path","description":"JSON Pointer of this schema leaf (for example /invoice_number). Join key between data and fields."},"value":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"},{"type":"boolean"},{"type":"null"}],"title":"Value","description":"Extracted scalar for this path, or null when the field was not found."},"status":{"type":"string","enum":["found","not_found","ambiguous"],"title":"Status","description":"Whether this leaf was filled: found has a value, not_found means the document was examined and the field is absent, ambiguous means a value is present but not unique."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"Evidence-support score for a found top-level scalar when the runtime produced one. Null for nested paths, arrays, not_found, and unverifiable fields."},"citations":{"items":{"$ref":"#/components/schemas/Citation"},"type":"array","title":"Citations","description":"Where the value was read. Empty when citations are off or the field was not found."}},"additionalProperties":false,"type":"object","required":["path","status"],"title":"ExtractedField","description":"One field an extraction looked for.\n\n``not_found`` is a real outcome with an entry, not a missing key: an\nextraction that silently omits what it could not find is indistinguishable\nfrom one that never looked."},"ExtractionNullOnSuccessDisclosure":{"properties":{"code":{"type":"string","const":"extraction_null_on_success","title":"Code"},"field_paths":{"items":{"type":"string"},"type":"array","title":"Field Paths","description":"JSON paths of schema-required fields that were absent in the source document and returned as null."}},"additionalProperties":false,"type":"object","required":["code","field_paths"],"title":"ExtractionNullOnSuccessDisclosure","description":"Schema-required fields returned null because the document did not contain them.\n\nThe job succeeded. Null means the document was examined and the field\nwas absent — not that extraction failed or was skipped."},"ExtractionSchema":{"properties":{"schema_id":{"type":"string","title":"Schema Id"},"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"},"version":{"type":"integer","minimum":1.0,"title":"Version"},"owner":{"type":"string","enum":["platform","tenant"],"title":"Owner"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"schema":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Schema"}},"additionalProperties":false,"type":"object","required":["schema_id","name","version","owner","created_at","updated_at","schema"],"title":"ExtractionSchema","description":"One immutable schema version, including the frozen JSON Schema body."},"ExtractionSchemaSummary":{"properties":{"schema_id":{"type":"string","title":"Schema Id"},"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"},"version":{"type":"integer","minimum":1.0,"title":"Version"},"owner":{"type":"string","enum":["platform","tenant"],"title":"Owner"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["schema_id","name","version","owner","created_at","updated_at"],"title":"ExtractionSchemaSummary","description":"Latest visible version of one schema family."},"FactSearchRequest":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"What to answer, in the caller's own words. Stripped before its length is checked; a blank query is refused rather than run."},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context","description":"Free-form background for the model — the engagement, the entity, what the caller already knows. It informs the answer; it does not widen or narrow which files the caller may see."},"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Put every uploaded file under one folder subtree, workspace-relative, in the run's scope; `paths`, where the body takes it, adds more files. Omit both for the whole workspace."},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Scope the run to exactly these uploaded files. Every retrieval leg and agent tool sees only these files and the content ingested from them, so nothing else can be read or cited. Each entry names an uploaded source file (never a folder — scope folders with path_prefix; the two add up, so the run covers the folder's files plus these). No limit on how many. Unknown or inaccessible paths are refused up front."},"top_k":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Top K","description":"How many evidences to return, best first. Omitted means 6. It is a cap on the answer's citation list, not on how much the pipeline reads: retrieval width is fixed, so a larger `top_k` returns more of what was already found rather than searching further. Raising it far above the default trades citation count for reliability — the whole list is one constrained generation, and the ceiling is 50."},"include_answer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Include Answer","description":"Deprecated and ignored: every run answers. Accepted so clients released before it was retired keep working; omit it.","deprecated":true}},"additionalProperties":false,"type":"object","required":["query"],"title":"FactSearchRequest","description":"Body for ``POST /workspaces/{workspace_id}/fact-search`` — always the fixed pipeline.\n\nDeliberately no ``session_id``: a fact-search run is single-shot and keeps no\nconversation, so the strict base rejects the field outright instead of a\nbespoke validator explaining why it cannot be honored. No ``effort`` either —\nthe fixed pipeline has no budget presets. And no ``allow_clarification``: the\npipeline has no agent who could ask back, so it always answers — the strict\nbase rejects the field. ``include_answer`` is accepted and ignored only\nbecause published SDK releases still send it (see :data:`RetiredIncludeAnswer`)."},"FieldReadability":{"properties":{"field":{"type":"string","title":"Field","description":"The extracted field the query filtered on."},"in_scope":{"type":"integer","title":"In Scope","description":"Components in scope whose document type carries this field."},"readable":{"type":"integer","title":"Readable","description":"Of those, how many had a resolved value the predicate could evaluate."}},"additionalProperties":false,"type":"object","required":["field","in_scope","readable"],"title":"FieldReadability","description":"How much of one filtered field the extraction could actually read.\n\nOnly a ``found`` observation materializes a value, so a comparison against a\nfield the extraction did not resolve silently drops those components: the\nquery is correct and the result is empty for a reason that has nothing to do\nwith the caller's question. Reported per field the query filtered on, and\nonly when ``readable < in_scope`` — a fully readable field says nothing.\n\nRead it with ``total_matches``: when ``readable`` is 0 the empty result\ncarries no information about the population, and when the unreadable\nremainder is large next to ``total_matches`` the matches shown are a floor,\nnot a census."},"File":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"path":{"type":"string","title":"Path","description":"Full path relative to the workspace root. Send this exact string wherever a tool takes `path`: tools match it exactly."},"file_name":{"type":"string","title":"File Name","description":"The last segment of `path`, for display only. A tool given it as `path` answers file_not_found."},"file_type":{"type":"string","title":"File Type"},"size_bytes":{"type":"integer","title":"Size Bytes"},"observed_hash":{"type":"string","title":"Observed Hash"},"ingested_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ingested Hash","description":"Content hash at the last successful ingestion. Null with ingested_at means never ingested."},"ingestion_status":{"$ref":"#/components/schemas/IngestionStatus"},"ingested_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ingested At"},"version":{"type":"integer","title":"Version","description":"Starts at 1; increments on every content replacement."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Null until categorised."},"access_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Label","description":"Exactly one label, or null when the workspace declares none."},"access_label_source":{"anyOf":[{"$ref":"#/components/schemas/AccessLabelSource"},{"type":"null"}]},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When derived material for this file ages out."},"graph_inclusion":{"type":"string","enum":["auto","include","exclude"],"title":"Graph Inclusion","description":"This file's knowledge-graph inclusion policy, not its effective membership. 'auto' defers to the workspace's KG exclusion rules; 'include'/'exclude' override them for this one file. A file excluded by a workspace rule still reads 'auto' here, so this does not on its own tell an excluded file from one whose graph is not built yet — read representations.knowledge_graph for whether a build has covered it.","default":"auto"},"labels":{"additionalProperties":{"type":"string"},"type":"object","title":"Labels","description":"Caller-supplied metadata."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["file_id","workspace_id","path","file_name","file_type","size_bytes","observed_hash","ingestion_status","version","created_at","updated_at"],"title":"File","description":"A source file. The derived tree is platform-owned and has no CRUD surface."},"FileCategoryAssignment":{"properties":{"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"is_freeform_subcategory":{"type":"boolean","title":"Is Freeform Subcategory","default":false}},"additionalProperties":false,"type":"object","required":["category","subcategory"],"title":"FileCategoryAssignment"},"FileComponentInfo":{"properties":{"kind":{"type":"string","enum":["section","tab","image","raw"],"title":"Kind","description":"What the component is: a document `section`, a spreadsheet `tab`, an `image`, or the `raw` file."},"name":{"type":"string","title":"Name","description":"The component's name — pass it as `component` to scope a question; empty when the whole file is the unit."},"summary":{"type":"string","title":"Summary","description":"What the component contains, as summarized at ingestion.","default":""},"categories":{"items":{"type":"string"},"type":"array","title":"Categories","description":"Category/subcategory paths assigned to this section or tab at ingestion."},"key_terms":{"items":{"$ref":"#/components/schemas/FileKeywordDescription"},"type":"array","maxItems":6,"title":"Key Terms","description":"Up to FILE_METADATA_MAX_KEY_TERMS of the component's extracted keywords whose role the source states (who a name is, what a date or number marks), in extraction order. Empty for files ingested before keyword roles were extracted."},"page_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Start","description":"First source page covered, 1-based (sections)."},"page_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page End","description":"Last source page covered, 1-based (sections)."},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count","description":"Tabs: rows in the queryable table; sections: rows in their rows tables; else the source extent."},"column_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Column Count","description":"Columns in the component's table, when it has one."},"readable":{"type":"boolean","title":"Readable","description":"True when the component has text a question about the file can be answered from."},"queryable":{"type":"boolean","title":"Queryable","description":"True when the component is a table that query-tables can compute over."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why ingestion could not read this component; it stays listed but has no content."}},"additionalProperties":false,"type":"object","required":["kind","name","readable","queryable"],"title":"FileComponentInfo","description":"One part of an uploaded file that can be asked about by name: a document\nsection, a spreadsheet tab, an image, or the raw upload itself."},"FileDeletionOutcome":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id","description":"The requested file, echoed whether or not it was deleted."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The deleted file's workspace-relative path; null when the id resolved to no visible file."},"status":{"type":"string","enum":["deleted","not_found","access_denied"],"title":"Status","description":"Whether this file was soft-deleted, did not exist in the workspace, or was withheld by the access gate."}},"additionalProperties":false,"type":"object","required":["file_id","status"],"title":"FileDeletionOutcome","description":"One requested file's fate, decided when the batch was accepted.\n\nPer-file rather than a single verdict, for the reason an ingestion reports\nper-file outcomes: an id that no longer resolves, or one the caller may not\nsee, must not fail the other files in the batch."},"FileDetail":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"path":{"type":"string","title":"Path","description":"Full path relative to the workspace root. Send this exact string wherever a tool takes `path`: tools match it exactly."},"file_name":{"type":"string","title":"File Name","description":"The last segment of `path`, for display only. A tool given it as `path` answers file_not_found."},"file_type":{"type":"string","title":"File Type"},"size_bytes":{"type":"integer","title":"Size Bytes"},"observed_hash":{"type":"string","title":"Observed Hash"},"ingested_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ingested Hash","description":"Content hash at the last successful ingestion. Null with ingested_at means never ingested."},"ingestion_status":{"$ref":"#/components/schemas/IngestionStatus"},"ingested_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ingested At"},"version":{"type":"integer","title":"Version","description":"Starts at 1; increments on every content replacement."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Null until categorised."},"access_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Label","description":"Exactly one label, or null when the workspace declares none."},"access_label_source":{"anyOf":[{"$ref":"#/components/schemas/AccessLabelSource"},{"type":"null"}]},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When derived material for this file ages out."},"graph_inclusion":{"type":"string","enum":["auto","include","exclude"],"title":"Graph Inclusion","description":"This file's knowledge-graph inclusion policy, not its effective membership. 'auto' defers to the workspace's KG exclusion rules; 'include'/'exclude' override them for this one file. A file excluded by a workspace rule still reads 'auto' here, so this does not on its own tell an excluded file from one whose graph is not built yet — read representations.knowledge_graph for whether a build has covered it.","default":"auto"},"labels":{"additionalProperties":{"type":"string"},"type":"object","title":"Labels","description":"Caller-supplied metadata."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"download_url":{"type":"string","title":"Download Url","description":"Time-limited presigned GET URL that saves the file's bytes to disk."},"preview_url":{"type":"string","title":"Preview Url","description":"Time-limited presigned GET URL that a browser renders inline."},"download_url_expires_at":{"type":"string","format":"date-time","title":"Download Url Expires At","description":"When the presigned URLs stop being valid."}},"additionalProperties":false,"type":"object","required":["file_id","workspace_id","path","file_name","file_type","size_bytes","observed_hash","ingestion_status","version","created_at","updated_at","download_url","preview_url","download_url_expires_at"],"title":"FileDetail","description":"A source file plus short-lived presigned URLs for its bytes.\n\nNo separate ``GET .../content`` route: a presigned URL keeps raw bytes\noff the API path and avoids charging for a second network hop inside the\nplatform.  Both URLs expire after ``DOWNLOAD_URL_TTL_SECONDS`` seconds;\nfetch them promptly.\n\nThe two differ only in the response headers S3 returns: ``download_url``\nsaves to disk, ``preview_url`` renders in place under the file's real\nmedia type.  One URL cannot do both — a browser decides from the headers."},"FileDocumentMetadata":{"properties":{"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"is_freeform_subcategory":{"type":"boolean","title":"Is Freeform Subcategory","default":false},"summary":{"type":"string","title":"Summary"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"keyword_descriptions":{"items":{"$ref":"#/components/schemas/FileKeywordDescription"},"type":"array","title":"Keyword Descriptions","description":"Context for each document keyword when generated."},"page_start":{"type":"integer","title":"Page Start"},"page_end":{"type":"integer","title":"Page End"},"path":{"type":"string","title":"Path"},"char_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Char Count","description":"Characters in the segment's markdown; null on older ingests."},"access_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Label"},"access_label_source":{"anyOf":[{"$ref":"#/components/schemas/AccessLabelSource"},{"type":"null"}]},"access_label_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Label Reason"}},"additionalProperties":false,"type":"object","required":["category","subcategory","summary","page_start","page_end","path"],"title":"FileDocumentMetadata"},"FileFigureInfo":{"properties":{"name":{"type":"string","title":"Name","description":"`figure p<page>-<n>`. Pass it as qa-file's `component` to ask the vision engine about this figure alone."},"page":{"type":"integer","title":"Page","description":"1-based page the figure is on."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What the figure shows, written by a vision model at ingestion; null when not described."},"text":{"type":"string","title":"Text","description":"Text printed inside the figure, as OCR read it.","default":""}},"additionalProperties":false,"type":"object","required":["name","page"],"title":"FileFigureInfo","description":"One picture inside a PDF page — a seal, chart, photo, map or stamp that OCR found as a region.\n\nIts description is also inline in read-file (``[figure pN-K: …]`` at its spot on the page)\nand in hybrid-search, so a figure can be found by what it shows."},"FileIdsSelection":{"properties":{"type":{"type":"string","const":"file_ids","title":"Type","default":"file_ids"},"file_ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":1000,"minItems":1,"title":"File Ids"}},"additionalProperties":false,"type":"object","required":["file_ids"],"title":"FileIdsSelection","description":"One file or an explicit batch."},"FileInput":{"properties":{"source_url":{"type":"string","title":"Source Url","description":"``s3://bucket/key``, ``https://`` (presigned/public), or ``ndi://file/<uuid>`` from ``POST /upload``."},"file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Name","description":"Original filename and source identity. Required for ``s3://`` / ``https://``. Optional for ``ndi://file/<uuid>`` (defaults to the name captured at upload); the upload's server-verified format remains authoritative."}},"additionalProperties":false,"type":"object","required":["source_url"],"title":"FileInput","description":"The document to process."},"FileKeywordDescription":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object"},"FileListPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/File"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."},"coverage":{"$ref":"#/components/schemas/Coverage"}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"FileListPage","description":"A page of source files plus the access honesty block.\n\n``coverage`` reports how many candidates the access gate withheld and\nwhich labels would have been needed to see them.  A workspace that\ndeclares no access labels always has an empty ``coverage``; ``total_count``\nis always exact after filtering."},"FileMarlinEvent":{"properties":{"start_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Ms"},"end_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Ms"},"text":{"type":"string","title":"Text","default":""}},"additionalProperties":false,"type":"object","title":"FileMarlinEvent"},"FileMediaMetadata":{"properties":{"modality":{"type":"string","enum":["audio","video"],"title":"Modality"},"duration_ms":{"type":"integer","title":"Duration Ms"},"speakers":{"items":{"$ref":"#/components/schemas/FileMediaSpeaker"},"type":"array","title":"Speakers"},"speech_segment_count":{"type":"integer","title":"Speech Segment Count","default":0},"frame_count":{"type":"integer","title":"Frame Count","default":0},"summary":{"type":"string","title":"Summary","default":""},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"marlin_summary":{"type":"string","title":"Marlin Summary","default":""},"marlin_events":{"items":{"$ref":"#/components/schemas/FileMarlinEvent"},"type":"array","title":"Marlin Events"},"timeline_path":{"type":"string","title":"Timeline Path"},"transcript_path":{"type":"string","title":"Transcript Path"},"frames_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Frames Dir"}},"additionalProperties":false,"type":"object","required":["modality","duration_ms","timeline_path","transcript_path"],"title":"FileMediaMetadata"},"FileMediaSpeaker":{"properties":{"id":{"type":"string","title":"Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"additionalProperties":false,"type":"object","required":["id"],"title":"FileMediaSpeaker"},"FileMetadata":{"properties":{"file":{"$ref":"#/components/schemas/File"},"lane":{"type":"string","title":"Lane","description":"Which ingestion lane processed this file."},"page_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Count","description":"For document formats; null for spreadsheets and media."},"sheet_names":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sheet Names","description":"For workbook formats; null for everything else."},"duration_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Ms","description":"For audio/video; null for document formats."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"Lane-level summary extracted during ingestion."},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords","description":"Lane-level keywords extracted during ingestion."},"keyword_descriptions":{"items":{"$ref":"#/components/schemas/FileKeywordDescription"},"type":"array","title":"Keyword Descriptions","description":"One source-grounded explanation per file keyword, when generated."},"documents":{"items":{"$ref":"#/components/schemas/FileDocumentMetadata"},"type":"array","title":"Documents"},"sheets":{"items":{"$ref":"#/components/schemas/FileSheetMetadata"},"type":"array","title":"Sheets"},"media":{"anyOf":[{"$ref":"#/components/schemas/FileMediaMetadata"},{"type":"null"}]},"native_metadata":{"anyOf":[{"$ref":"#/components/schemas/NativeFileMetadata"},{"type":"null"}],"description":"Source filesystem time and format-native properties captured during ingestion."},"extracted_fields":{"items":{"$ref":"#/components/schemas/ExtractedField"},"type":"array","title":"Extracted Fields"},"outputs":{"items":{"$ref":"#/components/schemas/ArtifactOutputRef"},"type":"array","title":"Outputs"},"representations":{"$ref":"#/components/schemas/RepresentationState"},"last_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"The most recent ingestion error, if any."}},"additionalProperties":false,"type":"object","required":["file","lane"],"title":"FileMetadata","description":"Ingestion-derived metadata for a source file.\n\n``representations`` answers \"is this file actually searchable right now\",\nwhich ``ingestion_status`` alone cannot: a file can be ingested while its\ngraph generation is still building.\n\n``outputs`` lists every live derivation (``retired_at IS NULL``) so a\ncaller knows exactly what exists at each instant without racing against a\nre-ingestion in progress."},"FileMetadataRequest":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path","description":"The uploaded file's full path relative to the workspace root, exactly as it was uploaded and as listings and search results print it — e.g. `evidence/doc-7f83/contract.pdf`. Not a bare file name (a file's `file_name`), a folder, a file id, or a path that starts with the workspace id."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"Describe only this section or tab, named exactly as an unscoped call lists it."}},"additionalProperties":false,"type":"object","required":["path"],"title":"FileMetadataRequest","description":"Request body for ``file-metadata``. ``path`` names one uploaded file."},"FileMetadataResult":{"properties":{"result_type":{"type":"string","const":"file_metadata","title":"Result Type","default":"file_metadata"},"output":{"$ref":"#/components/schemas/FileMetadataToolResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"FileMetadataResult"},"FileMetadataToolResponse":{"properties":{"path":{"type":"string","title":"Path","description":"The uploaded file's path relative to the workspace root, as requested."},"file_id":{"type":"string","format":"uuid","title":"File Id","description":"The uploaded file's id, as the files endpoints address it."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"Ingestion lane (document / table / media), when known."},"ingestion_status":{"$ref":"#/components/schemas/IngestionStatus","description":"Where the file is in ingestion; a file that is not `ingested` has no components yet."},"ingestion_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ingestion Error","description":"Why ingestion failed, when the ledger recorded a reason."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Byte size of the uploaded source object."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"The file's primary category path, when classified."},"page_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Count","description":"Pages in a paged document; absent for other files."},"tab_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tab Count","description":"Tabs in a workbook; absent for other files."},"summary":{"type":"string","title":"Summary","description":"Summary of the file's first section or tab; each component has its own.","default":""},"components":{"items":{"oneOf":[{"$ref":"#/components/schemas/FileComponentInfo"},{"$ref":"#/components/schemas/MediaComponentInfo"}],"discriminator":{"propertyName":"kind","mapping":{"image":"#/components/schemas/FileComponentInfo","media":"#/components/schemas/MediaComponentInfo","raw":"#/components/schemas/FileComponentInfo","section":"#/components/schemas/FileComponentInfo","tab":"#/components/schemas/FileComponentInfo"}}},"type":"array","title":"Components","description":"The file's sections, tabs, image or recording, in reading order."},"figures":{"items":{"$ref":"#/components/schemas/FileFigureInfo"},"type":"array","title":"Figures","description":"PDFs: pictures inside the pages (seals, charts, photos, stamps), in page order; with `component`, only those on that component's pages. Empty for other files and for PDFs ingested before figures were recorded."},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["path","file_id","ingestion_status","size_bytes"],"title":"FileMetadataToolResponse","description":"Response body for ``file-metadata`` — what one uploaded file is, without opening it.\n\n``summary`` is the summary of the file's first section or tab, never a\nconcatenation across components (each component carries its own). A file\nthat is not ingested yet answers 200 with its ``ingestion_status`` and no\ncomponents; a failed one also carries ``ingestion_error``."},"FileQueryScope":{"properties":{"type":{"type":"string","const":"file","title":"Type","default":"file"},"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path"}},"additionalProperties":false,"type":"object","required":["path"],"title":"FileQueryScope","description":"The question ran against one workspace-relative file."},"FileSheetMetadata":{"properties":{"sheet_name":{"type":"string","title":"Sheet Name"},"max_row":{"type":"integer","title":"Max Row","default":0},"max_column":{"type":"integer","title":"Max Column","default":0},"categories":{"items":{"$ref":"#/components/schemas/FileCategoryAssignment"},"type":"array","title":"Categories"},"summary":{"type":"string","title":"Summary","default":""},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"keyword_descriptions":{"items":{"$ref":"#/components/schemas/FileKeywordDescription"},"type":"array","title":"Keyword Descriptions","description":"Context for each sheet keyword when generated."},"non_empty_cell_count":{"type":"integer","title":"Non Empty Cell Count","default":0},"row_count":{"type":"integer","title":"Row Count","default":0},"column_count":{"type":"integer","title":"Column Count","default":0},"markdown_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Path"},"char_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Char Count","description":"Characters in the tab's markdown; null on older ingests."},"jsonl_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jsonl Path"},"parquet_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parquet Path"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"additionalProperties":false,"type":"object","required":["sheet_name"],"title":"FileSheetMetadata"},"FileVersion":{"properties":{"version":{"type":"integer","title":"Version"},"observed_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observed Hash"},"ingested_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ingested Hash"},"ingested_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ingested At"},"size_bytes":{"type":"integer","title":"Size Bytes"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"replaced_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Replaced At","description":"Null on the current version."},"is_current":{"type":"boolean","title":"Is Current"}},"additionalProperties":false,"type":"object","required":["version","size_bytes","created_at","is_current"],"title":"FileVersion","description":"Metadata only. Retaining every superseded copy is a customer opt-in."},"FilesQueryScope":{"properties":{"type":{"type":"string","const":"files","title":"Type","default":"files"},"count":{"type":"integer","minimum":2.0,"title":"Count"}},"additionalProperties":false,"type":"object","required":["count"],"title":"FilesQueryScope","description":"The question ran against several files; only the count is public."},"FilteredSearchCell":{"properties":{"field":{"type":"string","title":"Field"},"status":{"type":"string","enum":["found","not_found","ambiguous","unexamined"],"title":"Status"},"value":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/MoneyCell"},{"$ref":"#/components/schemas/TextCell"},{"$ref":"#/components/schemas/DateCell"},{"$ref":"#/components/schemas/NumberCell"},{"$ref":"#/components/schemas/BooleanCell"}],"discriminator":{"propertyName":"kind","mapping":{"boolean":"#/components/schemas/BooleanCell","date":"#/components/schemas/DateCell","money":"#/components/schemas/MoneyCell","number":"#/components/schemas/NumberCell","text":"#/components/schemas/TextCell"}}},{"type":"null"}],"title":"Value"},"item_index":{"type":"integer","title":"Item Index","description":"Position for repeated fields; 0 for scalars.","default":0},"citation":{"anyOf":[{"$ref":"#/components/schemas/Citation"},{"type":"null"}],"description":"Where the value was found, with quoted source text."},"native_raw":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Native Raw","description":"The stored native cell value, before display formatting or rounding."},"native_display":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Native Display","description":"The source cell's formatted display, when available, kept separately from its typed value."}},"additionalProperties":false,"type":"object","required":["field","status"],"title":"FilteredSearchCell","description":"One extracted field value on one row, with its evidence (D10).\n\n``status`` is value-level data honesty: ``not_found`` means the component\nwas examined and the field is absent; ``ambiguous`` means present but not\nnormalizable (e.g. money without a currency); ``unexamined`` means the\nextraction could not say."},"FilteredSearchComponent":{"properties":{"component":{"type":"string","title":"Component","description":"Public component name — the tab or document section, matching the component= argument of the file tools (qa-file, read-file, query-tables). Several document rows can share one section name; page_start/page_end distinguish them. A media row's name is the recording stem, display-only (file tools take the whole file)."},"component_kind":{"type":"string","enum":["document","sheet","media"],"title":"Component Kind","description":"The representation containing these observations."},"document_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Type","description":"The profiled document type of this component."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"The component's primary taxonomy category."},"subcategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subcategory","description":"The component's primary taxonomy subcategory."},"page_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Start","description":"First source page containing the component."},"page_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page End","description":"Last source page containing the component."},"summary":{"type":"string","title":"Summary","description":"A description of the component's contents.","default":""},"entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Id","description":"The printed identifier of the matching entity within a register."},"source_row":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Row","description":"The native sheet row containing this entity's facts."},"cells":{"items":{"$ref":"#/components/schemas/FilteredSearchCell"},"type":"array","title":"Cells","description":"Typed observations belonging to this component."},"content_matches":{"items":{"$ref":"#/components/schemas/ContentConditionMatch"},"type":"array","title":"Content Matches","description":"Content criteria this row satisfied, with observed values and the source passages used to verify them."}},"additionalProperties":false,"type":"object","required":["component","component_kind"],"title":"FilteredSearchComponent","description":"A matching component and its own observations within an uploaded file."},"FilteredSearchJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"filtered_search","title":"Kind","default":"filtered_search"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/FilteredSearchResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"FilteredSearchJob"},"FilteredSearchPage":{"properties":{"type":{"type":"string","const":"page","title":"Type","default":"page"},"cursor":{"type":"string","maxLength":512,"minLength":1,"title":"Cursor","description":"The `next_cursor` of an earlier filtered-search result, exactly as received."}},"additionalProperties":false,"type":"object","required":["cursor"],"title":"FilteredSearchPage","description":"Fetch the next page of an earlier filtered search — live re-execution, no agent."},"FilteredSearchResult":{"properties":{"result_type":{"type":"string","const":"filtered_search","title":"Result Type","default":"filtered_search"},"result_unit":{"type":"string","enum":["source","component","entity","entry"],"title":"Result Unit","description":"The unit used for rows, totals, top-N and pagination. New searches consistently return catalog entries with their established identities. Legacy units remain readable.","default":"component"},"columns":{"items":{"$ref":"#/components/schemas/CatalogColumnDescriptor"},"type":"array","title":"Columns"},"rows":{"items":{"$ref":"#/components/schemas/FilteredSearchRow"},"type":"array","title":"Rows"},"content_verification":{"anyOf":[{"$ref":"#/components/schemas/ContentVerificationSummary"},{"type":"null"}],"description":"Coverage of the content criterion check. Null for pure catalog queries and older results. An empty result with unverified candidates does not establish that no documents match."},"total_matches":{"type":"integer","title":"Total Matches","description":"Confirmed matches in result_unit, before any page or top-N cut.","default":0},"total_files":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Files","description":"Distinct source files supporting the confirmed matches before any page or top-N cut. Null for older results or when no authoritative selection was executed. Subject to the same completeness as total_matches."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque cursor for the next page — POST it back as {type: 'page', cursor}. Null on the last page."},"exhaustive":{"type":"boolean","title":"Exhaustive","description":"True only when every eligible component was completely cataloged and evaluated — the scope-wide completeness signal. False whenever coverage is partial or a residual content condition was applied.","default":false},"truncated":{"type":"boolean","title":"Truncated","description":"A structural cap degraded this result; matches shown remain valid.","default":false},"executed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Executed At","description":"When this page's snapshot was read."},"catalog_drifted":{"type":"boolean","title":"Catalog Drifted","description":"The catalog changed since the query was validated.","default":false},"applied_query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Applied Query","description":"Server-rendered display form of the published query."},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The agent's self-graded confidence in the published result — how well the catalog evidence supports its reading of the request, on the shared six-level scale (certain / very_high / high / medium / low / speculative). Null on runs rejected with a `clarification`, on page requests, and on results stored before the field existed."},"clarification":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clarification","description":"Non-null exactly when the run asked a clarifying question instead of executing — only possible when the initial query set `allow_clarification`: no rows, no applied_query, exhaustive false. Filtered search keeps no session; answer it by issuing a new initial query."},"content_evidences":{"items":{"$ref":"#/components/schemas/ContentEvidence"},"type":"array","title":"Content Evidences","description":"Residual content condition passages, server-verified; present only on residual queries."},"evidences":{"items":{"$ref":"#/components/schemas/SearchEvidence"},"type":"array","title":"Evidences","description":"Referent-resolution evidence: the file passages that turned a role or relative referent in the query ('the CEO') into the concrete filter value the published query uses. Agent-cited, then resolved server-side to the caller's own uploaded file exactly like search evidence — an entry that cannot be resolved to a visible file is dropped, never published. Distinct from content_evidences, which are server-verified residual matches. Empty on pure catalog queries."},"field_readability":{"items":{"$ref":"#/components/schemas/FieldReadability"},"type":"array","title":"Field Readability","description":"Filtered fields the extraction could not fully read, server-computed. An empty list is an answer — every field the query filtered on was fully readable — rather than an omission."},"coverage":{"$ref":"#/components/schemas/Coverage"},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallTrace"},"type":"array","title":"Tool Calls"},"steps_used":{"type":"integer","title":"Steps Used","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"Step budget hit before the agent finished. A success, not a failure.","default":false},"candidates_seen":{"type":"integer","title":"Candidates Seen","default":0}},"additionalProperties":false,"type":"object","title":"FilteredSearchResult","description":"The typed outcome of one filtered-search execution (or one page of it).\n\n``exhaustive`` is the coarse completeness signal: when it is false, returned\nmatches are valid, but \"all\"-style claims, ``total_matches`` as a census,\nand zero-match conclusions are not guaranteed. It is scope-wide and\nall-or-nothing, so it cannot say *what* was incomplete;\n``field_readability`` is its per-field companion, naming the filtered\nfields the extraction could not fully read — the difference between \"no\ncomponent matched\" and \"the column you filtered on was largely unreadable\".\nPagination is LIVE — each page re-executes against the current catalog, so\nconcurrent ingestion, deletion, or relabeling may shift later pages (rows\ncan repeat or be skipped across page boundaries); ``catalog_drifted`` says\nthe scope changed since the query was first validated."},"FilteredSearchRow":{"properties":{"component":{"type":"string","title":"Component","description":"Public component name — the tab or document section, matching the component= argument of the file tools (qa-file, read-file, query-tables). Several document rows can share one section name; page_start/page_end distinguish them. A media row's name is the recording stem, display-only (file tools take the whole file)."},"component_kind":{"type":"string","enum":["document","sheet","media"],"title":"Component Kind","description":"The representation containing these observations."},"document_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Type","description":"The profiled document type of this component."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"The component's primary taxonomy category."},"subcategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subcategory","description":"The component's primary taxonomy subcategory."},"page_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Start","description":"First source page containing the component."},"page_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page End","description":"Last source page containing the component."},"summary":{"type":"string","title":"Summary","description":"A description of the component's contents.","default":""},"entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Id","description":"The printed identifier of the matching entity within a register."},"source_row":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Row","description":"The native sheet row containing this entity's facts."},"cells":{"items":{"$ref":"#/components/schemas/FilteredSearchCell"},"type":"array","title":"Cells","description":"Typed observations belonging to this component."},"content_matches":{"items":{"$ref":"#/components/schemas/ContentConditionMatch"},"type":"array","title":"Content Matches","description":"Content criteria this row satisfied, with observed values and the source passages used to verify them."},"source_path":{"type":"string","title":"Source Path","description":"The uploaded file the result belongs to."},"source_file_id":{"type":"string","format":"uuid","title":"Source File Id","description":"Stable identity of the uploaded source file."},"entry_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Entry Id","description":"Catalog entry identity, independent of query wording, filtering and rank. Supporting profile records share an established structural identity; incomplete identities can change on catalog rebuild. Null on legacy units."},"components":{"items":{"$ref":"#/components/schemas/FilteredSearchComponent"},"type":"array","title":"Components","description":"Supporting records grouped into this result, in query order, with their separate values and evidence. The row's component fields mirror the first record for display. Empty when no grouping was needed or on older results."}},"additionalProperties":false,"type":"object","required":["component","component_kind","source_path","source_file_id"],"title":"FilteredSearchRow","description":"One catalog entry, or a historical result, with its supporting evidence."},"FolderFileEntry":{"properties":{"path":{"type":"string","title":"Path","description":"Workspace-relative path of the uploaded file — pass it to file-metadata, qa-file or query-tables as is."},"ingestion_status":{"$ref":"#/components/schemas/IngestionStatus","description":"Where the file is in ingestion; only `ingested` files answer."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Byte size of the uploaded file."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Ledger document category, when classified."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"Ingestion lane (document / table / media), when known."},"uploaded_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Uploaded At","description":"When this file was first registered (ISO 8601)."}},"additionalProperties":false,"type":"object","required":["path","ingestion_status","size_bytes"],"title":"FolderFileEntry","description":"One visible source file in a ``folder-metadata`` listing.\n\n``path`` is the uploaded source path — what the external audience addresses.\n``category`` and ``kind`` (the ingestion lane) are the triage facts: they say\nwhat a file is and which content tool family applies, without a\n``file-metadata`` call per file. ``derived_refs`` is the host's internal\ntwin, never serialized (``exclude=True``, same rule as\n:class:`~ndi_service.app.platform_api.contracts.Evidence`): the agent face\nexpands it into the derivative paths its readers accept."},"FolderMetadataRequest":{"properties":{"directory":{"type":"string","maxLength":1024,"title":"Directory","description":"Folder to describe, relative to the workspace root: `/` (the default) is the root, `evidence/2025` a folder under it. Never prefix it with the workspace id.","default":"/"},"recursive":{"type":"boolean","title":"Recursive","description":"Describe the folder's whole subtree instead of its own files only. A narrow implies true unless sent.","default":false},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Omit to include every file. Use a name exactly as a previous response's `categories[].name` printed it, e.g. `minutes/meeting_minutes`."},"ingestion_status":{"anyOf":[{"$ref":"#/components/schemas/IngestionStatus"},{"type":"null"}],"description":"Only files in this ingestion status — e.g. `failed` to list what did not ingest."},"kind":{"anyOf":[{"$ref":"#/components/schemas/IngestionLane"},{"type":"null"}],"description":"Only files of this kind: `document` (paged or prose), `table`, or `media`."},"name_contains":{"anyOf":[{"type":"string","maxLength":256,"minLength":1},{"type":"null"}],"title":"Name Contains","description":"Only files whose path contains this text, case-insensitively — how to find a file you know by name. `%` and `_` match literally."},"page_size":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Page Size","description":"File entries per page. The counts always cover the whole scope.","default":100},"start_after":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Start After","description":"Resume the file listing strictly after this path: the last `file_entries` path of the previous page."}},"additionalProperties":false,"type":"object","title":"FolderMetadataRequest","description":"Request body for ``folder-metadata``: describe one folder of the workspace.\n\nNon-recursive by default: the first call on a folder orients (its own files\nplus a summary per subfolder), and the caller descends or narrows from\nthere instead of receiving the whole subtree at once.\n\nA narrow (``category``, ``ingestion_status``, ``kind``, ``name_contains``)\n**implies recursion** unless ``recursive`` is sent explicitly: the counts\nthose names come from cover subtrees, so the follow-up call must scope the\nsame subtree. An explicit ``recursive=false`` alongside a narrow is honored."},"FolderMetadataResponse":{"properties":{"directory":{"type":"string","title":"Directory","description":"The folder described, relative to the workspace root (`/` is the root)."},"overall_files":{"type":"integer","title":"Overall Files","description":"Files in scope that the caller can see: the folder, or its subtree when recursive."},"categories":{"items":{"$ref":"#/components/schemas/CategoryCount"},"type":"array","title":"Categories","description":"File counts per category across the scope."},"subdirectories":{"items":{"$ref":"#/components/schemas/SubdirectorySummary"},"type":"array","title":"Subdirectories","description":"The folder's immediate subfolders, each summarizing its subtree."},"ingestion_summary":{"additionalProperties":{"type":"integer"},"propertyNames":{"$ref":"#/components/schemas/IngestionStatus"},"type":"object","title":"Ingestion Summary","description":"File counts per ingestion status across the scope."},"files_truncated":{"type":"boolean","title":"Files Truncated","description":"True when `file_entries` is one page of a longer listing; resume with `start_after`."},"file_entries":{"items":{"$ref":"#/components/schemas/FolderFileEntry"},"type":"array","title":"File Entries","description":"Files in scope, sorted by path, one page at a time."},"hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hint","description":"Present only when a call matched nothing: unfiltered, the nearest existing folder and what it holds; filtered, how many files the folder holds and their categories."},"coverage":{"$ref":"#/components/schemas/Coverage","description":"What the access gate withheld from these counts, as counts and label names only."},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["directory","overall_files","categories","subdirectories","ingestion_summary","files_truncated","file_entries","coverage"],"title":"FolderMetadataResponse","description":"Response body for ``folder-metadata``.\n\nCounts are filtered by both the caller's access predicate and the requested\n``directory`` — the two compose as an intersection, so the view is neither\nwider than the access gate nor wider than the declared scope.\n\n``file_entries`` lists the visible source files the counts cover (same\nscope and recursion as the counts), path-sorted, one page at a time\n(``page_size``); ``files_truncated`` reports a cut page — resume with\n``start_after=<last path>``, or narrow. Source paths only, never ingestion\nderivatives."},"FolderMetadataResult":{"properties":{"result_type":{"type":"string","const":"folder_metadata","title":"Result Type","default":"folder_metadata"},"output":{"$ref":"#/components/schemas/FolderMetadataResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"FolderMetadataResult"},"FrontierReference":{"properties":{"provider":{"type":"string","enum":["GPT-6 Astra","Claude Fable 5.1"],"title":"Provider"},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score"},"median_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Median Seconds"},"p95_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"P95 Seconds"},"captured_cost_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Captured Cost Usd"},"excluded_from_official_sota":{"type":"boolean","const":true,"title":"Excluded From Official Sota","default":true}},"type":"object","required":["provider","score"],"title":"FrontierReference","description":"Astra or Fable result shown for context, never for official SOTA."},"GenerateDomainRequest":{"properties":{"description":{"anyOf":[{"type":"string","maxLength":4000,"minLength":1},{"type":"null"}],"title":"Description","description":"What kinds of files belong in this domain — the classifier-facing brief."},"source":{"anyOf":[{"$ref":"#/components/schemas/ParseResultSource"},{"type":"null"}],"description":"Succeeded Parse job whose content contains the taxonomy to extract."},"sheet_name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Sheet Name","description":"Workbook worksheet to extract. Required when the Parse result contains multiple sheets."},"display_name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Display Name","description":"Optional name hint used when suggesting a display name and slug."},"slug":{"anyOf":[{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},{"type":"null"}],"title":"Slug","description":"Optional slug hint. When omitted, the model derives one from the input."}},"additionalProperties":false,"type":"object","title":"GenerateDomainRequest","description":"Ask the model for an unsaved taxonomy draft.\n\nNothing is persisted: the caller edits the draft, then posts it to\n``POST /v1/domains``. Optional ``display_name`` / ``slug`` seed the\nsuggested identity fields returned alongside the taxonomy. Exactly one\ninput is required: a written description, or a succeeded Parse job."},"GenerateDomainResponse":{"properties":{"taxonomy":{"$ref":"#/components/schemas/Taxonomy-Output"},"suggested_slug":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Suggested Slug"},"suggested_display_name":{"type":"string","maxLength":200,"minLength":1,"title":"Suggested Display Name"},"validation":{"$ref":"#/components/schemas/DomainValidation","description":"Publish-gate check on the normalized draft — always run so the UI knows it can create cleanly."}},"additionalProperties":false,"type":"object","required":["taxonomy","suggested_slug","suggested_display_name","validation"],"title":"GenerateDomainResponse","description":"An unsaved draft ready for the authoring UI to edit and then create."},"GrantsResponse":{"properties":{"key_prefix":{"type":"string","title":"Key Prefix"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"labels":{"items":{"type":"string"},"type":"array","title":"Labels","description":"The labels this key now holds in this workspace."}},"type":"object","required":["key_prefix","workspace_id","labels"],"title":"GrantsResponse"},"GranularRetention":{"type":"string","enum":["short","zero_retention"],"title":"GranularRetention","description":"Retention for document operations — a **client** setting, not a request field.\n\nA data-handling guarantee a caller can accidentally opt out of on one\nendpoint is not a guarantee, so this is configured per client at onboarding\nand appears in no request body."},"GrepMatch":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id","description":"The uploaded file the line belongs to."},"path":{"type":"string","title":"Path","description":"Uploaded source path of the file."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"Public component of the line as file-metadata lists it and read-file accepts as component= (tab name, section); None when the file is the unit (an image, a recording, a raw upload)."},"kind":{"type":"string","enum":["section","tab","media","image","raw"],"title":"Kind","description":"What the component is: a document section, a spreadsheet tab, an image, a recording, or a raw upload."},"line":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line","description":"1-based line number in the text read-file returns for path and component (for a single-component file, the same as reading the whole file); document text only. None on a pointer match: a spreadsheet tab (run-sql its sql_table for the answer), an image (its text or summary matched; ask-file reads it), a recording."},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page","description":"The source page the line sits on; None when the text has no pages or the match is a pointer."},"text":{"type":"string","title":"Text","description":"The matching line, clipped around its first match when it is long."},"sql_table":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sql Table","description":"The run-sql table holding the component's rows (a spreadsheet tab, a document's long tables); None when it has none."},"table":{"anyOf":[{"$ref":"#/components/schemas/GrepTable"},{"type":"null"}],"description":"When the line is a row of a table in document text: that table's lines, title and header row."},"context_before":{"items":{"type":"string"},"type":"array","title":"Context Before","description":"The `before` lines above the match (document text), clipped, top first."},"context_after":{"items":{"type":"string"},"type":"array","title":"Context After","description":"The `after` lines below the match, clipped."}},"additionalProperties":false,"type":"object","required":["file_id","path","component","kind","line","page","text"],"title":"GrepMatch","description":"One matching line, placed where the file tools address it."},"GrepResponse":{"properties":{"matches":{"items":{"$ref":"#/components/schemas/GrepMatch"},"type":"array","title":"Matches","description":"The matching lines, in path order then line order."},"files_matched":{"type":"integer","title":"Files Matched","description":"How many of the scanned files had at least one matching line."},"files_scanned":{"type":"integer","title":"Files Scanned","description":"How many files were read and matched line by line."},"files_unscanned":{"type":"integer","title":"Files Unscanned","description":"Files that could match but were not read before the limits ran out."},"truncated":{"type":"boolean","title":"Truncated","description":"True when max_matches or the scan budget cut the result short."},"mode":{"type":"string","enum":["scan","index"],"title":"Mode","description":"scan: every file in scope was read. index: the content index first narrowed the scope to the files holding the pattern's words, and those were read."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"How the pattern was read, when not as written."},"near_misses":{"items":{"$ref":"#/components/schemas/GrepMatch"},"type":"array","title":"Near Misses","description":"Only when nothing matched: scanned lines holding most of the pattern's words, best first — the document's own wording of what the pattern looked for."},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["matches","files_matched","files_scanned","files_unscanned","truncated","mode"],"title":"GrepResponse","description":"Response of ``grep``.\n\n``files_unscanned`` counts the files that could hold a match but were not read because\n``max_matches`` or the scan budget ran out first — narrow with ``path_prefix`` to reach them."},"GrepResult":{"properties":{"result_type":{"type":"string","const":"grep","title":"Result Type","default":"grep"},"output":{"$ref":"#/components/schemas/GrepResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"GrepResult"},"GrepTable":{"properties":{"first_line":{"type":"integer","title":"First Line","description":"Line of the table's first row (its header), in read-file's line numbers."},"last_line":{"type":"integer","title":"Last Line","description":"Line of the table's last row."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"The text printed just above the table (its caption, units), clipped; None when there is none."},"header":{"type":"string","title":"Header","description":"The column names: the table's first row, or for an HTML table every header row joined per column with ' > ' (empty when it has none), clipped when very wide."},"rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rows","description":"For a table stored as one HTML line (PDF ingestion): how many data rows it has."}},"additionalProperties":false,"type":"object","required":["first_line","last_line","title","header"],"title":"GrepTable","description":"The table a matching line is a row of, so the row reads without another call."},"GroundAudioHints":{"properties":{"transcript_anchor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Anchor","description":"Nearby transcript text used as an anchor."}},"additionalProperties":false,"type":"object","title":"GroundAudioHints"},"GroundDerivedSources":{"properties":{"markdown_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown Url","description":"Markdown from a prior parse of the same file."},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url","description":"Transcript derived from the source media."},"jsonl_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jsonl Url","description":"JSONL artifact derived from the source."},"ocr_artifact_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ocr Artifact Url","description":"Word-level OCR artifact from a prior parse of the same file."}},"additionalProperties":false,"type":"object","title":"GroundDerivedSources","description":"Artifacts from prior NDI runs that speed up / improve grounding."},"GroundItem":{"properties":{"item_id":{"type":"string","title":"Item Id","description":"Caller-assigned identifier echoed back in the result."},"query":{"type":"string","title":"Query","description":"Text, value, or phrase to locate. Closest-match wins."},"semantic":{"type":"boolean","title":"Semantic","description":"When true, ``query`` is a semantic description of what to find (e.g. 'total liabilities') rather than the literal text.","default":false},"hints":{"anyOf":[{"$ref":"#/components/schemas/GroundItemHints"},{"type":"null"}],"description":"Optional modality-specific hints."}},"additionalProperties":false,"type":"object","required":["item_id","query"],"title":"GroundItem","description":"One value to locate in the source document."},"GroundItemHints":{"properties":{"visual":{"anyOf":[{"$ref":"#/components/schemas/GroundVisualHints"},{"type":"null"}]},"spreadsheet":{"anyOf":[{"$ref":"#/components/schemas/GroundSpreadsheetHints"},{"type":"null"}]},"audio":{"anyOf":[{"$ref":"#/components/schemas/GroundAudioHints"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"GroundItemHints"},"GroundItemResult":{"properties":{"item_id":{"type":"string","title":"Item Id"},"found":{"type":"boolean","title":"Found","default":false},"matches":{"items":{"oneOf":[{"$ref":"#/components/schemas/VisualRegionMatch"},{"$ref":"#/components/schemas/AudioRangeMatch"},{"$ref":"#/components/schemas/SpreadsheetRangeMatch"},{"$ref":"#/components/schemas/TextRangeMatch"},{"$ref":"#/components/schemas/JsonlRecordMatch"},{"$ref":"#/components/schemas/RowRangeMatch"},{"$ref":"#/components/schemas/JsonPointerMatch"}],"discriminator":{"propertyName":"match_type","mapping":{"audio_range":"#/components/schemas/AudioRangeMatch","json_pointer":"#/components/schemas/JsonPointerMatch","jsonl_record":"#/components/schemas/JsonlRecordMatch","row_range":"#/components/schemas/RowRangeMatch","spreadsheet_range":"#/components/schemas/SpreadsheetRangeMatch","text_range":"#/components/schemas/TextRangeMatch","visual_region":"#/components/schemas/VisualRegionMatch"}}},"type":"array","title":"Matches"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["item_id"],"title":"GroundItemResult"},"GroundJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"ground","title":"Kind","default":"ground"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__GroundResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"GroundJob"},"GroundJobRequest":{"properties":{"file":{"$ref":"#/components/schemas/FileInput","description":"File to ground. Supported extensions: ``.avi``, ``.bmp``, ``.csv``, ``.doc``, ``.docm``, ``.docx``, ``.eml``, ``.flac``, ``.htm``, ``.html``, ``.jpeg``, ``.jpg``, ``.json``, ``.jsonl``, ``.log``, ``.m4a``, ``.md``, ``.mdx``, ``.mkv``, ``.mov``, ``.mp3``, ``.mp4``, ``.mpga``, ``.msg``, ``.oft``, ``.oga``, ``.ogg``, ``.parquet``, ``.pdf``, ``.png``, ``.ppt``, ``.pptx``, ``.tif``, ``.tiff``, ``.txt``, ``.vsd``, ``.vsdx``, ``.wav``, ``.webp``, ``.xls``, ``.xlsm``, ``.xlsx``, ``.xml``."},"items":{"items":{"$ref":"#/components/schemas/GroundItem"},"type":"array","maxItems":30,"minItems":1,"title":"Items","description":"Items to locate in the source (max 30 per request)."},"derived":{"anyOf":[{"$ref":"#/components/schemas/GroundDerivedSources"},{"type":"null"}]},"options":{"$ref":"#/components/schemas/ndi_service__app__schemas__public__GroundOptions"},"idempotency_key":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Idempotency Key"}},"additionalProperties":false,"type":"object","required":["file","items"],"title":"GroundJobRequest","description":"Body for ``POST /ground`` and ``POST /ground_async``."},"GroundMatch":{"properties":{"word_anchor":{"anyOf":[{"$ref":"#/components/schemas/WordAnchor"},{"type":"null"}],"description":"Unique literal occurrence in the original DOCX/DOCM paragraph text, when available."},"rank":{"type":"integer","minimum":1.0,"title":"Rank","description":"1-based position in this target's matches after the matcher has sorted hits best-first. 1 is the primary location; later ranks are other occurrences or weaker hits. On an HTML source, a hint ranks the visible occurrence nearest that nearby text first; without a hint, rank 1 is the first visible occurrence. Rank restarts at 1 on every target. The list is capped by options.max_matches. Not a score — use match_method and confidence."},"matched_text":{"type":"string","title":"Matched Text","description":"The string actually found at location. Can differ from the request target text when match_method is normalized or semantic."},"match_method":{"type":"string","enum":["exact","normalized","semantic"],"title":"Match Method","description":"How this hit was accepted: exact is a character-for-character copy of the target, normalized ignores case and punctuation, semantic is a meaning-similar or visual hit."},"confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Confidence","description":"0-1 locator confidence when the grounding provider reports one. Independent of match_method: exact and normalized hits can carry a score too. Null only when the provider has no confidence for that match. This is not rank."},"location":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/PageRegion"},{"$ref":"#/components/schemas/SheetRange"},{"$ref":"#/components/schemas/TextSpan"},{"$ref":"#/components/schemas/RowRange"},{"$ref":"#/components/schemas/TableRegion"},{"$ref":"#/components/schemas/JsonPointer"}],"discriminator":{"propertyName":"kind","mapping":{"json_pointer":"#/components/schemas/JsonPointer","page_region":"#/components/schemas/PageRegion","row_range":"#/components/schemas/RowRange","sheet_range":"#/components/schemas/SheetRange","table_region":"#/components/schemas/TableRegion","text_span":"#/components/schemas/TextSpan"}}},{"oneOf":[{"$ref":"#/components/schemas/TextRange"},{"$ref":"#/components/schemas/VisualRegion"},{"$ref":"#/components/schemas/SpreadsheetRange"},{"$ref":"#/components/schemas/JsonlRecord"},{"$ref":"#/components/schemas/JsonPointer"},{"$ref":"#/components/schemas/AudioRange"},{"$ref":"#/components/schemas/RowRange"}],"discriminator":{"propertyName":"kind","mapping":{"audio_range":"#/components/schemas/AudioRange","json_pointer":"#/components/schemas/JsonPointer","jsonl_record":"#/components/schemas/JsonlRecord","row_range":"#/components/schemas/RowRange","spreadsheet_range":"#/components/schemas/SpreadsheetRange","text_range":"#/components/schemas/TextRange","visual_region":"#/components/schemas/VisualRegion"}}}],"title":"Location","description":"Where the quote was found. Kind follows the source: page_region for PDF or image polygons, text_span for character offsets — into the derived text for most sources, but into the uploaded file itself for HTML and email, so tags and headers are counted — sheet_range for a workbook tab and A1, json_pointer for JSON, jsonl_record for a JSONL line, row_range for table rows, or audio_range for media timestamps."},"cropped_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cropped Image Url","description":"Crop URL when options.include_previews is true and the match has a visual region."}},"additionalProperties":false,"type":"object","required":["rank","matched_text","match_method","location"],"title":"GroundMatch"},"GroundOptions-Output":{"properties":{"max_matches":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Max Matches","description":"Maximum matches to return per target, ranked best-first. An HTML source is capped the same way, but only visible rendered text is matched: text hidden by its own style attribute, a hidden or aria-hidden attribute, or an unopened <dialog> is never returned. Hiding that comes from a stylesheet or a media query is not evaluated. A hint ranks the visible occurrence nearest that nearby text first; without a hint, rank 1 is the first visible occurrence.","default":10},"minimum_semantic_score":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Minimum Semantic Score","description":"Deprecated minimum score for semantic and model-scored matches. The exact-match PDF, Word and PowerPoint runtime ignores it: a semantic pick there is kept only when the model rates it above no answer. Exact and normalized matches are unaffected."},"include_previews":{"type":"boolean","title":"Include Previews","description":"When true, matches include cropped_image_url for visual regions. Fetch with the same API key.","default":false},"require_visual_region":{"type":"boolean","title":"Require Visual Region","description":"When true, only matches that have a visual region are kept. Not supported by the current runtime.","default":false},"use_word_level_grounding":{"type":"boolean","title":"Use Word Level Grounding","description":"Experimental. Match targets against word-level OCR bboxes. PDF sources only. Targets shorter than 2 normalized characters return status failed with error needle_too_short.","default":false}},"additionalProperties":false,"type":"object","title":"GroundOptions"},"GroundParseSettings":{"properties":{"figures":{"anyOf":[{"$ref":"#/components/schemas/ParseSettingsFigures"},{"type":"null"}],"description":"How figure regions are kept in the Parse this operation reads. Omit to keep figures. Only figures.mode omit changes the Parse."},"diagrams":{"anyOf":[{"$ref":"#/components/schemas/ParseDiagramsOptions"},{"type":"null"}],"description":"Whether flowchart-like figures are rewritten as Mermaid fences, as diagrams on Parse. Defaults to omit."},"spreadsheet":{"anyOf":[{"$ref":"#/components/schemas/ParseSpreadsheetOptions"},{"type":"null"}],"description":"Workbook controls, as spreadsheet on Parse. Applied to spreadsheet sources only."},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive pages to read, as page_ranges on Parse. On an operation with its own page_ranges the two must agree. With a parse_result source it keeps only those pages of the reused Parse."},"parse_mode":{"anyOf":[{"type":"string","enum":["low","medium"]},{"type":"null"}],"title":"Parse Mode","description":"Parsing effort for the Parse Ground reads: low (the default) or medium. high is not accepted."}},"additionalProperties":false,"type":"object","title":"GroundParseSettings","description":"Settings for the shared Parse Ground reads. Ground has no high mode: it bills per target, not per page."},"GroundRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to search: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"claims":{"anyOf":[{"items":{"$ref":"#/components/schemas/Claim"},"type":"array","maxItems":30,"minItems":1},{"type":"null"}],"title":"Claims","description":"Legacy locator shape. Prefer targets. Exactly one of claims or targets must be set."},"targets":{"anyOf":[{"items":{"$ref":"#/components/schemas/GroundTarget"},"type":"array","maxItems":30,"minItems":1},{"type":"null"}],"title":"Targets","description":"Quoted strings to locate, up to 30. Exactly one of claims or targets must be set."},"options":{"$ref":"#/components/schemas/ndi_service__app__platform_api__document_operations__schemas__GroundOptions","description":"Match caps, semantic score floor, and whether to mint crop preview URLs."},"parse":{"anyOf":[{"$ref":"#/components/schemas/GroundParseSettings"},{"type":"null"}],"description":"Settings for the shared Parse Ground reads, using the same fields as Parse. Omit to use the default Parse. parse_mode high is not accepted on Ground. Only PDF, image, and Word sources on the native_1 provider read that Parse. Elsewhere the settings are not applied and the result's warnings say so. page_ranges keeps only matches on those pages."}},"additionalProperties":false,"type":"object","required":["source"],"title":"GroundRequest","description":"Body for canonical ``POST /v1/ground``.\n\n``targets`` is the canonical p0 locator contract: caller-supplied text to\nresolve back to source locations.\n``claims`` remains as a legacy compatibility shape for existing callers."},"GroundRequestEcho":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to search: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"claims":{"anyOf":[{"items":{"$ref":"#/components/schemas/Claim"},"type":"array","maxItems":30,"minItems":1},{"type":"null"}],"title":"Claims","description":"Legacy locator shape. Prefer targets. Exactly one of claims or targets must be set."},"targets":{"anyOf":[{"items":{"$ref":"#/components/schemas/GroundTarget"},"type":"array","maxItems":30,"minItems":1},{"type":"null"}],"title":"Targets","description":"Quoted strings to locate, up to 30. Exactly one of claims or targets must be set."},"options":{"$ref":"#/components/schemas/GroundOptions-Output","description":"Match caps, semantic score floor, and whether to mint crop preview URLs."},"parse":{"anyOf":[{"$ref":"#/components/schemas/GroundParseSettings"},{"type":"null"}],"description":"Settings for the shared Parse Ground reads, using the same fields as Parse. Omit to use the default Parse. parse_mode high is not accepted on Ground. Only PDF, image, and Word sources on the native_1 provider read that Parse. Elsewhere the settings are not applied and the result's warnings say so. page_ranges keeps only matches on those pages."},"request_type":{"type":"string","const":"ground","title":"Request Type","default":"ground"}},"additionalProperties":false,"type":"object","required":["source"],"title":"GroundRequestEcho","description":"A stored ``ground`` request, read back."},"GroundSpreadsheetHints":{"properties":{"sheet_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet Name","description":"Sheet name hint."},"cell_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Hint","description":"Cell hint such as 'B12'."},"range_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Range Hint","description":"Range hint such as 'B12:D18'."}},"additionalProperties":false,"type":"object","title":"GroundSpreadsheetHints"},"GroundTarget":{"properties":{"id":{"type":"string","title":"Id","description":"Caller-defined id echoed on the matching result target."},"text":{"type":"string","title":"Text","description":"Quoted string to locate in the source."},"hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hint","description":"Nearby free-text context that helps disambiguate a repeated quote."},"semantic":{"type":"boolean","title":"Semantic","description":"When true, text is a description of what to find, not a quote. On deployments that ground PDF, Word and PowerPoint sources with the exact-match runtime, the description picks up to max_matches sentences, table cells, lines, blocks, sections (a heading with its text) or table rows that answer it, best first, and each comes back as an exact match with match_method semantic. hint steers the pick. A target whose answer is not in the source comes back not found. On those deployments, if the picking model is unavailable, the target fails with error native_2_semantic_unavailable. Use false for exact text matching.","default":false},"page_hints":{"anyOf":[{"items":{"type":"integer","minimum":1.0},"type":"array"},{"type":"null"}],"title":"Page Hints","description":"Optional 1-based pages to search first."},"sheet":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet","description":"Workbook tab to search. Ignored for non-spreadsheet sources."}},"additionalProperties":false,"type":"object","required":["id","text"],"title":"GroundTarget","description":"One piece of text to locate in the source document.\n\n``hint`` is nearby free-text context. ``page_hints`` carries 1-based pages\nto prioritize during visual/document search. ``sheet`` names the\nspreadsheet tab to search when the source is a workbook — the same name\nsearch and tool citations publish as ``component`` — so a 30-sheet\nworkbook is not searched whole. Ignored for non-spreadsheet sources."},"GroundTargetResult":{"properties":{"id":{"type":"string","title":"Id","description":"Caller-defined id from the request targets list. Join request to result on this, not on quote text."},"status":{"type":"string","enum":["found","not_found","failed"],"title":"Status","description":"Per-target outcome: found has at least one location, not_found means the quote is not in the document (the job still succeeded), failed is a target-level error."},"matches":{"items":{"$ref":"#/components/schemas/GroundMatch"},"type":"array","title":"Matches","description":"Locations for this target, sorted best-first and numbered by rank. Empty when not found."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Machine-readable reason when status is failed, for example needle_too_short. Null otherwise."}},"additionalProperties":false,"type":"object","required":["id","status"],"title":"GroundTargetResult"},"GroundVisualHints":{"properties":{"anchor_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anchor Text","description":"Nearby text used to disambiguate the location."},"page_hints":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Page Hints","description":"1-based page numbers to prioritize."}},"additionalProperties":false,"type":"object","title":"GroundVisualHints"},"HybridSearchResult":{"properties":{"result_type":{"type":"string","const":"hybrid_search","title":"Result Type","default":"hybrid_search"},"output":{"$ref":"#/components/schemas/SearchResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"HybridSearchResult"},"IngestRequest":{"properties":{"selection":{"oneOf":[{"$ref":"#/components/schemas/FileIdsSelection"},{"$ref":"#/components/schemas/PathPrefixSelection"}],"title":"Selection","discriminator":{"propertyName":"type","mapping":{"file_ids":"#/components/schemas/FileIdsSelection","path_prefix":"#/components/schemas/PathPrefixSelection"}}},"reingest_unchanged":{"type":"boolean","title":"Reingest Unchanged","default":false}},"additionalProperties":false,"type":"object","required":["selection"],"title":"IngestRequest","description":"Body for ``POST /v1/workspaces/{workspace_id}/ingestions``.\n\n``selection`` is the discriminated union that says *what* to process:\n\n* ``{\"type\": \"file_ids\", \"file_ids\": [...]}`` — one file or an explicit\n  batch (up to MAX_INGESTION_BATCH files).\n* ``{\"type\": \"path_prefix\", \"path_prefix\": \"reports/\"}`` — a folder;\n  ``\"\"`` or ``\"/\"`` means the whole workspace.  Set ``stale_only`` to\n  re-ingest only files whose observed hash diverged from the ingested hash\n  since the last run — the routine reconciliation-driven case.\n\nThe ingestion lane (PDF, spreadsheet, audio, etc.) is chosen per file from\nthe file type inside the run.  A caller that had to name a lane would be\nmaintaining the platform's routing table; the union keeps that responsibility\nwhere it belongs."},"IngestedFileOutcome":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"path":{"type":"string","title":"Path"},"status":{"type":"string","enum":["ingested","skipped_unchanged","skipped_empty","failed"],"title":"Status"},"lane":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lane"},"units":{"type":"integer","title":"Units","default":0},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["file_id","path","status"],"title":"IngestedFileOutcome","description":"Per-file, because one corrupt file in a folder of 400 must not fail the run."},"IngestionJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"ingestion","title":"Kind","default":"ingestion"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/IngestionResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"IngestionJob"},"IngestionLane":{"type":"string","enum":["document","table","media","json"],"title":"IngestionLane","description":"The processing lane a file routes through — exactly one per file.\n\n``DOCUMENT`` covers everything the categorize pipeline can split into\nlogical documents (PDF, Office, Visio diagrams, images, text, markdown, HTML, email);\n``TABLE`` covers spreadsheets and CSV; ``MEDIA`` covers audio and video,\nwhich become one speaker-attributed timeline plus sampled frames;\n``JSON`` preserves arbitrary nested structure and may add a table\nprojection for a top-level record array."},"IngestionResult":{"properties":{"result_type":{"type":"string","const":"ingestion","title":"Result Type","default":"ingestion"},"outcomes":{"items":{"$ref":"#/components/schemas/IngestedFileOutcome"},"type":"array","title":"Outcomes"},"files_ingested":{"type":"integer","title":"Files Ingested"},"files_skipped":{"type":"integer","title":"Files Skipped"},"files_empty":{"type":"integer","title":"Files Empty","description":"Files skipped because a valid Parquet input contained zero rows.","default":0},"files_failed":{"type":"integer","title":"Files Failed"},"units_total":{"type":"integer","title":"Units Total"},"kg_build_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Kg Build Job Id","description":"The knowledge-graph build this ingestion chained, when the workspace auto-builds. Poll it to know when the graph covers these files; null means no build was chained (auto-build off, or a pending build already covers them)."},"ledger_understanding_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Ledger Understanding Job Id","description":"The ledger-understanding run this ingestion chained. Null when none was: the workspace holds no journal-line table, an artefact for this exact package already exists, one is already queued, or the workspace turned chaining off."}},"additionalProperties":false,"type":"object","required":["outcomes","files_ingested","files_skipped","files_failed","units_total"],"title":"IngestionResult"},"IngestionStatus":{"type":"string","enum":["discovered","queued","ingesting","ingested","stale","expired","failed","not_required"],"title":"IngestionStatus","description":"The only thing that says whether a file is searchable.\n\n``expired`` cannot be derived from the hash pair: retention clears\n``ingested_hash``, so an aged-out file and a never-ingested file look\nidentical. They call for different customer actions, so the status carries\nthe distinction the hashes cannot."},"InitialFilteredSearch":{"properties":{"type":{"type":"string","const":"query","title":"Type","default":"query"},"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query"},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context"},"result_unit":{"anyOf":[{"type":"string","enum":["source","component","entity"]},{"type":"null"}],"title":"Result Unit","description":"Legacy grouping override. Omit to return catalog entries with their established identities. Supporting sections retain their separate evidence. Explicit legacy values keep their original grouping, counting and pagination semantics.","deprecated":true},"path_prefix":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Path Prefix","description":"Narrow the run to a folder subtree. It intersects with the access filter, never overrides it."},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Narrow the run to exactly these uploaded files: only catalog entries extracted from them can match, and the agent's searches and reads see only them. Each entry names an uploaded source file (never a folder — scope folders with path_prefix; the two add up, so the catalog covers the folder's files plus these). No limit on how many. Unknown or inaccessible paths are refused up front."},"allow_clarification":{"type":"boolean","title":"Allow Clarification","description":"Let the run finish with ONE clarifying question instead of a result, when the request is genuinely ambiguous and the ambiguity materially changes the result. The rejected result carries the question in `clarification` (no rows, no applied_query, exhaustive false); filtered search keeps no session, so answer it by issuing a new initial query. Off — the default — means the run always executes.","default":false}},"additionalProperties":false,"type":"object","required":["query"],"title":"InitialFilteredSearch","description":"Start a filtered search: a natural-language filter/rank/count request."},"IntegrityFindingWire":{"properties":{"check":{"type":"string","title":"Check","description":"Which question of the integrity battery this finding answers, by its check id."},"severity":{"type":"string","enum":["info","warning","blocking"],"title":"Severity","description":"How to read it: informational, a warning to weigh, or a structural absence that blocks."},"table":{"type":"string","title":"Table","description":"The table the finding is about."},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope","description":"The slice this figure is for, such as one entity or one column. Null is the whole file."},"count":{"type":"integer","title":"Count","description":"Rows, journals or values the check found, depending on what it asks."},"amount":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount","description":"The money figure behind the count, at the ledger's own scale."},"sample_keys":{"items":{"type":"string"},"type":"array","title":"Sample Keys","description":"A bounded, ascending sample of the offending keys, so a reader can go and look at them."},"message":{"type":"string","title":"Message","description":"One sentence stating the finding in this package's own column names."}},"additionalProperties":false,"type":"object","required":["check","severity","table","count","sample_keys","message"],"title":"IntegrityFindingWire","description":"One thing the integrity battery established about the population."},"IntegrityReportWire":{"properties":{"findings":{"items":{"$ref":"#/components/schemas/IntegrityFindingWire"},"type":"array","title":"Findings","description":"Everything the battery established, in plan order."},"skipped":{"items":{"$ref":"#/components/schemas/SkippedCheckWire"},"type":"array","title":"Skipped","description":"Checks that did not run. Reported rather than dropped, because an untested condition and a clean one are different answers."},"blocking":{"type":"boolean","title":"Blocking","description":"Whether the package is missing something structural — a balanceable amount, a date, or an account — which is the only condition that stops the stage going further."},"executions":{"anyOf":[{"items":{"$ref":"#/components/schemas/CheckExecutionWire"},"type":"array"},{"type":"null"}],"title":"Executions","description":"Per-statement outcomes; null on legacy readings."}},"additionalProperties":false,"type":"object","required":["findings","skipped","blocking"],"title":"IntegrityReportWire","description":"Whether this population is fit to test, and what could not be asked."},"IntelligentSearchJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"intelligent_search","title":"Kind","default":"intelligent_search"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/IntelligentSearchResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"IntelligentSearchJob"},"IntelligentSearchResult":{"properties":{"result_type":{"type":"string","const":"intelligent_search","title":"Result Type","default":"intelligent_search"},"claims":{"items":{"$ref":"#/components/schemas/DeepSearchVerifiedClaim"},"type":"array","title":"Claims","description":"Calculated answer values bound to recorded executions."},"command_receipts":{"items":{"$ref":"#/components/schemas/CommandReceipt"},"type":"array","title":"Command Receipts","description":"Successful shell calculations cited by this answer."},"sql_receipts":{"items":{"$ref":"#/components/schemas/SqlReceipt"},"type":"array","title":"Sql Receipts","description":"SQL executions supporting calculated answer claims."},"evidences":{"items":{"$ref":"#/components/schemas/SearchEvidence"},"type":"array","title":"Evidences","description":"The evidence the agent found for the query, in order of importance."},"reasoning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning","description":"The agent's account of how the pieces of evidence chain together to address the query, including any assumption it made in reading the query."},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"A direct answer to the query, grounded in the evidences. Always present on a newly finalized run that answered; null when the run rejected the query with a `clarification`, and on results stored before answers became unconditional (the evidence-only mode)."},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"clarification":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clarification","description":"Non-null exactly when the run rejected the query as genuinely ambiguous instead of answering — only possible when the request set `allow_clarification`: one direct question back to the caller, with `answer` and `reasoning` null and `evidences` empty. Answer it by re-asking in the same thread via the result's `session_id`."},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The agent's self-graded confidence in the answer — how well the evidence it retrieved supports it, on the shared six-level scale (certain / very_high / high / medium / low / speculative). Null on runs rejected with a `clarification` and on results stored before the field existed."},"coverage":{"$ref":"#/components/schemas/Coverage"},"candidates_seen":{"type":"integer","title":"Candidates Seen","default":0},"steps_used":{"type":"integer","title":"Steps Used","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"Budget hit before the loop was satisfied. A successful response, not a failure. When the agent authored no answer or reasoning, reasoning carries an actionable briefing and answer stays null so presentation does not treat the briefing as an answer.","default":false},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallTrace"},"type":"array","title":"Tool Calls"},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"The conversation this run belongs to. Send it back as the request's `session_id` to ask a follow-up in the same thread. Null only on results finalized before sessions existed."},"cache":{"anyOf":[{"$ref":"#/components/schemas/AnswerCacheInfo"},{"type":"null"}],"description":"Set when this answer was re-served from the workspace's answer cache instead of derived by this run, with the provenance of the run that did derive it. Null on every run that computed its own answer."},"usage":{"anyOf":[{"$ref":"#/components/schemas/SearchLlmUsage"},{"type":"null"}],"description":"What this run spent on LLM calls. Present only when the request asked for it; null means nothing was measured, not that nothing was spent."},"grounding_job_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Grounding Job Ids","description":"Ground jobs planned for this search's evidences. Empty when postprocessing is disabled for this caller by deployment policy, explicitly disabled for the run, or no evidence is groundable. Absent on older results. When empty or absent, callers may POST /v1/ground explicitly to locate quotes."}},"additionalProperties":false,"type":"object","title":"IntelligentSearchResult"},"InvitationInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","enum":["owner","admin","member"],"title":"Role"},"invited_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Invited By User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"}},"type":"object","required":["id","email","role","created_at"],"title":"InvitationInfo","description":"A live invitation. Passwordless links remain usable for seven days unless withdrawn."},"InvitationListResponse":{"properties":{"invitations":{"items":{"$ref":"#/components/schemas/InvitationInfo"},"type":"array","title":"Invitations"}},"type":"object","required":["invitations"],"title":"InvitationListResponse"},"JeTestingBody":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"What to answer, in the caller's own words. Stripped before its length is checked; a blank query is refused rather than run."},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context","description":"Free-form background for the model — the engagement, the entity, what the caller already knows. It informs the answer; it does not widen or narrow which files the caller may see."},"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Put every uploaded file under one folder subtree, workspace-relative, in the run's scope; `paths`, where the body takes it, adds more files. Omit both for the whole workspace."},"selection_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Selection Id","description":"Confirmed ledger source selection; mutually exclusive with path selectors."},"reasoning_effort":{"anyOf":[{"type":"string","enum":["none","minimal","low","medium","high"]},{"type":"null"}],"title":"Reasoning Effort","description":"Thinking budget for the testing agent; changing it does not change the engine. Null keeps the catalogue's per-model prescription. The console's Effort pill sends 'low' (default) or 'medium'.","default":"low"},"effort":{"anyOf":[{"type":"string","enum":["high","medium","low"]},{"type":"null"}],"title":"Effort","description":"Deprecated and ignored: the service resolves the run's configuration itself. Accepted so clients released before the effort levels were retired keep working; omit it.","deprecated":true},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Scope the run to exactly these uploaded files — the ledger package to test. Every tool the agent runs (listings, reads, SQL) sees only these files and the content ingested from them. Each entry names an uploaded source file, never a folder; scope folders with path_prefix, which adds its files to these. No limit on how many. Unknown or inaccessible paths are refused up front. Omit to test the whole workspace: the agent then orients over every queryable file the caller can see and finds the ledger package itself, exactly as deep-search does when unscoped."},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"Continue a prior je-testing conversation: the id echoed on an earlier result's `session_id`. The agent resumes with that thread's full context — its orientation and its receipted statements — and treats this request as the follow-up. Omit to start a new thread. Only the API key that started the thread may continue it; a thread whose turn is still running returns 409 session_busy."},"allow_clarification":{"type":"boolean","title":"Allow Clarification","description":"Let the agent stop and ask instead of answering, when the test needs something the data cannot tell it (a threshold, the period or entity in scope, the client's definition of a term) or the work turns up a material ambiguity the request does not settle. The result then carries the questions in `clarification_questions` (and as text in `clarification`), with `answer` null; answer them in the same thread via the result's `session_id`, with `clarification_answers` or a follow-up query. Off, the default, means the agent always answers, naming the assumptions it made.","default":false},"clarification_answers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ClarificationAnswer"},"type":"array","maxItems":2,"minItems":1},{"type":"null"}],"title":"Clarification Answers","description":"Answers to the clarifying questions this thread's last turn asked (its result's `clarification_questions`): one entry per question, in order. Send them with that turn's `session_id` and its `query`; the agent then answers that query with the answers applied, and sees which answer belongs to which of its questions. Any other follow-up query in the thread works too — this field is the structured way to answer. Cannot be combined with `allow_clarification`: a run answering questions does not ask again."}},"additionalProperties":false,"type":"object","required":["query"],"title":"JeTestingBody","description":"Body for ``POST /workspaces/{workspace_id}/je-testing``."},"JeTestingJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"je_testing","title":"Kind","default":"je_testing"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/JetResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"JeTestingJob","description":"The je-testing route's response shape.\n\nOne kind, one result: the agent engine answers on ``je_testing``. The\npipeline engine behind ``je-testing-v2`` answers on the same ``JetResult``\nunder its own kind, but that route is unpublished, so this shape names only\nthe kind a caller of the published route can receive."},"JetAgentUsage":{"properties":{"execution_requests":{"type":"integer","minimum":0.0,"title":"Execution Requests","description":"Completed model requests in normal execution cycles."},"compaction_requests":{"type":"integer","minimum":0.0,"title":"Compaction Requests","description":"Completed model requests used to summarize compacted history."},"finalization_requests":{"type":"integer","minimum":0.0,"title":"Finalization Requests","description":"Completed requests in the tool-less recovery finalizer."},"total_requests":{"type":"integer","minimum":0.0,"title":"Total Requests","description":"Sum of execution, compaction, and finalization requests."}},"additionalProperties":false,"type":"object","required":["execution_requests","compaction_requests","finalization_requests","total_requests"],"title":"JetAgentUsage","description":"Completed root-agent model requests by session phase.\n\nThis is intentionally separate from :class:`SearchLlmUsage`: that ledger\ncovers every nested LLM call and token, while this block explains the agent\nprocedure itself. Provider transport attempts are not exposed by the model\nboundary reliably and are therefore not guessed here."},"JetBreakdown":{"properties":{"columns":{"items":{"type":"string"},"type":"array","title":"Columns","description":"Column names, in the statement's own result order."},"rows":{"items":{"items":{"type":"string"},"type":"array"},"type":"array","title":"Rows","description":"Rows in receipt order, cells as text so a decimal, a date and a NULL all survive the wire. At most 200; a longer result sets `truncated` and stays whole on its receipt."},"truncated":{"type":"boolean","title":"Truncated","description":"Whether rows were cut — either by this table's own cap or already on the receipt it came from. A capped breakdown is never read as the complete listing.","default":false},"result_id":{"type":"string","title":"Result Id","description":"`sql_receipts[].result_id` of the statement these rows are."}},"additionalProperties":false,"type":"object","required":["result_id"],"title":"JetBreakdown","description":"The tabular result behind one figure, attached by the server.\n\nWhat a caller asking \"by FSLI and month\" or \"top 10 preparers\" wanted, in the\nshape the question implies. The rows are NOT model-authored and never were:\nthey are the cited receipt's own result, stringified and capped here, attached\nat finalize from :class:`SqlReceipt` rows the run already published. That is\nthe whole design — a figure's table costs the model no output tokens and\ncannot carry a cell no statement returned — and it is why there is no\nreshaping either: the receipt's shape IS the breakdown, so a matrix the SQL\nnever grouped by month is a wrong statement rather than a rendering problem.\n\n``result_id`` names the receipt the rows came from, which is always one of the\nfigure's own citations — either on ``result_ids`` or its ``exception_listing_result_id``,\nthe two id sets the console makes openable — so the breakdown is a convenience\nover the payload's own working, never a second source of truth, and a reader who\nwants the statement, the whole bounded result or its row provenance follows that\nid. (When the model names a listing it did not also list in ``receipt_ids``, that\nid reaches the figure through ``exception_listing_result_id`` rather than\n``result_ids``; both render as receipt buttons, so the table stays one click away\neither way.)"},"JetCriterionOutcome":{"properties":{"criterion_id":{"type":"string","minLength":1,"title":"Criterion Id","description":"Stable short id for this requested test. Its TestSpec and published figure use the same id."},"description":{"type":"string","minLength":1,"title":"Description","description":"The requested test in the caller's terms, without an invented conclusion."},"status":{"type":"string","enum":["performed","cannot_be_performed","incomplete"],"title":"Status","description":"Whether the test produced a finding, proved it could not be performed, or remained incomplete."},"spec_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Id","description":"The committed TestSpec id and matching `figures[].spec_id`. Null when setup never reached a spec."},"blocker":{"anyOf":[{"type":"string","enum":["binding_unresolved","measurement_failed","missing_finding","population_incomplete","context_exhausted","missing_business_parameter","methodology_unresolved","finding_unverified"]},{"type":"null"}],"title":"Blocker","description":"Why an incomplete test did not finish, including reasons newer than the three `incomplete_reason` keeps to. Null for performed and cannot-be-performed tests."},"incomplete_reason":{"anyOf":[{"type":"string","enum":["binding_unresolved","measurement_failed","missing_finding"]},{"type":"null"}],"title":"Incomplete Reason","description":"`blocker` in the three values older SDKs accept: `population_incomplete` and `finding_unverified` read as `measurement_failed`, and every other newer blocker as `missing_finding`. Read `blocker` for the full reason."},"missing_parameters":{"items":{"type":"string","enum":["close_cutoff","balance_tolerance","selected_user","authority_limit","methodology","required_fields"]},"type":"array","title":"Missing Parameters","description":"Policy inputs this test was missing. Set only when `blocker` is `missing_business_parameter` or `methodology_unresolved`; empty otherwise."}},"additionalProperties":false,"type":"object","required":["criterion_id","description","status"],"title":"JetCriterionOutcome","description":"The final disposition of one requested test."},"JetFigure":{"properties":{"criterion":{"type":"string","title":"Criterion","description":"What was tested, in the caller's terms."},"definition":{"type":"string","title":"Definition","description":"The definition it was tested under: which column and values encoded the term, which clock, which basis, which threshold and where it came from."},"spec_id":{"type":"string","title":"Spec Id","description":"The run's committed TestSpec this figure was computed under."},"population":{"type":"integer","minimum":0.0,"title":"Population","description":"The denominator — rows at this test's grain that the criterion ran over."},"count":{"type":"integer","minimum":0.0,"title":"Count","description":"Members of the population that met the criterion."},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value","description":"The exceptions' value as text, so a decimal survives the wire. Null for a count-only criterion."},"result_ids":{"items":{"type":"string"},"type":"array","title":"Result Ids","description":"`sql_receipts[].result_id` of every statement this figure is readable out of."},"exception_listing_result_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exception Listing Result Id","description":"The receipt that lists the exceptions themselves, when one was produced."},"band_group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Band Group","description":"Set when this figure is one band of a family that partitions a population — the same name on every band of the family, whose counts sum to that population."},"cannot_be_performed":{"type":"boolean","title":"Cannot Be Performed","description":"The workspace does not hold the material this criterion needs. `result_ids` then name the probes that establish the absence rather than the figures.","default":false},"breakdown":{"anyOf":[{"$ref":"#/components/schemas/JetBreakdown"},{"type":"null"}],"description":"The tabular result behind this figure, attached by the server from the receipt it cites — the exception listing where there is one, otherwise the single cited statement that returned more than one row. Null when no cited statement holds a table, and on a criterion that could not be performed."}},"additionalProperties":false,"type":"object","required":["criterion","definition","spec_id","population","count"],"title":"JetFigure","description":"One criterion the run tested, and the statements its figures come from.\n\nThe answer's structure on the wire. ``JetResult.answer`` is prose a person\nreads; this is the same content a reviewer can *check*: the definition the\nfigure was computed under, the population it was computed over, the spec that\npinned both, and the ``sql_receipts`` entries the figures are readable out of.\n\nEvery ``result_id`` here names a receipt on the same result, so a reader\nfollows a figure to its statement and its rows without leaving the payload.\n``exception_listing_result_id`` is the one worth opening: an unfiltered count\ngrounds correctly but points at every row, while an exception listing points\nat the rows that failed."},"JetQuality":{"properties":{"status":{"type":"string","enum":["clean","recovered_with_warnings","degraded"],"title":"Status","description":"``clean`` when nothing was recovered; ``recovered_with_warnings`` when a fail-open check, tool failure, or missing audit artifact was recorded; ``degraded`` when the run salvaged working after a hard failure (see ``JetResult.degraded``)."},"validation_warnings":{"items":{"$ref":"#/components/schemas/JetValidationWarning"},"type":"array","title":"Validation Warnings","description":"Fail-open output checks that passed the answer through after their corrective retry."},"tool_failures":{"items":{"$ref":"#/components/schemas/JetToolFailure"},"type":"array","title":"Tool Failures","description":"Non-success tool outcomes the agent recovered from, aggregated by tool and category."},"missing_artifacts":{"items":{"type":"string","enum":["binding","sql_receipts"]},"type":"array","title":"Missing Artifacts","description":"Required audit artifact classes absent from a quantitative result (``binding`` and/or ``sql_receipts``). Empty when every finding is ``cannot_be_performed`` or when both artifacts are present."},"retried_checks":{"items":{"type":"string","enum":["specs","scope","cycle","grain","basis","absence","bands","pointer","delivery","figures"]},"type":"array","title":"Retried Checks","description":"Output-contract check families that cost the answer a model re-emission, whether or not the re-emission repaired them. Attribution only — a retry the model then satisfied is a clean answer, so this does not move ``status``."},"withheld_receipt_figures":{"type":"integer","minimum":0.0,"title":"Withheld Receipt Figures","description":"How many performed figures were published with no readable receipt id — either the statements behind them are not visible to this caller, or the figure was computed without one. The figures themselves are still returned; this counts the ones whose working cannot be inspected.","default":0}},"additionalProperties":false,"type":"object","required":["status"],"title":"JetQuality","description":"Structured execution-quality reporting for one JE-testing result.\n\nDistinguishes a clean, fully evidenced success from a recovered or partially\nvalidated one without changing ``ok`` or inventing figures. Contains only\ncheck names, tool names, outcome categories, and counts — never prompts,\nanswers, evidence bodies, shell output, or client identifiers."},"JetResult":{"properties":{"result_type":{"type":"string","const":"je_testing","title":"Result Type","default":"je_testing"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The direct, grounded answer to the request. Null only on a run that exhausted its budget before authoring one, or that asked `clarification_questions` instead."},"clarification":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Clarification","description":"The run's clarifying questions as plain text, instead of an answer. Only ever set when the request carried `allow_clarification` and the run needed the user's input to go on; `answer` is null and `evidences` empty alongside it. The same questions, structured, are in `clarification_questions`."},"clarification_questions":{"anyOf":[{"items":{"$ref":"#/components/schemas/ClarifyingQuestion"},"type":"array","maxItems":2},{"type":"null"}],"title":"Clarification Questions","description":"The questions behind `clarification`, at most 2, each with up to 4 suggested answers. Answer them with a follow-up on `session_id` that repeats the query and carries `clarification_answers` (one entry per question, a null answer skips it), or with any follow-up query in your own words. Null on every run that answered."},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The agent's self-graded confidence in the answer — how well the evidence and executed statements support it, on the shared six-level scale (certain / very_high / high / medium / low / speculative). Deep search publishes an answer that cites no evidence, claim or receipt at medium at most, and JE testing publishes a run with any `incomplete` criterion at medium at most. Null on exhausted runs and on results stored before the field existed."},"population_statement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Population Statement","description":"The population every figure was computed over — file, period, layer, status, basis, grain — in the run's own words. Null only on a run that never authored an answer."},"figures":{"items":{"$ref":"#/components/schemas/JetFigure"},"type":"array","title":"Figures","description":"One entry per criterion tested, each linked to the receipts its figures are readable out of. Empty on a run that answered without testing anything, or that exhausted its budget first."},"criteria":{"items":{"$ref":"#/components/schemas/JetCriterionOutcome"},"type":"array","title":"Criteria","description":"Every requested test and its final disposition, including tests that never reached binding, measurement, or a published figure. Empty only on results stored before this checklist existed."},"discrepancies":{"items":{"type":"string"},"type":"array","title":"Discrepancies","description":"Where the data contradicted the request's premise or a figure it stated. Empty when nothing did — the run is asked for this explicitly, so an empty list is an answer rather than an omission."},"reasoning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning","description":"How the receipted statements chain together into the answer."},"evidences":{"items":{"$ref":"#/components/schemas/SearchEvidence"},"type":"array","title":"Evidences","description":"The material the answer cites, each resolved to the caller's own uploaded file."},"sql_receipts":{"items":{"$ref":"#/components/schemas/SqlReceipt"},"type":"array","title":"Sql Receipts","description":"Every statement the run executed, in execution order — the answer's working."},"binding":{"anyOf":[{"$ref":"#/components/schemas/LedgerBindingWire"},{"type":"null"}],"description":"The definitional layer the run committed and computed under — which column is the period, which values mean posted, which clock a timing test was verbed on. Null on a run that answered without binding a ledger, which is only possible before any statement ran."},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallTrace"},"type":"array","title":"Tool Calls","description":"One entry per tool the run invoked, in execution order — the tool's name, a digest of its arguments, how many results came back, and how long it took. The run's shape, not its content."},"steps_used":{"type":"integer","title":"Steps Used","description":"Legacy procedure-step count retained for compatibility. It is engine-specific and is not a model-request count; agent runs expose completed root-model requests in `agent_usage`. Read it with `exhausted`, which says whether the configured request budget ran out before the run was satisfied.","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"Step budget hit before the run was satisfied. A successful response, not a failure.","default":false},"degraded":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degraded","description":"Why this result is degraded, when it is. The run broke before it could finalize an answer but had already computed real working, so what is published is that working — `sql_receipts` and `binding` — with `figures` empty and `answer` saying so. Null on every run that finished normally, exhausted ones included."},"quality":{"anyOf":[{"$ref":"#/components/schemas/JetQuality"},{"type":"null"}],"description":"Structured execution quality: clean vs recovered-with-warnings vs degraded, plus the fail-open checks, tool-failure counts, and missing audit artifacts that produced that status. JE-testing always sets this on a finished run. Other JetResult subclasses (deep search) leave it null. Null also on results stored before the field existed."},"execution_status":{"anyOf":[{"type":"string","enum":["performed","partially_performed","not_performed"]},{"type":"null"}],"title":"Execution Status","description":"Whether the run tested what it was asked to test: ``performed`` when every figure was computed, ``partially_performed`` when some criteria could not be, ``not_performed`` when none could. Read it alongside `quality`, which grades how well a performed test went. JE-testing always sets this on a finished run; other JetResult subclasses (deep search) leave it null, as do results stored before the field existed."},"agent_usage":{"anyOf":[{"$ref":"#/components/schemas/JetAgentUsage"},{"type":"null"}],"description":"Root-agent model requests split into execution, compaction, and recovery finalization. Null on the fixed pipeline and on results stored before this telemetry existed; use `usage` for all nested LLM cost."},"spec_digest":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Digest","description":"A short fingerprint of what this run committed to TEST — the rows, grain, clock, encoding, thresholds and time window each criterion was pinned to — with the free-text justifications beside those choices excluded. Two runs of the same question carry the same value when they tested the same thing, so an unstable answer can be told apart from an answer to a quietly different question without re-reading either run. Null on a run that committed no test spec, and on other JetResult subclasses."},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"The conversation this run belongs to. Send it back as the request's `session_id` to ask a follow-up in the same thread."},"usage":{"anyOf":[{"$ref":"#/components/schemas/SearchLlmUsage"},{"type":"null"}],"description":"What this run spent on LLM calls. Present only when the request asked for it; null means nothing was measured, not that nothing was spent."},"grounding_job_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array"},{"type":"null"}],"title":"Grounding Job Ids","description":"Ground jobs planned for this search's evidences. Empty when postprocessing is disabled for this caller by deployment policy, explicitly disabled for the run, or no evidence is groundable. Absent on older results. When empty or absent, callers may POST /v1/ground explicitly to locate quotes."}},"additionalProperties":false,"type":"object","title":"JetResult","description":"The result of one journal-entry-testing run (``JobKind.JE_TESTING``).\n\nShape-compatible with :class:`IntelligentSearchResult` for the retrieval\ncore — evidences, reasoning, answer, the tool-call trace, the session\nhandle, usage and exhaustion all mean exactly what they mean there — plus\n``sql_receipts``: the statements behind the answer.\n\n``figures`` is the answer's checkable half: one entry per criterion, each\nnaming the receipts its figures are readable out of. There is no ``coverage``\nblock — v1 runs on tables the caller selected, and an honest coverage number\nneeds an orientation pass that reports what was *not* selected."},"JetToolFailure":{"properties":{"tool":{"type":"string","title":"Tool","description":"Tool name that produced the non-success outcome (for example ``run_command``)."},"outcome":{"type":"string","enum":["model_retry","command_error","timeout","tool_error"],"title":"Outcome","description":"Category of the non-success: ``model_retry`` (a call the run corrected: a gate refusal, a rejected argument shape or a validation retry; does not lower `quality.status`), ``command_error`` (non-zero shell exit), ``timeout``, or ``tool_error`` (the tool itself failed, for example a SQL error)."},"count":{"type":"integer","minimum":1.0,"title":"Count","description":"How many times this tool×outcome pair occurred in the run."}},"additionalProperties":false,"type":"object","required":["tool","outcome","count"],"title":"JetToolFailure","description":"How many times one tool returned a non-success outcome this run."},"JetValidationWarning":{"properties":{"check":{"type":"string","enum":["specs","scope","cycle","grain","basis","absence","bands","pointer","delivery","figures"],"title":"Check","description":"Stable machine-readable name of the fail-open check that was not satisfied. ``specs`` covers two causes: a finding that names no committed test, and a finding computed for a test the run still declared blocked by a missing parameter."},"status":{"type":"string","const":"failed_open","title":"Status","description":"Always ``failed_open``: the check rejected the answer once, then passed it through.","default":"failed_open"}},"additionalProperties":false,"type":"object","required":["check"],"title":"JetValidationWarning","description":"One output-contract check that failed open after its corrective retry."},"Job":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"$ref":"#/components/schemas/JobKind","description":"Which operation created this job. Discriminates the result payload."},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/StorageConnectionValidationResult"},{"$ref":"#/components/schemas/FolderMetadataResult"},{"$ref":"#/components/schemas/FileMetadataResult"},{"$ref":"#/components/schemas/ReadFileResult"},{"$ref":"#/components/schemas/HybridSearchResult"},{"$ref":"#/components/schemas/GrepResult"},{"$ref":"#/components/schemas/RunSqlResult"},{"$ref":"#/components/schemas/LocateResult"},{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__ParseResult"},{"$ref":"#/components/schemas/SplitResult"},{"$ref":"#/components/schemas/ClassifyResult"},{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__CategorizeResult"},{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__ExtractResult"},{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__GroundResult"},{"$ref":"#/components/schemas/IngestionResult"},{"$ref":"#/components/schemas/ReconciliationResult"},{"$ref":"#/components/schemas/KnowledgeGraphBuildResult"},{"$ref":"#/components/schemas/LedgerUnderstandingResult"},{"$ref":"#/components/schemas/LedgerUnderstandingResetResult"},{"$ref":"#/components/schemas/LedgerParseExhibitsResult"},{"$ref":"#/components/schemas/UploadFileResult"},{"$ref":"#/components/schemas/ReplaceFileResult"},{"$ref":"#/components/schemas/DeleteFileResult"},{"$ref":"#/components/schemas/DeleteFilesResult"},{"$ref":"#/components/schemas/WorkspaceDeleteResult"},{"$ref":"#/components/schemas/TenantPurgeResult"},{"$ref":"#/components/schemas/IntelligentSearchResult"},{"$ref":"#/components/schemas/QaFileResult"},{"$ref":"#/components/schemas/QaTablesResult"},{"$ref":"#/components/schemas/FilteredSearchResult"},{"$ref":"#/components/schemas/JetResult"},{"$ref":"#/components/schemas/DeepSearchV2Result"},{"$ref":"#/components/schemas/AutomaticAgentResult"},{"$ref":"#/components/schemas/AutomaticSearchResult"}],"discriminator":{"propertyName":"result_type","mapping":{"automatic_agent":"#/components/schemas/AutomaticAgentResult","automatic_search":"#/components/schemas/AutomaticSearchResult","categorize":"#/components/schemas/ndi_service__app__platform_api__results__CategorizeResult","classify":"#/components/schemas/ClassifyResult","deep_search_v2":"#/components/schemas/DeepSearchV2Result","extract":"#/components/schemas/ndi_service__app__platform_api__results__ExtractResult","file_delete":"#/components/schemas/DeleteFileResult","file_metadata":"#/components/schemas/FileMetadataResult","file_replace":"#/components/schemas/ReplaceFileResult","file_upload":"#/components/schemas/UploadFileResult","files_delete":"#/components/schemas/DeleteFilesResult","filtered_search":"#/components/schemas/FilteredSearchResult","folder_metadata":"#/components/schemas/FolderMetadataResult","grep":"#/components/schemas/GrepResult","ground":"#/components/schemas/ndi_service__app__platform_api__results__GroundResult","hybrid_search":"#/components/schemas/HybridSearchResult","ingestion":"#/components/schemas/IngestionResult","intelligent_search":"#/components/schemas/IntelligentSearchResult","je_testing":"#/components/schemas/JetResult","kg_build":"#/components/schemas/KnowledgeGraphBuildResult","ledger_parse_exhibits":"#/components/schemas/LedgerParseExhibitsResult","ledger_understanding":"#/components/schemas/LedgerUnderstandingResult","ledger_understanding_reset":"#/components/schemas/LedgerUnderstandingResetResult","locate":"#/components/schemas/LocateResult","parse":"#/components/schemas/ndi_service__app__platform_api__results__ParseResult","qa_file":"#/components/schemas/QaFileResult","qa_tables":"#/components/schemas/QaTablesResult","read_file":"#/components/schemas/ReadFileResult","reconciliation":"#/components/schemas/ReconciliationResult","run_sql":"#/components/schemas/RunSqlResult","split":"#/components/schemas/SplitResult","storage_connection_validate":"#/components/schemas/StorageConnectionValidationResult","tenant_purge":"#/components/schemas/TenantPurgeResult","workspace_delete":"#/components/schemas/WorkspaceDeleteResult"}}},{"type":"null"}],"title":"Result","description":"Present on succeeded while retained. Also present on a running classify or extract job that already published a progressive result (labels or values). Null while queued, after its content is removed, and once the job, or the job it ran for, is cancelled."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","kind","status","created_at"],"title":"Job","description":"Every slow method returns one of these (spec 12 §1.4).\n\nThere is no ``/parse`` + ``/parse_async`` pair: every job-creating route\nreturns ``202`` with a queued job and accepts ``?wait_seconds=``, returning\n``200`` with a terminal job if the work finished inside the window. The\ncaller's code path is the same either way — read ``status``."},"JobAccepted":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"}},"additionalProperties":false,"type":"object","required":["job_id"],"title":"JobAccepted","description":"Returned by the async endpoints: the job started, poll ``GET /jobs/{job_id}``."},"JobCost":{"properties":{"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"pricing_version":{"type":"string","title":"Pricing Version","description":"The dollar price-sheet version pinned when this job was accepted."},"total_usd":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d{0,9}0*$","title":"Total Usd","description":"Sum of the component amounts in USD, serialized as a decimal string."},"lines":{"items":{"$ref":"#/components/schemas/CostLine"},"type":"array","title":"Lines","description":"The independently priced Parse and operation components, including paid reuse."}},"additionalProperties":false,"type":"object","required":["pricing_version","total_usd","lines"],"title":"JobCost","description":"An immutable USD price independent of the legacy credit schedule."},"JobDownloadLink":{"properties":{"url":{"type":"string","title":"Url","description":"Signed download URL. Treat it as a temporary credential. Customer-workspace links recheck storage access and job availability when opened; other links remain valid until expiry."},"expires_at":{"type":"integer","title":"Expires At","description":"Expiry of the URL, as Unix epoch seconds."},"file_name":{"type":"string","title":"File Name","description":"Name the file is served under."},"content_type":{"type":"string","title":"Content Type","description":"Media type the file is served with."},"disposition":{"type":"string","enum":["inline","attachment"],"title":"Disposition","description":"Disposition the file is served with."}},"additionalProperties":false,"type":"object","required":["url","expires_at","file_name","content_type","disposition"],"title":"JobDownloadLink","description":"Short-lived signed URL to one job file, fetchable without API-key headers."},"JobDownloadLinkRequest":{"properties":{"resource":{"type":"string","enum":["split-artifacts","ground-crops","ground-transcript","parse-images","parse-transcript","converted-pdf","spreadsheet-cell-maps"],"title":"Resource","description":"Route segment of the job file, as in its stable URL `/v1/jobs/{job_id}/{resource}/{ref}`."},"ref":{"type":"string","maxLength":4096,"minLength":1,"title":"Ref","description":"Opaque file ref, the last segment of that stable URL."},"disposition":{"type":"string","enum":["inline","attachment"],"title":"Disposition","description":"Whether a browser should render the file in place or save it. Types unsafe to render are always attachments.","default":"inline"}},"additionalProperties":false,"type":"object","required":["resource","ref"],"title":"JobDownloadLinkRequest","description":"Body for ``POST /jobs/{job_id}/download-links``."},"JobError":{"properties":{"code":{"type":"string","title":"Code","description":"Stable machine-readable error code."},"message":{"type":"string","title":"Message","description":"Human-readable failure detail."}},"type":"object","required":["code","message"],"title":"JobError"},"JobKind":{"type":"string","enum":["parse","split","classify","categorize","extract","ground","ingestion","reconciliation","kg_build","file_upload","file_replace","upload_session_complete","file_delete","files_delete","workspace_delete","intelligent_search","folder_metadata","file_metadata","read_file","hybrid_search","grep","run_sql","locate","qa_file","qa_tables","filtered_search","je_testing","je_testing_v2","deep_search_v2","automatic_agent","ledger_understanding","ledger_understanding_reset","ledger_parse_exhibits","tenant_purge","storage_connection_validate"],"title":"JobKind","description":"What a job is doing. Open enum — a new member is additive."},"JobList":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/JobSummary"},"type":"array","title":"Jobs"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as ``cursor`` to fetch the next (older) page; null when exhausted."}},"type":"object","title":"JobList","description":"Response for ``GET /jobs``: newest first, cursor-paginated."},"JobProgress":{"properties":{"units_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Units Total"},"units_done":{"type":"integer","title":"Units Done","default":0},"items_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Items Total","description":"Files, for batch kinds."},"items_done":{"type":"integer","title":"Items Done","default":0},"items_failed":{"type":"integer","title":"Items Failed","description":"Quarantined after exhausting retries, for batch kinds. Excluded from items_done.","default":0},"stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stage","description":"Current pipeline stage, for display only."},"knowledge_graph":{"anyOf":[{"$ref":"#/components/schemas/KnowledgeGraphBuildProgress"},{"type":"null"}],"description":"Detail only a kg_build reports; null for every other job kind."},"routing":{"anyOf":[{"$ref":"#/components/schemas/AutomaticSearchRouting"},{"type":"null"}],"description":"The route an automatic search chose, from the moment it chose it, so a caller can show the decision while the chosen pipeline runs; timings arrive with the result's ``routing``. Null for every other job kind."}},"additionalProperties":false,"type":"object","title":"JobProgress","description":"Absent until the job is ``running``."},"JobStatus-Input":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"title":"JobStatus","description":"``cancelled`` is a first-class terminal status, not a ``failed`` variant.\n\nConflating them makes error-rate metrics lie and forces every client to\nstring-match an error code."},"JobSummary":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"},"action":{"type":"string","title":"Action"},"status":{"type":"string","title":"Status"},"error":{"anyOf":[{"$ref":"#/components/schemas/JobError"},{"type":"null"}]},"is_example":{"type":"boolean","title":"Is Example","description":"True for provisioned Playground example jobs.","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"credits_used":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits Used","description":"Credits charged to this job per the ledger. 0 for failed/cancelled jobs (never charged) and zero-credit example jobs; null while the job is non-terminal (not counted yet) or for a succeeded job predating the ledger."}},"type":"object","required":["job_id","action","status","created_at"],"title":"JobSummary","description":"One row of ``GET /jobs`` — deliberately light (no result payloads)."},"JobUsage":{"properties":{"lines":{"items":{"$ref":"#/components/schemas/UsageLine"},"type":"array","title":"Lines","description":"One line per part. Their credits sum to the job's credits; waived parts remain listed at 0 credits."}},"additionalProperties":false,"type":"object","required":["lines"],"title":"JobUsage","description":"How a job's final credits were computed."},"JoinEdgeWire":{"properties":{"left_table":{"type":"string","title":"Left Table","description":"The table the edge is measured from."},"left_column":{"type":"string","title":"Left Column","description":"The column on that table the edge joins on."},"right_table":{"type":"string","title":"Right Table","description":"The table the edge is measured against."},"right_column":{"type":"string","title":"Right Column","description":"The column on that table the edge joins on."},"left_columns":{"items":{"type":"string"},"type":"array","title":"Left Columns","description":"Ordered composite source key; empty means the scalar column."},"right_columns":{"items":{"type":"string"},"type":"array","title":"Right Columns","description":"Ordered composite reference key; empty means the scalar column."},"left_tables":{"items":{"type":"string"},"type":"array","title":"Left Tables","description":"Selected population members measured together; empty means the scalar table."},"left_null_rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Left Null Rows","description":"Source rows with a missing key component."},"right_null_rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Right Null Rows","description":"Reference rows with a missing key component."},"right_duplicate_keys":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Right Duplicate Keys","description":"Reference keys appearing more than once, making row enrichment unsafe."},"left_in_right":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Left In Right","description":"Share of the left column's distinct values that appear in the right."},"right_in_left":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Right In Left","description":"Share of the right column's distinct values that appear in the left."},"unmatched_left":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unmatched Left","description":"Distinct left values with no match on the right."},"unmatched_right":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unmatched Right","description":"Distinct right values with no match on the left."}},"additionalProperties":false,"type":"object","required":["left_table","left_column","right_table","right_column"],"title":"JoinEdgeWire","description":"One expected join of the ledger's graph, measured in both directions."},"JsonPointer":{"properties":{"kind":{"type":"string","const":"json_pointer","title":"Kind","default":"json_pointer"},"pointer":{"type":"string","pattern":"^(?:$|/)","title":"Pointer"}},"additionalProperties":false,"type":"object","required":["pointer"],"title":"JsonPointer","description":"An RFC 6901 pointer into a JSON source; an empty string means the root."},"JsonPointerMatch":{"properties":{"match_type":{"type":"string","const":"json_pointer","title":"Match Type","default":"json_pointer"},"pointer":{"type":"string","pattern":"^(?:$|/)","title":"Pointer"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["pointer"],"title":"JsonPointerMatch"},"JsonValue":{},"JsonlRecord":{"properties":{"kind":{"type":"string","const":"jsonl_record","title":"Kind","default":"jsonl_record"},"row_offset":{"type":"integer","title":"Row Offset"},"column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column"}},"additionalProperties":false,"type":"object","required":["row_offset"],"title":"JsonlRecord"},"JsonlRecordMatch":{"properties":{"match_type":{"type":"string","const":"jsonl_record","title":"Match Type","default":"jsonl_record"},"line_index":{"type":"integer","title":"Line Index"},"keys":{"items":{"type":"string"},"type":"array","title":"Keys"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["line_index","keys"],"title":"JsonlRecordMatch"},"KeyAttempt":{"properties":{"columns":{"items":{"type":"string"},"type":"array","title":"Columns","description":"Ordered nominated identity; empty when no candidate was available."},"nominated_by":{"type":"string","enum":["automatic","human","proposal","model"],"title":"Nominated By","description":"Origin of the nomination, not its acceptance: the census search, a reviewer, the discovery structure proposal, or the model's key recovery."},"outcome":{"type":"string","enum":["qualified","rejected","unmeasured"],"title":"Outcome","description":"Measured gate result or incomplete evidence."},"reason":{"type":"string","title":"Reason","description":"Aggregate explanation; never journal values."},"null_counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Null Counts","description":"Exact null counts per column, not a row-wise union."},"measured_rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Measured Rows","description":"Observed row coverage, absent before key measurement."},"expected_rows":{"type":"integer","title":"Expected Rows","description":"Complete primary row count."},"balanced_share":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balanced Share","description":"Measured balance share, absent when unmeasured."}},"additionalProperties":false,"type":"object","required":["columns","nominated_by","outcome","reason","expected_rows"],"title":"KeyAttempt"},"KeyGrantSummary":{"properties":{"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"labels":{"items":{"type":"string"},"type":"array","title":"Labels"}},"type":"object","required":["workspace_id","labels"],"title":"KeyGrantSummary","description":"One workspace grant for a key listing."},"KeyGrantsListResponse":{"properties":{"key_prefix":{"type":"string","title":"Key Prefix"},"grants":{"items":{"$ref":"#/components/schemas/KeyGrantSummary"},"type":"array","title":"Grants"}},"type":"object","required":["key_prefix","grants"],"title":"KeyGrantsListResponse"},"KnowledgeGraphBuildJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"kg_build","title":"Kind","default":"kg_build"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/KnowledgeGraphBuildResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"KnowledgeGraphBuildJob"},"KnowledgeGraphBuildProgress":{"properties":{"phase_index":{"type":"integer","title":"Phase Index","description":"0-based position of the current phase in the build's fixed run order; equals phase_count when done."},"phase_count":{"type":"integer","title":"Phase Count","description":"How many phases a build passes through before it is done. Currently 9."},"countable":{"type":"boolean","title":"Countable","description":"Whether items_total/items_done describe this phase. False for the phases that are a single step, which have no unit to count — draw those as indeterminate rather than as a bar stuck at zero."},"documents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Documents","description":"Documents registered from the corpus, once the registering phase has run."},"mentions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Mentions","description":"Mentions extracted across the corpus, once the validating phase has run."},"step":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Step","description":"The span in flight inside a single-step phase, reported by the running step itself. Null when the phase counts its own units, or before the step has reported one."},"step_done":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Step Done","description":"Units of `step` finished, when it has countable units."},"step_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Step Total","description":"Units `step` has to get through, when that is known."}},"additionalProperties":false,"type":"object","required":["phase_index","phase_count","countable"],"title":"KnowledgeGraphBuildProgress","description":"Where a ``kg_build`` is, beyond what ``stage`` alone can say.\n\nA graph build runs for minutes to hours through a fixed sequence of phases,\nand ``stage`` names only the current one. Turning that into \"how far along\"\notherwise means hard-coding the build engine's phase order in every client —\nan order that lives in another package and is free to gain a phase. So the\nposition is reported rather than inferred.\n\nThe counters are deliberately not a percentage. The phases are wildly unequal\n(extraction is ~60% of a build, and its per-document cost varies 25x with how\ndense the documents are), so weighting them is a presentation decision, made\nagainst measurements, that belongs to whoever is drawing the bar."},"KnowledgeGraphBuildRequest":{"properties":{"force":{"type":"boolean","title":"Force","description":"Clear the workspace's knowledge-graph store and rebuild from scratch. The default resumes from the durable store, reusing every extraction, embedding, and resolution verdict already paid for; a force build discards that cache — use it only when the store is suspected corrupt or the ontology's meaning changed under a version it did not re-key.","default":false}},"additionalProperties":false,"type":"object","title":"KnowledgeGraphBuildRequest","description":"Request body for ``POST /v1/workspaces/{id}/knowledge-graph/builds``."},"KnowledgeGraphBuildResult":{"properties":{"result_type":{"type":"string","const":"kg_build","title":"Result Type","default":"kg_build"},"snapshot_id":{"type":"string","title":"Snapshot Id"},"status":{"type":"string","enum":["published","empty_no_mentions"],"title":"Status","description":"published when this build wrote a snapshot. empty_no_mentions when every planned document extracted and none produced a mention, so the job succeeded without publishing a snapshot.","default":"published"},"files_covered":{"type":"integer","title":"Files Covered","description":"Source files whose ledger version matched the build-time corpus at finalize; files replaced during the build are excluded and will show as needing a rebuild."},"node_count":{"type":"integer","title":"Node Count","default":0},"edge_count":{"type":"integer","title":"Edge Count","default":0},"rebuilt":{"type":"boolean","title":"Rebuilt","description":"True when a force build cleared the prior store first.","default":false},"files_failed":{"items":{"$ref":"#/components/schemas/KnowledgeGraphFileFailure"},"type":"array","title":"Files Failed","description":"Files quarantined after exhausting their retries. Not in the graph, and not marked covered."}},"additionalProperties":false,"type":"object","required":["snapshot_id","files_covered"],"title":"KnowledgeGraphBuildResult","description":"The corpus-level graph build: what one snapshot covered.\n\nThe graph is a property of the whole corpus, not a per-file derivative, so\nthis reports totals rather than per-file outcomes — with one exception:\n``files_failed`` is per-file because a build now finishes without the files it\ncould not process, and \"which files is this graph blind to\" is otherwise\nunanswerable from the outside. A file listed there is excluded from\n``files_covered`` and stays marked as needing a rebuild.\n\n``snapshot_id`` is the new graph's cache key — the same value ``kg_info``\nreturns — so a caller can tell the build actually advanced the served graph."},"KnowledgeGraphConfig":{"properties":{"auto_build":{"type":"boolean","title":"Auto Build","description":"Build the graph automatically after each ingestion completes. On by default; turn it off to build only on request (a build is billable and long-running). Ingestion skips the automatic build once the graph corpus reaches the deployment's kg.auto_build.max_corpus_files limit; an explicit build still runs.","default":true},"exclude_path_prefixes":{"items":{"type":"string","maxLength":1024},"type":"array","maxItems":128,"title":"Exclude Path Prefixes","description":"Files whose path starts with any of these are kept out of the graph corpus (override per file)."},"exclude_categories":{"items":{"type":"string","maxLength":1024},"type":"array","maxItems":128,"title":"Exclude Categories","description":"Files whose category is any of these are kept out of the graph corpus (override per file)."}},"additionalProperties":false,"type":"object","title":"KnowledgeGraphConfig","description":"A workspace's knowledge-graph build policy.\n\nThe defaults keep the whole corpus in scope and build the graph after every\ningestion, so fact search and deep search have it to navigate by. Set\n``auto_build=false`` for a workspace that builds only on request.\n``exclude_path_prefixes`` and ``exclude_categories`` are the workspace-wide\nskip rules a file's ``graph_inclusion`` can override — a file matching either\nis left out of the graph corpus unless it is explicitly ``include``\\ d."},"KnowledgeGraphFileFailure":{"properties":{"path":{"type":"string","title":"Path"},"phase":{"type":"string","enum":["classifying","extracting"],"title":"Phase","description":"Where it failed: 'classifying' (never registered) or 'extracting'."},"error":{"type":"string","title":"Error","description":"The verbatim final cause, as the failing step reported it."}},"additionalProperties":false,"type":"object","required":["path","phase","error"],"title":"KnowledgeGraphFileFailure","description":"One source file the build could not get into the graph."},"LedgerAssessmentWire":{"properties":{"status":{"type":"string","enum":["ready","limited","needs_scope","needs_source_selection","needs_decision","execution_failed","unknown"],"title":"Status","description":"Summary; inspect procedure readiness and execution coverage before relying on results.","default":"unknown"},"reasons":{"items":{"type":"string"},"type":"array","title":"Reasons","description":"Why the summary is not fully ready."},"planned_checks":{"type":"integer","title":"Planned Checks","description":"Statements planned, excluding missing-prerequisite skips.","default":0},"completed_checks":{"type":"integer","title":"Completed Checks","description":"Statements completed, including zero-finding results.","default":0},"failed_checks":{"type":"integer","title":"Failed Checks","description":"Planned statements that failed execution.","default":0},"skipped_checks":{"type":"integer","title":"Skipped Checks","description":"Checks not planned because prerequisites were absent.","default":0},"not_run_checks":{"type":"integer","title":"Not Run Checks","description":"Planned statements withheld after an earlier resource failure.","default":0},"execution_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Execution Coverage","description":"Completed over planned statements; null when unknown or none planned."},"procedures":{"additionalProperties":{"$ref":"#/components/schemas/ProcedureReadinessWire"},"type":"object","title":"Procedures","description":"Procedure-specific readiness, not a JET gate."},"populations":{"items":{"$ref":"#/components/schemas/PopulationCandidateWire"},"type":"array","title":"Populations","description":"Bounded same-scope candidate evidence."},"population_count":{"type":"integer","title":"Population Count","description":"Total candidate count before bounding the evidence list.","default":0},"source_review_available":{"type":"boolean","title":"Source Review Available","description":"Whether this completed current reading can open the source-review correction flow.","default":false},"structure_review_available":{"type":"boolean","title":"Structure Review Available","description":"Whether complete measured schema supports a structural proposal, not key acceptance.","default":false},"header_status":{"type":"string","enum":["not_required","unmeasured","complete","partial","unsafe","failed"],"title":"Header Status","description":"Declared header tuple's exact coverage and cardinality verdict.","default":"unmeasured"},"header_unmatched_lines":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Header Unmatched Lines","description":"Unmatched lines retained by optional LEFT JOIN enrichment."},"header_duplicate_keys":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Header Duplicate Keys","description":"Excess header rows on the complete declared tuple."}},"additionalProperties":false,"type":"object","title":"LedgerAssessmentWire","description":"Evidence-based assessment independent of job success and structural blocking."},"LedgerBindingWire":{"properties":{"tables":{"items":{"$ref":"#/components/schemas/BoundTable"},"type":"array","title":"Tables"},"policy_sheets":{"items":{"type":"string"},"type":"array","title":"Policy Sheets","description":"Documents the run treated as settling parameters (a sequence policy, a topside register)."},"columns":{"items":{"$ref":"#/components/schemas/BoundColumn"},"type":"array","title":"Columns","description":"Every column pinned to a slot, in slot order."},"periods":{"items":{"$ref":"#/components/schemas/BoundPeriod"},"type":"array","title":"Periods","description":"The period domain, in period order, with roles."},"value_sets":{"items":{"$ref":"#/components/schemas/BoundValueSet"},"type":"array","title":"Value Sets","description":"Encoding candidates and layer memberships. More than one entry under 'encodings.manual' means the run kept both readings and resolved them per test."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"Deviations the run observed while orienting."},"revised_because":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revised Because","description":"Why the binding was replaced mid-run, when it was. Null on a run that bound once."}},"additionalProperties":false,"type":"object","title":"LedgerBindingWire","description":"The definitional layer a run committed, echoed for the caller to read.\n\nThis is the answer to \"on what definitions does this figure rest\" — the\nquestion the prose relay of the old playbook could not answer, and the reason\nthe binding is a validated artifact rather than a paragraph. Every pin was\nchecked against the tables' own profiles before the run was allowed to\ncompute anything: the columns exist with compatible types, the period roles\npartition the observed domain, each clock's declared grain matches its\ncolumn, and every encoding value occurs in its column.\n\nPublished as flat slot listings rather than as a mirror of the internal\nmodel's tree. Two reasons, both practical: a reader wants \"which column is\nthe approval clock\" answered in one place rather than by walking a nested\nobject, and a slot the design adds later becomes another row here instead of\na change to this contract."},"LedgerPackageProposals":{"properties":{"auto_confirmation":{"anyOf":[{"$ref":"#/components/schemas/AutoConfirmation"},{"type":"null"}],"description":"Automatic confirmation outcome and review reason."},"tie_break":{"anyOf":[{"$ref":"#/components/schemas/PackageTieBreak"},{"type":"null"}],"description":"Model choice between competing high-confidence packages; absent when no tie was offered."},"candidates":{"items":{"$ref":"#/components/schemas/PackageCandidate"},"type":"array","maxItems":3,"title":"Candidates","description":"Validated nominations in model rank order."},"model_slug":{"type":"string","title":"Model Slug","description":"Model used to nominate packages."},"catalog_revision":{"type":"string","title":"Catalog Revision","description":"Accessible catalog revision used for nomination."},"triaged_out":{"items":{"type":"string"},"type":"array","title":"Triaged Out","description":"Bounded sample of omitted source handles and short reasons."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Discovery limitations, including heuristic fallback after empty triage."},"heuristic_fallback":{"type":"boolean","title":"Heuristic Fallback","description":"Whether composition ran over rank-ordered catalog sources because triage nominated none.","default":false},"triaged_out_count":{"type":"integer","title":"Triaged Out Count","description":"Total sources omitted from composition, including those beyond the displayed sample.","default":0},"rejected":{"items":{"$ref":"#/components/schemas/RejectedCandidate"},"type":"array","title":"Rejected","description":"Nominations refused by catalog validation."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Elapsed discovery time in milliseconds.","default":0},"input_tokens":{"type":"integer","title":"Input Tokens","description":"Total input tokens across model calls and retries.","default":0},"output_tokens":{"type":"integer","title":"Output Tokens","description":"Total output tokens across model calls and retries.","default":0}},"additionalProperties":false,"type":"object","required":["model_slug","catalog_revision"],"title":"LedgerPackageProposals"},"LedgerPackageScope":{"properties":{"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Folder containing the package, relative to the workspace root."},"paths":{"items":{"type":"string"},"type":"array","title":"Paths","description":"Exact source paths in the package, added to every path under the prefix."},"selection_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Selection Id","description":"Protected, immutable source-role selection reference."}},"additionalProperties":false,"type":"object","title":"LedgerPackageScope","description":"A package's source files: every file under the prefix plus every explicit path."},"LedgerParseExhibitsResult":{"properties":{"result_type":{"type":"string","const":"ledger_parse_exhibits","title":"Result Type","default":"ledger_parse_exhibits"},"parse_run_id":{"type":"string","title":"Parse Run Id","description":"The parse run whose journals the published examples rank and locate."},"journals_total":{"type":"integer","minimum":0.0,"title":"Journals Total","description":"Journals the published examples cover, equal to the parse's own count."}},"additionalProperties":false,"type":"object","required":["parse_run_id","journals_total"],"title":"LedgerParseExhibitsResult","description":"Which parse run's GL parse examples are published, read from the manifest that commits them.\n\nThe examples themselves stay behind the explorer routes; this names what a\nsucceeded job made readable, so success always has something to point at."},"LedgerUnderstandingConfig":{"properties":{"engine":{"type":"string","enum":["measured","llm"],"title":"Engine","description":"Discovery method; selected packages always run measured validation.","default":"measured"},"package_confirmation":{"type":"string","enum":["required","automatic"],"title":"Package Confirmation","description":"Who confirms an llm-discovered package before GL parsing: a person, or the model on its own. When a person must, parsing runs only on the mapping that person confirmed.","default":"required"},"package_scope":{"$ref":"#/components/schemas/LedgerPackageScope","description":"Default package selection for understanding, including ingestion-triggered runs."},"trigger":{"type":"string","enum":["auto","always","off"],"title":"Trigger","description":"When an ingestion should chain the stage: only for a workspace that holds a journal-line table, after every ingestion that landed files, or never.","default":"auto"},"gl_parsing":{"type":"boolean","title":"Gl Parsing","description":"Whether the stage should also map each journal's account/debit-credit groups to balanced sub-journals and publish the mapping as a derived table.","default":true},"prepared_relationships":{"items":{"$ref":"#/components/schemas/PreparedRelationshipConfig"},"type":"array","maxItems":4,"title":"Prepared Relationships","description":"Reviewed large-table relationships to prepare before JET starts. Empty disables preparation."}},"additionalProperties":false,"type":"object","title":"LedgerUnderstandingConfig","description":"A workspace's ledger-understanding policy.\n\nOn by default in its cheapest form: ``auto`` costs a workspace with no ledger\nin it nothing at all, because the test for \"is there a ledger here\" is the\ncensus's own pure predicate over sidecars that ingestion already wrote."},"LedgerUnderstandingReport":{"properties":{"artifact_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Artifact Version","description":"Compatibility version that produced this report; absent on legacy job results."},"current_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Current Version","description":"Compatibility version of the server that returned this response."},"rerun_required":{"type":"boolean","title":"Rerun Required","description":"Whether a new understanding run is needed to obtain a current report.","default":false},"auto_decisions":{"items":{"$ref":"#/components/schemas/AutoDecisionWire"},"type":"array","title":"Auto Decisions","description":"Automatic choices, suggestions and refusals from this reading."},"engine":{"type":"string","enum":["measured","llm"],"title":"Engine","description":"Configured discovery engine for this reading.","default":"measured"},"proposals":{"anyOf":[{"$ref":"#/components/schemas/LedgerPackageProposals"},{"type":"null"}],"description":"Sidecar-only nominations awaiting human source selection and measurement."},"reading_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reading Id","description":"Immutable reading identity to echo when answering source-selection HITL; absent on legacy reports."},"scope":{"$ref":"#/components/schemas/LedgerPackageScope","description":"Source selection this report describes; independent packages have independent readings."},"assessment":{"$ref":"#/components/schemas/LedgerAssessmentWire","description":"Readiness and execution coverage; legacy readings are unknown."},"package_fingerprint":{"type":"string","title":"Package Fingerprint","description":"Identifies the exact selected files this reading measured. It moves whenever one of those files is re-ingested, made visible, or replaced."},"produced_at":{"type":"string","format":"date-time","title":"Produced At","description":"When the stage finished measuring this package."},"stale":{"type":"boolean","title":"Stale","description":"Whether the workspace has moved since this reading was measured. A stale report is still returned, because an old measurement a reader can date beats no answer at all."},"stale_reason":{"anyOf":[{"type":"string","enum":["package","version","decisions"]},{"type":"null"}],"title":"Stale Reason","description":"Why it is stale, when it is: 'package' means files were ingested, replaced or made visible since; 'decisions' means somebody has answered a review this reading did not fold. They are different actions — the first is re-measured by a plain run, the second by applying the decisions. 'version' means this build's measurement rules changed. Precedence is package, version, then decisions; the version fields and pending decision count retain the other reasons when several apply."},"pending_decisions":{"type":"integer","title":"Pending Decisions","description":"Decisions stored for this workspace that this reading did not fold. Zero on a reading that is current with every answer given.","default":0},"applied_decisions":{"items":{"$ref":"#/components/schemas/AppliedDecisionWire"},"type":"array","title":"Applied Decisions","description":"What this reading did with each decision it folded, including the ones it could not apply."},"blocking":{"type":"boolean","title":"Blocking","description":"Mirrors the integrity report's structural verdict, so a caller can branch on one field."},"tables":{"items":{"$ref":"#/components/schemas/TableCardWire"},"type":"array","title":"Tables","description":"Every queryable table in the package, with its grain figures."},"conventions":{"$ref":"#/components/schemas/ConventionsWire","description":"The settled reading of what the package's numbers mean."},"integrity":{"$ref":"#/components/schemas/IntegrityReportWire","description":"The integrity battery's findings and the checks it could not run."},"join_graph":{"items":{"$ref":"#/components/schemas/JoinEdgeWire"},"type":"array","title":"Join Graph","description":"The expected joins between the package's tables, with their ratios."},"open_questions":{"items":{"$ref":"#/components/schemas/OpenQuestionWire"},"type":"array","title":"Open Questions","description":"What the data could not settle and a reader must decide."},"parsing":{"anyOf":[{"$ref":"#/components/schemas/ParseSummaryWire"},{"type":"null"}],"description":"The general-ledger parsing summary, or null when the workspace has the pass switched off or the package left a precondition open."},"preparations":{"items":{"$ref":"#/components/schemas/PreparationSummaryWire"},"type":"array","title":"Preparations","description":"Reusable relationship preparations requested for this package; empty when none were configured."},"settled_structure":{"anyOf":[{"$ref":"#/components/schemas/StructureProposal"},{"type":"null"}],"description":"The journal key, account, amount and optional columns this reading settled, spelled as a structure proposal so it can pre-fill a mapping edit. Null on a discovery reading or when no complete mapping settled."}},"additionalProperties":false,"type":"object","required":["package_fingerprint","produced_at","stale","blocking","tables","conventions","integrity","join_graph","open_questions"],"title":"LedgerUnderstandingReport"},"LedgerUnderstandingResetResult":{"properties":{"result_type":{"type":"string","const":"ledger_understanding_reset","title":"Result Type","default":"ledger_understanding_reset"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id","description":"The workspace whose ledger reading was removed."},"objects_deleted":{"type":"integer","title":"Objects Deleted","description":"Stored objects removed across the stage's own prefix and the je-testing prep prefix.","default":0},"decisions_deleted":{"type":"integer","title":"Decisions Deleted","description":"Stored review answers cleared across every package; the rows stay, emptied.","default":0},"jobs_cancelled":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Jobs Cancelled","description":"Runs stopped because they were reading what this reset removed."},"verified":{"type":"boolean","title":"Verified","description":"False is a failed reset and must alert.","default":false}},"additionalProperties":false,"type":"object","required":["workspace_id"],"title":"LedgerUnderstandingResetResult","description":"What one ledger-understanding reset removed.\n\nCounted rather than merely reported done, for ``DeleteFileResult``'s reason: a\ncaller who asked for a reset can see it happened. ``verified`` comes from an\nindependent re-read of the prefix, and a false one is an alertable fact on a\njob that still succeeded — failing the job would hide these counts."},"LedgerUnderstandingResult":{"properties":{"result_type":{"type":"string","const":"ledger_understanding","title":"Result Type","default":"ledger_understanding"},"follow_up_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Follow Up Job Id","description":"Selected-package measurement job chained by discovery."},"report":{"$ref":"#/components/schemas/LedgerUnderstandingReport","description":"The package's tables, conventions, integrity findings and open questions."}},"additionalProperties":false,"type":"object","required":["report"],"title":"LedgerUnderstandingResult","description":"One package's settled reading, as the understanding job publishes it.\n\nThe result IS the report: the route's ``GET`` and ``GET /v1/jobs/{id}``\nanswer with the same object, so a caller that polled the job never has to\ncall a second endpoint to learn what the run concluded."},"LoadProbeResponse":{"properties":{"client":{"type":"string","title":"Client"},"window_seconds":{"type":"integer","title":"Window Seconds"},"sampled_at":{"type":"string","format":"date-time","title":"Sampled At"},"in_flight":{"$ref":"#/components/schemas/StatusCounts","description":"Counts across all rows (any age)."},"in_window":{"$ref":"#/components/schemas/StatusCounts","description":"Counts for rows created within ``window_seconds``."},"in_window_by_action":{"$ref":"#/components/schemas/ActionCounts","description":"Per-action breakdown for rows created within ``window_seconds``."}},"additionalProperties":false,"type":"object","required":["client","window_seconds","sampled_at","in_flight","in_window","in_window_by_action"],"title":"LoadProbeResponse","description":"Server-side snapshot of ``api_requests`` for the calling client.\n\nBoth ``window_seconds`` and the total counts are returned so callers\ncan compute throughput (window counts) and saturation (in-flight =\n``pending`` + ``running``) without having to do their own arithmetic."},"LocatePiece":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path","description":"The file's uploaded source path."},"number":{"type":"integer","minimum":1.0,"title":"Number","description":"The piece's `number`: a page, or a text file's window."},"component":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Component","description":"The piece's `component` (a tab or section); null when it had none."}},"additionalProperties":false,"type":"object","required":["path","number"],"title":"LocatePiece","description":"A piece a previous locate offered, as its `pages[]` entry named it."},"LocateRead":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path","description":"The file's uploaded source path."},"pages":{"anyOf":[{"items":{"type":"integer","minimum":1.0},"type":"array","maxItems":1000,"minItems":1},{"type":"null"}],"title":"Pages","description":"The page numbers that were read."},"line_start":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Line Start","description":"First line read; null from line 1."},"line_end":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Line End","description":"Last line read; null to the end."},"component":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Component","description":"The tab or section read; null for the file's own text, or every tab of a whole read."}},"additionalProperties":false,"type":"object","required":["path"],"title":"LocateRead","description":"A read already done: pages of a paged file, a line span of a text file, or the whole file (neither given)."},"LocateRequest":{"properties":{"need":{"type":"string","maxLength":400,"minLength":1,"title":"Need","description":"What is still needed, in a few words: a year, an entity, a line item, a definition."},"question":{"anyOf":[{"type":"string","maxLength":4096,"minLength":1},{"type":"null"}],"title":"Question","description":"The whole question the need is part of; every decision weighs the need within it. Omit it and the need is the whole question."},"k":{"type":"integer","maximum":24.0,"minimum":1.0,"title":"K","description":"How many pieces to name.","default":12},"every":{"type":"boolean","title":"Every","description":"The need names a kind of file and every one is wanted (each invoice, every statement): the navigator rates each file of that kind and lists the members in `population`.","default":false},"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Only files under this folder, workspace-relative; `paths` adds files. Omit both for the whole workspace."},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Only these uploaded files (with `path_prefix`, its folder's files too). Unknown or inaccessible paths are refused."},"exclude":{"items":{"$ref":"#/components/schemas/LocatePiece"},"type":"array","maxItems":1000,"title":"Exclude","description":"Pieces earlier locates offered, left out of this answer."},"already_read":{"items":{"$ref":"#/components/schemas/LocateRead"},"type":"array","maxItems":1000,"title":"Already Read","description":"Reads already done: their pieces are left out, and the navigator is told they did not settle the need."},"pointer":{"type":"boolean","title":"Pointer","description":"Name every page in `text` by its opening lines only. Without it, the best pages come in full, as a task's first locate wants them; later locates pass it, so page text does not pile up in an agent's context.","default":false}},"additionalProperties":false,"type":"object","required":["need"],"title":"LocateRequest","description":"Request for ``locate``: where in the workspace a piece of information is.\n\nThe navigator NDI's own agent calls as ``ndi-locate``, over the files the caller may see. It is stateless: what a\ncaller was already offered (``exclude``) and has read (``already_read``) is left out of the answer only when sent\nback, as a run's memory does it for NDI's agent. A call that leaves out nothing is the caller's opening and rates\nmore files. ``text`` gives the best pages in full unless ``pointer`` asks for previews only."},"LocateResponse":{"properties":{"text":{"type":"string","title":"Text","description":"The reply as NDI's own agent reads it: each piece with the command that reads it and its text (the best pages in full, the rest by their opening lines; every page by its opening lines with `pointer`), then a population's members and the tables to query."},"pages":{"items":{"$ref":"#/components/schemas/LocatedPiece"},"type":"array","title":"Pages","description":"The pieces named, best first."},"tables":{"items":{"$ref":"#/components/schemas/LocatedTableRef"},"type":"array","title":"Tables","description":"The tables rated for the need, best first."},"population":{"items":{"$ref":"#/components/schemas/LocatedMember"},"type":"array","title":"Population","description":"Set when answering needs every file of a kind (each invoice, every contract): the members, best first."},"population_unrated":{"type":"integer","title":"Population Unrated","description":"Files in folders rated likely to hold members that the budget ran out before rating: when above 0, `population` is incomplete; narrow the need to a folder, kind or period and locate again with `every`.","default":0},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job."}},"additionalProperties":false,"type":"object","required":["text","pages","tables","population"],"title":"LocateResponse","description":"Response of ``locate``: the reply NDI's agent reads, and the same findings as fields."},"LocateResult":{"properties":{"result_type":{"type":"string","const":"locate","title":"Result Type","default":"locate"},"output":{"$ref":"#/components/schemas/LocateResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"LocateResult"},"LocatedMember":{"properties":{"path":{"type":"string","title":"Path","description":"The file's uploaded source path."},"score":{"type":"number","title":"Score","description":"How likely the file is a member, 0 to 1."}},"additionalProperties":false,"type":"object","required":["path","score"],"title":"LocatedMember","description":"A file rated a member when the question needs every file of a kind."},"LocatedPiece":{"properties":{"path":{"type":"string","title":"Path","description":"Uploaded source path of the file."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"The tab or section a read of the piece names; null when the file's text is one."},"paged":{"type":"boolean","title":"Paged","description":"True for a page (read it by `number`); false for a window of lines."},"number":{"type":"integer","title":"Number","description":"The page number, or the window's number in a text file."},"line_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line Start","description":"A window's first line, as read-file numbers lines."},"line_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line End","description":"A window's last line, inclusive."},"score":{"type":"number","title":"Score","description":"How likely the piece holds what is needed, 0 to 1."},"head":{"type":"string","title":"Head","description":"The piece's opening text, cut where the reply text cuts it."}},"additionalProperties":false,"type":"object","required":["path","paged","number","score","head"],"title":"LocatedPiece","description":"A piece the navigator named: a page of a paged document, or a line window of a text file."},"LocatedTableRef":{"properties":{"sql_table":{"type":"string","title":"Sql Table","description":"The table's name in SQL queries."},"path":{"type":"string","title":"Path","description":"Uploaded source path of the file holding it."},"tab":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tab","description":"The workbook tab, when it is one."},"score":{"type":"number","title":"Score","description":"How likely its rows answer the need, 0 to 1."},"columns":{"items":{"type":"string"},"type":"array","title":"Columns","description":"Every column of the table, in order."},"relevant_columns":{"items":{"type":"string"},"type":"array","title":"Relevant Columns","description":"The columns a query for the need reads, when rated."}},"additionalProperties":false,"type":"object","required":["sql_table","path","score","columns","relevant_columns"],"title":"LocatedTableRef","description":"A queryable table the navigator rated for the need."},"ManagedWorkspaceStorage":{"properties":{"type":{"type":"string","const":"managed","title":"Type","default":"managed"}},"additionalProperties":false,"type":"object","title":"ManagedWorkspaceStorage"},"MappingChange":{"properties":{"role":{"type":"string","enum":["journal_key","account","amount","effective_date","period","line_ordinal"],"title":"Role","description":"Structural role whose column changed after the reviewer confirmed it."},"confirmed":{"items":{"type":"string"},"type":"array","title":"Confirmed","description":"Columns the reviewer confirmed for this role, in order; debit before credit."},"settled":{"items":{"type":"string"},"type":"array","title":"Settled","description":"Columns the run settled for this role, in order; empty when it settled none."}},"additionalProperties":false,"type":"object","required":["role","confirmed","settled"],"title":"MappingChange"},"MappingConfirmationRequired":{"properties":{"reason":{"type":"string","enum":["model_confirmed_package","mapping_changed"],"title":"Reason","description":"Why parsing waits: a model rather than a person confirmed the package, or the run settled columns other than the ones a person confirmed."},"changes":{"items":{"$ref":"#/components/schemas/MappingChange"},"type":"array","title":"Changes","description":"Each confirmed role the run settled differently; empty for a model-confirmed package."},"proposed":{"anyOf":[{"$ref":"#/components/schemas/StructureProposal"},{"type":"null"}],"description":"The mapping the run settled, offered for confirmation; null when it settled no complete one."}},"additionalProperties":false,"type":"object","required":["reason"],"title":"MappingConfirmationRequired"},"MarkRunViewedRequest":{"properties":{"viewed":{"type":"boolean","title":"Viewed","description":"Set true once the signed-in user has seen the run's result."}},"type":"object","required":["viewed"],"title":"MarkRunViewedRequest"},"MediaComponentInfo":{"properties":{"kind":{"type":"string","const":"media","title":"Kind","default":"media"},"modality":{"type":"string","enum":["audio","video"],"title":"Modality","description":"Whether the recording is `audio` or `video`."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Length of the recording in milliseconds."},"speaker_count":{"type":"integer","title":"Speaker Count","description":"Distinct speakers detected in the recording."},"summary":{"type":"string","title":"Summary","description":"What the recording covers, as summarized at ingestion.","default":""}},"additionalProperties":false,"type":"object","required":["modality","duration_ms","speaker_count"],"title":"MediaComponentInfo","description":"A recording: timeline facts, no paths — ask about it with qa-file."},"MediaFrameRef":{"properties":{"timestamp_ms":{"type":"integer","title":"Timestamp Ms","description":"Frame timestamp in integer milliseconds from the start of the recording."},"path":{"type":"string","title":"Path","description":"Path of this frame inside the media artifact, relative to the timeline."}},"additionalProperties":false,"type":"object","required":["timestamp_ms","path"],"title":"MediaFrameRef","description":"One sampled video frame referenced from a timeline segment."},"MediaSilenceSegment":{"properties":{"kind":{"type":"string","const":"silence","title":"Kind","default":"silence"},"start_ms":{"type":"integer","title":"Start Ms","description":"Inclusive start of this silence stretch, in integer milliseconds."},"end_ms":{"type":"integer","title":"End Ms","description":"Exclusive end of this silence stretch, in integer milliseconds."},"speaker":{"type":"null","title":"Speaker","description":"Always null on a silence segment so every segment shares a speaker slot."},"transcript":{"type":"string","const":"","title":"Transcript","description":"Always empty on a silence segment so every segment shares a transcript slot.","default":""},"frames":{"items":{"$ref":"#/components/schemas/MediaFrameRef"},"type":"array","title":"Frames","description":"Sampled video frames that fall inside this silent stretch. Empty for audio and when none were sampled."}},"additionalProperties":false,"type":"object","required":["start_ms","end_ms"],"title":"MediaSilenceSegment","description":"A stretch with no transcribed speech, kept so the timeline has no holes."},"MediaSpeaker":{"properties":{"id":{"type":"string","title":"Id","description":"Diarizer cluster id for this speaker, for example SPEAKER_00."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Mapped display name when a caller assigned one. Null when only the cluster id is known."}},"additionalProperties":false,"type":"object","required":["id"],"title":"MediaSpeaker","description":"A diarizer speaker cluster on a parse transcript."},"MediaSpeechSegment":{"properties":{"kind":{"type":"string","const":"speech","title":"Kind","default":"speech"},"start_ms":{"type":"integer","title":"Start Ms","description":"Inclusive start of this speech stretch, in integer milliseconds."},"end_ms":{"type":"integer","title":"End Ms","description":"Exclusive end of this speech stretch, in integer milliseconds."},"speaker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker","description":"Diarizer cluster id that spoke this stretch. Null only when diarization produced no turns."},"transcript":{"type":"string","title":"Transcript","description":"Recognized speech text for this stretch. The field name is transcript, not text."},"frames":{"items":{"$ref":"#/components/schemas/MediaFrameRef"},"type":"array","title":"Frames","description":"Sampled video frames that fall inside this stretch. Empty for audio and when none were sampled."}},"additionalProperties":false,"type":"object","required":["start_ms","end_ms","speaker","transcript"],"title":"MediaSpeechSegment","description":"A stretch of one speaker talking on the parse transcript."},"MediaTimeline":{"properties":{"schema_version":{"type":"integer","title":"Schema Version","description":"Timeline schema version. Current parses emit version 2."},"modality":{"type":"string","enum":["audio","video"],"title":"Modality","description":"Whether the source was an audio file or a video file."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Probed duration of the recording in integer milliseconds."},"speakers":{"items":{"$ref":"#/components/schemas/MediaSpeaker"},"type":"array","title":"Speakers","description":"Diarizer clusters discovered in the recording. Labels stay null unless a caller mapped them."},"segments":{"items":{"oneOf":[{"$ref":"#/components/schemas/MediaSpeechSegment"},{"$ref":"#/components/schemas/MediaSilenceSegment"}],"discriminator":{"propertyName":"kind","mapping":{"silence":"#/components/schemas/MediaSilenceSegment","speech":"#/components/schemas/MediaSpeechSegment"}}},"type":"array","title":"Segments","description":"Ordered gapless run of speech and silence covering the whole recording."},"peaks":{"items":{"type":"number"},"type":"array","title":"Peaks","description":"Windowed RMS envelope over the full recording, 0..1 inclusive. Empty means measurement unavailable."}},"additionalProperties":false,"type":"object","required":["schema_version","modality","duration_ms"],"title":"MediaTimeline","description":"Seekable MediaTimeline JSON carried inline on an audio or video parse."},"MemberInfo":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"role":{"type":"string","enum":["owner","admin","member"],"title":"Role"},"disabled":{"type":"boolean","title":"Disabled","description":"A disabled member cannot sign in; the organization's keys are unaffected."},"joined_at":{"type":"string","format":"date-time","title":"Joined At"}},"type":"object","required":["user_id","role","disabled","joined_at"],"title":"MemberInfo","description":"One human in the organization."},"MemberListResponse":{"properties":{"members":{"items":{"$ref":"#/components/schemas/MemberInfo"},"type":"array","title":"Members"}},"type":"object","required":["members"],"title":"MemberListResponse"},"ModelTokenUsage":{"properties":{"model":{"type":"string","title":"Model","description":"Model identifier as the provider reported it, or as the caller asked for it."},"requests":{"type":"integer","title":"Requests","description":"Observed provider attempts, including explicitly recorded failures.","default":0},"input_tokens":{"type":"integer","title":"Input Tokens","description":"Prompt tokens sent to this model, cached ones included.","default":0},"output_tokens":{"type":"integer","title":"Output Tokens","description":"Completion tokens this model generated.","default":0},"cached_input_tokens":{"type":"integer","title":"Cached Input Tokens","description":"The share of input_tokens served from the provider's prompt cache — billed at a reduced rate, so pricing needs it separated out rather than subtracted.","default":0}},"type":"object","required":["model"],"title":"ModelTokenUsage","description":"One model's share of a run's LLM spend.\n\nPer model rather than per run alone because a single run legitimately spends\non several: a search agent's own turns, the vision engine that cracked a\nscan, the sub-model an RLM read used. They are priced differently, so a\ntotal without this breakdown cannot be turned into money."},"MoneyCell":{"properties":{"kind":{"type":"string","const":"money","title":"Kind","default":"money"},"amount":{"type":"string","title":"Amount","description":"Decimal-as-string, 2 decimal places."},"currency":{"type":"string","title":"Currency","description":"ISO 4217 code as stated by the source."},"currency_source":{"type":"string","enum":["stated","assumed"],"title":"Currency Source","description":"How the currency was arrived at: 'stated' when the source named it, 'assumed' when the workspace's default currency disambiguated a symbol the source left open (e.g. a bare '$'). Never a conversion — the amount is always the figure the document showed.","default":"stated"}},"additionalProperties":false,"type":"object","required":["amount","currency"],"title":"MoneyCell","description":"An amount with its original ISO currency — never converted or normalized (D9).\n\nMixed-currency comparison and aggregation are unsupported in this version:\nresults assume the compared records share a currency and always show it."},"NativeFileMetadata":{"properties":{"source_modified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Source Modified At","description":"Filesystem modification time reported by the uploading client; informational, not audit evidence."},"properties":{"items":{"$ref":"#/components/schemas/NativeMetadataProperty"},"type":"array","title":"Properties","description":"Format-native properties discovered inside the uploaded file."}},"additionalProperties":false,"type":"object","title":"NativeFileMetadata"},"NativeMetadataProperty":{"properties":{"key":{"type":"string","title":"Key","description":"Format-qualified property name, such as pdf.creator or image.exif.Model."},"value":{"type":"string","title":"Value","description":"Property value preserved as text from the source container."}},"additionalProperties":false,"type":"object","required":["key","value"],"title":"NativeMetadataProperty"},"NoulAnswer":{"properties":{"type":{"type":"string","const":"noul","title":"Type","default":"noul"},"noul":{"type":"number","title":"Noul","description":"Probability, from 0 to 1, that the statement is true."}},"additionalProperties":false,"type":"object","required":["noul"],"title":"NoulAnswer"},"NoulCriteria":{"properties":{"true":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"True","description":"What makes the statement true, in the caller's words."},"false":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"False","description":"What makes the statement false, in the caller's words."}},"additionalProperties":false,"type":"object","title":"NoulCriteria"},"NoulQuestion":{"properties":{"type":{"type":"string","const":"noul","title":"Type"},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instructions","description":"The question to decide. Needs instructions or at least one criterion."},"criteria":{"anyOf":[{"$ref":"#/components/schemas/NoulCriteria"},{"type":"null"}],"description":"Optional descriptions of the true and false outcomes."}},"additionalProperties":false,"type":"object","required":["type"],"title":"NoulQuestion","description":"A yes/no question. Its answer is the probability that the statement is true."},"NumberCell":{"properties":{"kind":{"type":"string","const":"number","title":"Kind","default":"number"},"number":{"type":"string","title":"Number","description":"Decimal-as-string."}},"additionalProperties":false,"type":"object","required":["number"],"title":"NumberCell"},"OcrBoundingBox":{"properties":{"left":{"type":"number","title":"Left","description":"Normalized left edge of the box, 0-1 from the page left."},"top":{"type":"number","title":"Top","description":"Normalized top edge of the box, 0-1 from the page top."},"width":{"type":"number","title":"Width","description":"Normalized width of the box, 0-1 of the page width."},"height":{"type":"number","title":"Height","description":"Normalized height of the box, 0-1 of the page height."},"page":{"type":"integer","title":"Page","description":"1-based page this box was measured on after any conversion."},"original_page":{"type":"integer","title":"Original Page","description":"1-based page in the original file, before conversion."}},"additionalProperties":false,"type":"object","required":["left","top","width","height","page","original_page"],"title":"OcrBoundingBox","description":"Normalized top-left OCR geometry for one page."},"OcrElement":{"properties":{"text":{"type":"string","title":"Text","description":"Recognized text of this word or line."},"bbox":{"$ref":"#/components/schemas/OcrBoundingBox","description":"Normalized page geometry for this word or line."},"confidence":{"type":"number","title":"Confidence","description":"OCR engine confidence for this element, 0-1."},"chunk_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Chunk Index","description":"Index into document.chunks when this element was assigned to a chunk."},"rotation":{"type":"integer","title":"Rotation","description":"Clockwise rotation of the element in degrees.","default":0}},"additionalProperties":false,"type":"object","required":["text","bbox","confidence"],"title":"OcrElement","description":"One inline OCR word or line."},"OfficialComparator":{"properties":{"provider":{"type":"string","title":"Provider"},"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score"}},"type":"object","required":["provider","score"],"title":"OfficialComparator","description":"Comparison used for the team's official SOTA decision."},"OpenQuestionWire":{"properties":{"id":{"type":"string","title":"Id","description":"A stable id within this report, assigned after a deterministic sort."},"slot":{"type":"string","title":"Slot","description":"The binding slot or convention this question is about."},"question":{"type":"string","title":"Question","description":"The question, phrased so it can be answered from the package itself."},"candidates":{"items":{"type":"string"},"type":"array","title":"Candidates","description":"The alternatives the data leaves open, where it narrows them at all."},"evidence":{"items":{"type":"string"},"type":"array","title":"Evidence","description":"What the census measured about the choice, one line per measurement."},"exclusive_group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exclusive Group","description":"Questions sharing this group take distinct columns; null when the question stands alone."}},"additionalProperties":false,"type":"object","required":["id","slot","question","candidates","evidence"],"title":"OpenQuestionWire","description":"One thing the data could not settle, asked exactly once."},"OrganizationAccessLabelInfo":{"properties":{"access_label_id":{"type":"string","format":"uuid","title":"Access Label Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"}},"type":"object","required":["access_label_id","name","description"],"title":"OrganizationAccessLabelInfo","description":"One catalog label — enough for the grants UI checkboxes."},"OrganizationAccessLabelListResponse":{"properties":{"labels":{"items":{"$ref":"#/components/schemas/OrganizationAccessLabelInfo"},"type":"array","title":"Labels"}},"type":"object","required":["labels"],"title":"OrganizationAccessLabelListResponse"},"OrganizationInfo":{"properties":{"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"name":{"type":"string","title":"Name","description":"Storage-safe slug, derived server-side. Stable; not shown to users."},"display_name":{"type":"string","title":"Display Name","description":"The name a human gave the organization."},"role":{"type":"string","enum":["owner","admin","member"],"title":"Role","description":"The signed-in user's role here. It may differ per organization."},"rate_limit_rpm":{"type":"integer","title":"Rate Limit Rpm"},"included_credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Included Credits","description":"Lifetime credit allowance; null means unlimited."},"joined_at":{"type":"string","format":"date-time","title":"Joined At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"default_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Default Workspace Id","description":"The signed-in user's Perception Playground in this organization — where the console's perception tools upload by default. Null when it has not been provisioned yet, which the console handles by falling back to workspace-free uploads."}},"type":"object","required":["organization_id","name","display_name","role","rate_limit_rpm","joined_at","created_at"],"title":"OrganizationInfo","description":"One organization the signed-in user belongs to, with their role in it."},"OrganizationKeyInfo":{"properties":{"key_prefix":{"type":"string","title":"Key Prefix","description":"Display handle, and the id used to revoke or grant."},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What the key is for, as its creator described it. Null when they said nothing."},"created_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By User Id","description":"Who minted it. Attribution only — the key belongs to the organization."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When it stops authenticating. Null means it never expires."},"status":{"type":"string","enum":["active","expiring_soon","expired","disabled"],"title":"Status","description":"'expiring_soon' inside the warning window before expires_at; 'expired' after it; 'disabled' when an admin has suspended it, which outranks both. An expired or disabled key stays listed so it can be seen and replaced, but it no longer authenticates."},"disabled":{"type":"boolean","title":"Disabled","description":"Whether an admin has suspended the key. Unlike revocation this is reversible.","default":false},"system":{"type":"boolean","title":"System","description":"A key the platform manages — the signed-in member's own console session key. It is listed so the credential the console itself uses is visible, but it cannot be disabled or revoked through these endpoints.","default":false},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At","description":"Last authenticated use. May lag by up to the auth-cache TTL (~5 minutes): cache hits skip the timestamp bump."}},"type":"object","required":["key_prefix","name","created_at","status"],"title":"OrganizationKeyInfo","description":"Metadata for one API key — never the secret."},"OrganizationKeyListResponse":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/OrganizationKeyInfo"},"type":"array","title":"Keys"}},"type":"object","required":["keys"],"title":"OrganizationKeyListResponse"},"OrganizationListResponse":{"properties":{"current_user_id":{"type":"string","format":"uuid","title":"Current User Id","description":"Stable internal ID of the authenticated user, independent of their email or identity provider subject."},"organizations":{"items":{"$ref":"#/components/schemas/OrganizationInfo"},"type":"array","title":"Organizations"},"can_create_organization":{"type":"boolean","title":"Can Create Organization","description":"False when the free allowance is used up or this installation seeds its organizations with the CLI. Advisory for the UI — creation is refused server-side regardless."},"can_run_evals":{"type":"boolean","title":"Can Run Evals","description":"Whether this identity may use the eval console (a Nace staff email domain). A person-level capability like `can_create_organization`, not an organization's — an eval run scores the deployment and belongs to no tenant. Advisory for the UI; the eval routes enforce it regardless.","default":false}},"type":"object","required":["current_user_id","organizations","can_create_organization"],"title":"OrganizationListResponse","description":"Everywhere the signed-in user may work, plus what they may do themselves."},"OrganizationWorkspaceInfo":{"properties":{"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"name":{"type":"string","title":"Name"},"access_labels":{"items":{"type":"string"},"type":"array","title":"Access Labels","description":"Label names declared on this workspace."}},"type":"object","required":["workspace_id","name","access_labels"],"title":"OrganizationWorkspaceInfo","description":"A labelled workspace, for applying key grants without the /v1 plane."},"OrganizationWorkspaceListResponse":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/OrganizationWorkspaceInfo"},"type":"array","title":"Workspaces"}},"type":"object","required":["workspaces"],"title":"OrganizationWorkspaceListResponse"},"PackageCandidate":{"properties":{"primary_source_id":{"type":"string","title":"Primary Source Id","description":"Catalog handle of the proposed posting population."},"supporting_source_ids":{"items":{"type":"string"},"type":"array","title":"Supporting Source Ids","description":"Catalog handles of supporting references."},"trial_balance_source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trial Balance Source Id","description":"Supporting reference nominated as trial balance."},"user_master_source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Master Source Id","description":"Supporting reference nominated as user master."},"structure":{"anyOf":[{"$ref":"#/components/schemas/ProposedStructure"},{"type":"null"}],"description":"Column interpretation awaiting measurement; absent for native SAP contracts."},"confidence":{"type":"string","enum":["high","medium","low"],"title":"Confidence","description":"Model confidence, not measured readiness."},"rationale":{"items":{"type":"string"},"type":"array","maxItems":4,"title":"Rationale","description":"Short reasons for proposing this package."},"warnings":{"items":{"type":"string"},"type":"array","maxItems":8,"title":"Warnings","description":"Limitations to resolve during review."},"key_warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Warning","description":"Why the proposed journal key or line ordinal cannot identify every line, by the catalog's null counts, after the repair still named it. The selected run searches the measured population for another key."}},"additionalProperties":false,"type":"object","required":["primary_source_id","confidence"],"title":"PackageCandidate"},"PackageTieBreak":{"properties":{"choice":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Choice","description":"Primary handle the model chose among competing high-confidence packages; null when its answer named none of them."},"confidence":{"type":"string","enum":["high","medium","low"],"title":"Confidence","description":"Model confidence in the choice, not measured readiness."},"rationale":{"items":{"type":"string"},"type":"array","maxItems":4,"title":"Rationale","description":"Short reasons for the choice."}},"additionalProperties":false,"type":"object","required":["choice","confidence"],"title":"PackageTieBreak"},"PageRange":{"properties":{"start":{"type":"integer","minimum":1.0,"title":"Start","description":"First page of the range, 1-based and inclusive."},"end":{"type":"integer","minimum":1.0,"title":"End","description":"Last page of the range, 1-based and inclusive."}},"additionalProperties":false,"type":"object","required":["start","end"],"title":"PageRange","description":"One-based inclusive page range shared by document operations."},"PageRegion":{"properties":{"kind":{"type":"string","const":"page_region","title":"Kind","default":"page_region"},"page":{"type":"integer","minimum":1.0,"title":"Page","description":"1-based page number this region sits on."},"polygons":{"items":{"items":{"prefixItems":[{"type":"number"},{"type":"number"}],"type":"array","maxItems":2,"minItems":2},"type":"array","minItems":3},"type":"array","title":"Polygons","description":"One or more polygons in normalized 0-1 coordinates, used to draw overlays."}},"additionalProperties":false,"type":"object","required":["page"],"title":"PageRegion","description":"A region on a 1-based page. A bbox is a 4-point polygon."},"PageSelection":{"properties":{"ranges":{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200,"minItems":1,"title":"Ranges","description":"One-based inclusive page ranges to include. At least one range is required."}},"additionalProperties":false,"type":"object","required":["ranges"],"title":"PageSelection","description":"One or more one-based inclusive page ranges."},"Page_AccessLabelCatalogEntry_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AccessLabelCatalogEntry"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[AccessLabelCatalogEntry]"},"Page_DomainSummary_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DomainSummary"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[DomainSummary]"},"Page_ExtractionSchemaSummary_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ExtractionSchemaSummary"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[ExtractionSchemaSummary]"},"Page_ExtractionSchema_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ExtractionSchema"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[ExtractionSchema]"},"Page_FileVersion_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FileVersion"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[FileVersion]"},"Page_Job_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Job"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[Job]"},"Page_Tenant_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Tenant"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[Tenant]"},"Page_Workspace_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Workspace"},"type":"array","title":"Items","description":"This page's rows, in the list's order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque; null means the last page."},"total_count":{"type":"integer","title":"Total Count","description":"Exact, and filtered by the caller's access predicate."}},"additionalProperties":false,"type":"object","required":["items","total_count"],"title":"Page[Workspace]"},"PairedAmount":{"properties":{"kind":{"type":"string","const":"paired","title":"Kind","description":"Separate debit and credit columns."},"debit":{"type":"string","minLength":1,"title":"Debit","description":"Debit column on every primary member."},"credit":{"type":"string","minLength":1,"title":"Credit","description":"Credit column on every primary member."}},"additionalProperties":false,"type":"object","required":["kind","debit","credit"],"title":"PairedAmount"},"ParseCapProfileWire":{"properties":{"journals":{"type":"integer","title":"Journals","description":"Distinct journals stopped for this reason."},"groups_median":{"type":"number","title":"Groups Median","description":"Median account and direction group count per journal."},"groups_p95":{"type":"number","title":"Groups P95","description":"Group count at the ninety-fifth percentile."},"groups_max":{"type":"integer","title":"Groups Max","description":"Largest group count per journal."},"lines_median":{"type":"number","title":"Lines Median","description":"Median represented posting count per journal."},"lines_p95":{"type":"number","title":"Lines P95","description":"Posting count at the ninety-fifth percentile."},"lines_max":{"type":"integer","title":"Lines Max","description":"Largest represented posting count per journal."}},"additionalProperties":false,"type":"object","required":["journals","groups_median","groups_p95","groups_max","lines_median","lines_p95","lines_max"],"title":"ParseCapProfileWire","description":"Aggregate journal complexity for one stop reason; contains no business values."},"ParseChunk":{"properties":{"id":{"type":"string","title":"Id","description":"Stable id of this chunk within the parsed document."},"content":{"type":"string","title":"Content","description":"Chunk text sized for retrieval, not the full document rendering."},"location":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/PageRegion"},{"$ref":"#/components/schemas/SheetRange"},{"$ref":"#/components/schemas/TextSpan"},{"$ref":"#/components/schemas/RowRange"},{"$ref":"#/components/schemas/TableRegion"},{"$ref":"#/components/schemas/JsonPointer"}],"discriminator":{"propertyName":"kind","mapping":{"json_pointer":"#/components/schemas/JsonPointer","page_region":"#/components/schemas/PageRegion","row_range":"#/components/schemas/RowRange","sheet_range":"#/components/schemas/SheetRange","table_region":"#/components/schemas/TableRegion","text_span":"#/components/schemas/TextSpan"}}},{"type":"null"}],"title":"Location","description":"Where this chunk sits in the source. Null when chunking did not emit geometry."}},"additionalProperties":false,"type":"object","required":["id","content"],"title":"ParseChunk","description":"One RAG-oriented chunk produced when ``chunking.strategy`` is not ``none``."},"ParseChunkingOptions":{"properties":{"strategy":{"type":"string","enum":["none","page","section"],"title":"Strategy","description":"How result.document.chunks is built. none leaves the list empty; page and section produce RAG-sized pieces with locations.","default":"none"}},"additionalProperties":false,"type":"object","title":"ParseChunkingOptions"},"ParseDiagramsOptions":{"properties":{"mode":{"type":"string","enum":["omit","mermaid"],"title":"Mode","description":"Whether flowchart-like figures stay as images or are rewritten as Mermaid fences.","default":"omit"}},"additionalProperties":false,"type":"object","title":"ParseDiagramsOptions"},"ParseDocument":{"properties":{"page_count":{"type":"integer","title":"Page Count","description":"Number of pages (or equivalent sheets) in the parsed source."},"markdown":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Markdown","description":"Markdown rendering when requested in output.formats; null if that format was omitted."},"content_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Url","description":"Authenticated streaming URL for complete content when markdown contains only a bounded preview."},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text","description":"Plaintext rendering when requested in output.formats; headings and images stripped."},"blocks":{"anyOf":[{"items":{"$ref":"#/components/schemas/ParsedBlock"},"type":"array"},{"type":"null"}],"title":"Blocks","description":"Layout blocks with locations when requested in output.formats; null if omitted."},"has_signature":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Signature","description":"True when a signature was detected on any parsed page; the blocks of type signature say where. False only when every parsed page was checked and none was found. Absent or null when signature detection did not run on every parsed page."},"chunks":{"items":{"$ref":"#/components/schemas/ParseChunk"},"type":"array","title":"Chunks","description":"RAG chunks when chunking.strategy is not none; otherwise empty."},"ocr":{"anyOf":[{"$ref":"#/components/schemas/ParseOcrData"},{"type":"null"}],"description":"Word- and line-level OCR geometry when output.return_ocr_data is true."},"spreadsheet":{"anyOf":[{"$ref":"#/components/schemas/ParseSpreadsheet"},{"type":"null"}],"description":"Workbook sidecars such as per-sheet cell maps. Null for non-spreadsheet sources."}},"additionalProperties":false,"type":"object","required":["page_count"],"title":"ParseDocument","description":"The parsed document payload under ``ParseResult.document``."},"ParseEngine":{"type":"string","enum":["native_ocr","document_ocr","layout_ocr"],"title":"ParseEngine","description":"Stable public identity for the parse engine that produced a result."},"ParseFidelityDisclosure":{"properties":{"code":{"type":"string","const":"parse_fidelity","title":"Code"},"mode":{"type":"string","enum":["reduced_resolution","reduced_layout"],"title":"Mode","description":"Rendering or layout adjustment applied to fit the processing memory budget."},"pages":{"items":{"type":"integer","minimum":1.0},"type":"array","title":"Pages","description":"Exact 1-based source pages affected when physical pages are available; empty when the bounded format has no reliable physical-page map."}},"additionalProperties":false,"type":"object","required":["code","mode","pages"],"title":"ParseFidelityDisclosure","description":"An oversized parse used a bounded fidelity mode without dropping extracted text."},"ParseFiguresOptions":{"properties":{"mode":{"type":"string","enum":["omit","include","describe"],"title":"Mode","description":"Whether figure regions are dropped, kept as crops, or kept with a generated caption. Defaults to include. describe adds one vision caption call per figure.","default":"include"}},"additionalProperties":false,"type":"object","title":"ParseFiguresOptions"},"ParseJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"parse","title":"Kind","default":"parse"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__platform_api__results__ParseResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"ParseJob"},"ParseJobRequest":{"properties":{"file":{"$ref":"#/components/schemas/FileInput","description":"File to parse. Supported extensions: ``.avi``, ``.csv``, ``.doc``, ``.docm``, ``.docx``, ``.eml``, ``.flac``, ``.htm``, ``.html``, ``.jpeg``, ``.jpg``, ``.json``, ``.log``, ``.m4a``, ``.md``, ``.mdx``, ``.mkv``, ``.mov``, ``.mp3``, ``.mp4``, ``.mpga``, ``.msg``, ``.oft``, ``.oga``, ``.ogg``, ``.parquet``, ``.pdf``, ``.png``, ``.ppt``, ``.pptx``, ``.tif``, ``.tiff``, ``.txt``, ``.vsd``, ``.vsdx``, ``.wav``, ``.webp``, ``.xls``, ``.xlsm``, ``.xlsx``, ``.xml``."},"idempotency_key":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Idempotency Key","description":"Repeating a POST with the same key returns the original job instead of starting a new one."}},"additionalProperties":false,"type":"object","required":["file"],"title":"ParseJobRequest","description":"Body for ``POST /parse`` and ``POST /parse_async``."},"ParseOcrData":{"properties":{"words":{"items":{"$ref":"#/components/schemas/OcrElement"},"type":"array","title":"Words","description":"Word-level OCR elements when output.return_ocr_data is true."},"lines":{"items":{"$ref":"#/components/schemas/OcrElement"},"type":"array","title":"Lines","description":"Line-level OCR elements when output.return_ocr_data is true."}},"additionalProperties":false,"type":"object","title":"ParseOcrData","description":"Optional inline OCR geometry requested by the caller."},"ParseOcrOptions":{"properties":{"mode":{"type":"string","enum":["auto","force","disabled"],"title":"Mode","description":"When to run OCR. auto runs only if the file needs it; force always runs; disabled never runs. ocr_applied on the result says whether OCR actually ran.","default":"auto"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages","description":"Optional BCP-47 language hints for OCR. Empty lets the engine detect language."}},"additionalProperties":false,"type":"object","title":"ParseOcrOptions"},"ParseOutputOptions":{"properties":{"formats":{"items":{"type":"string","enum":["markdown","text","blocks"]},"type":"array","title":"Formats","description":"Which renderings to populate on result.document. Omitted formats are null. Default is markdown plus layout blocks; text is a stripped plaintext rendering."},"table_format":{"type":"string","enum":["html","markdown"],"title":"Table Format","description":"How tables are written inside markdown and text. Layout blocks keep their own table structure.","default":"html"},"include_images":{"type":"boolean","title":"Include Images","description":"When true, figure blocks include a crop URL for PDF and raster uploads. A figure that cannot be cropped keeps image_url null; the job still succeeds.","default":false},"return_ocr_data":{"type":"boolean","title":"Return Ocr Data","description":"When true, attach word- and line-level OCR geometry on result.document.ocr.","default":false},"include_page_markers":{"type":"boolean","title":"Include Page Markers","description":"Insert `--- Page N ---` headers between PDF pages in markdown and text. On by default. Page chunking and the canonical Parse dependency retain these headers internally when this is false, then strip them from the returned document.","default":true}},"additionalProperties":false,"type":"object","title":"ParseOutputOptions"},"ParsePreviewContent":{"properties":{"generation":{"type":"string","title":"Generation","description":"Provider invocation that produced this preview."},"index":{"type":"integer","title":"Index","description":"Original page number or selected sheet position."},"label":{"type":"string","title":"Label","description":"Page label or original sheet name."},"markdown":{"type":"string","title":"Markdown","description":"Checked preview text before document-wide finalization."},"truncated":{"type":"boolean","title":"Truncated","description":"This unit exceeded the preview budget; complete content is in the final result."},"ready_at":{"type":"string","format":"date-time","title":"Ready At","description":"Server time at which the unit became ready."}},"additionalProperties":false,"type":"object","required":["generation","index","label","markdown","truncated","ready_at"],"title":"ParsePreviewContent"},"ParsePreviewSnapshot":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Parse job being observed."},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Authoritative lifecycle state of the owning job."},"generation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generation","description":"Provider invocation whose preview is current."},"kind":{"anyOf":[{"type":"string","enum":["page","sheet","section","segment"]},{"type":"null"}],"title":"Kind","description":"Natural unit of this preview."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Number of requested units when known."},"units":{"items":{"$ref":"#/components/schemas/ParsePreviewUnit"},"type":"array","title":"Units","description":"Ready units in original document order."},"more":{"type":"boolean","title":"More","description":"The bounded preview omits further units; the final result remains complete.","default":false},"first_ready_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"First Ready At","description":"Server publication time of the first nonempty preview; null when not measured or unavailable."},"all_ready_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"All Ready At","description":"Server publication time when every requested preview was saved; document finalization can follow."}},"additionalProperties":false,"type":"object","required":["job_id","status"],"title":"ParsePreviewSnapshot"},"ParsePreviewUnit":{"properties":{"index":{"type":"integer","title":"Index","description":"Original page number or selected sheet position."},"revision":{"type":"string","title":"Revision","description":"Opaque immutable revision used to replace a prior preview."},"content_url":{"type":"string","title":"Content Url","description":"Authenticated URL for this bounded preview unit."}},"additionalProperties":false,"type":"object","required":["index","revision","content_url"],"title":"ParsePreviewUnit"},"ParseRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The document to read: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"parser":{"anyOf":[{"type":"string","enum":["native","datalab","nace_router"]},{"type":"null"}],"title":"Parser","description":"Deprecated parse implementation override. Prefer parse_mode. Omit or null for native; 'datalab' and 'nace_router' remain accepted for compatibility."},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to process. Omit to use the whole document."},"page_range":{"anyOf":[{"prefixItems":[{"type":"integer"},{"type":"integer"}],"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Page Range","description":"Legacy [start, end] pair. Prefer page_ranges."},"pages":{"anyOf":[{"$ref":"#/components/schemas/PageSelection"},{"type":"null"}],"description":"Legacy page selector. Prefer page_ranges."},"output_formats":{"anyOf":[{"items":{"type":"string","enum":["markdown","text","blocks"]},"type":"array"},{"type":"null"}],"title":"Output Formats","description":"Legacy formats list. Prefer output.formats."},"quality":{"type":"string","enum":["auto","fast","accurate"],"title":"Quality","description":"Latency versus accuracy preference for this run.","default":"auto"},"ocr":{"$ref":"#/components/schemas/ParseOcrOptions","description":"OCR on/off and language hints."},"output":{"$ref":"#/components/schemas/ParseOutputOptions","description":"Which text renderings, table style, images, and OCR geometry to return."},"figures":{"$ref":"#/components/schemas/ParseFiguresOptions","description":"How figure regions are kept or captioned."},"diagrams":{"$ref":"#/components/schemas/ParseDiagramsOptions","description":"Whether diagram-like figures are rewritten as Mermaid."},"chunking":{"$ref":"#/components/schemas/ParseChunkingOptions","description":"Optional RAG chunking of the parsed document."},"spreadsheet":{"$ref":"#/components/schemas/ParseSpreadsheetOptions","description":"Workbook-only filters for sheets, hidden cells, and formulas."},"password":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Password","description":"Optional PDF password. Never stored in the job payload or returned in any response.","writeOnly":true}},"additionalProperties":false,"type":"object","required":["source"],"title":"ParseRequest","description":"Body for canonical ``POST /v1/parse`` (and the hidden legacy alias).\n\n``page_ranges`` is the canonical one-based inclusive selector. Legacy\n``page_range`` / ``pages`` remain accepted on the wire during rollout.\n\n``password`` is write-only: it is never stored in ``ndi_job.input`` or\nreturned in any response. The service stores an AES-GCM-encrypted copy in\n``ndi_job_secret`` for the unlock activity to consume once, then empties it."},"ParseRequestEcho":{"additionalProperties":true,"type":"object"},"ParseResultSource":{"properties":{"type":{"type":"string","const":"parse_result","title":"Type","default":"parse_result"},"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Succeeded parse job whose artifact should be reused."}},"additionalProperties":false,"type":"object","required":["job_id"],"title":"ParseResultSource","description":"A prior Parse job whose parsed artifact can be reused by downstream methods."},"ParseSettings":{"properties":{"figures":{"anyOf":[{"$ref":"#/components/schemas/ParseSettingsFigures"},{"type":"null"}],"description":"How figure regions are kept in the Parse this operation reads. Omit to keep figures. Only figures.mode omit changes the Parse."},"diagrams":{"anyOf":[{"$ref":"#/components/schemas/ParseDiagramsOptions"},{"type":"null"}],"description":"Whether flowchart-like figures are rewritten as Mermaid fences, as diagrams on Parse. Defaults to omit."},"spreadsheet":{"anyOf":[{"$ref":"#/components/schemas/ParseSpreadsheetOptions"},{"type":"null"}],"description":"Workbook controls, as spreadsheet on Parse. Applied to spreadsheet sources only."},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive pages to read, as page_ranges on Parse. On an operation with its own page_ranges the two must agree. With a parse_result source it keeps only those pages of the reused Parse."},"parse_mode":{"anyOf":[{"type":"string","enum":["high","medium","low"]},{"type":"null"}],"title":"Parse Mode","description":"Parsing effort for the Parse before this operation, as parse_mode on Parse. Omit to use the request's top-level parse_mode, which defaults to low."}},"additionalProperties":false,"type":"object","title":"ParseSettings","description":"Settings for the Parse that runs before Split, Classify, or Extract.\n\nA subset of the ``POST /v1/parse`` body with the same field names and nested\nmodels. Options that only shape the Parse response (``output``, ``chunking``)\nand options the runtime refuses (``quality``, ``ocr``) are not accepted here.\nA setting the file type cannot use is accepted and reported in the result's warnings."},"ParseSettingsFigures":{"properties":{"mode":{"type":"string","enum":["omit","include","describe"],"title":"Mode","description":"omit drops figure regions from the Parse this operation reads. include and describe both keep them and are the default: the operation reads the same Parse for either."}},"additionalProperties":false,"type":"object","required":["mode"],"title":"ParseSettingsFigures","description":"How figure regions are kept in the Parse behind an operation."},"ParseSpreadsheet":{"properties":{"sheets":{"items":{"$ref":"#/components/schemas/ParseSpreadsheetSheet"},"type":"array","title":"Sheets","description":"Per-sheet cell-map and complete-content URLs when the source was a workbook."}},"additionalProperties":false,"type":"object","title":"ParseSpreadsheet","description":"Spreadsheet-specific Parse artifacts."},"ParseSpreadsheetOptions":{"properties":{"sheets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sheets","description":"Optional sheet-name filter. When set, only listed sheets are parsed, in workbook order."},"include_hidden_sheets":{"type":"boolean","title":"Include Hidden Sheets","description":"When false, skip sheets marked hidden in the workbook.","default":true},"include_hidden_rows":{"type":"boolean","title":"Include Hidden Rows","description":"When false, skip rows marked hidden.","default":true},"include_hidden_columns":{"type":"boolean","title":"Include Hidden Columns","description":"When false, skip columns marked hidden.","default":true},"include_formulas":{"type":"boolean","title":"Include Formulas","description":"When true, include formula source text. Cached calculated values are always present.","default":false}},"additionalProperties":false,"type":"object","title":"ParseSpreadsheetOptions","description":"Workbook-specific Parse controls for spreadsheet sources.\n\nDefaults preserve the pre-control behavior: every sheet/row/column is\nincluded and formula *source text* is omitted (cached values still appear)."},"ParseSpreadsheetSheet":{"properties":{"sheet_name":{"type":"string","title":"Sheet Name","description":"Workbook tab this cell map belongs to."},"cell_map_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Map Url","description":"Authenticated job-scoped URL that maps rendered table axes to physical cells."},"content_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Url","description":"Authenticated streaming URL for complete sheet Markdown when document.markdown contains only a bounded preview."},"rows_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rows Url","description":"Authenticated URL for bounded Parquet row pages; accepts start_row and limit."},"markdown_deferred":{"type":"boolean","title":"Markdown Deferred","description":"Full Markdown is generated on demand; content requests may return HTTP 202 while it is prepared.","default":false},"source_sha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Sha256","description":"SHA-256 of the immutable source used by row browsing and full Markdown export."},"row_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Row Count","description":"Total source rows when a row browser is available."},"column_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Column Count","description":"Total source columns when a row browser is available."}},"additionalProperties":false,"type":"object","required":["sheet_name"],"title":"ParseSpreadsheetSheet","description":"Downloadable artifacts for one rendered spreadsheet sheet."},"ParseSummaryWire":{"properties":{"resource_failure":{"anyOf":[{"type":"string","enum":["spill_capacity","memory"]},{"type":"null"}],"title":"Resource Failure","description":"Exhausted engine resource that prevented parsing."},"journals_total":{"type":"integer","title":"Journals Total","description":"Journals found in the ledger, on the accepted journal key."},"candidates":{"type":"integer","title":"Candidates","description":"Journals holding enough account/debit-credit groups to be worth splitting."},"attempted_candidates":{"type":"integer","title":"Attempted Candidates","description":"Candidate journals actually evaluated by the parser.","default":0},"candidate_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Candidate Coverage","description":"Attempted candidates divided by all candidates, or null when none exist."},"population_capped_share":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Population Capped Share","description":"Population-capped candidates divided by all candidates, or null when none exist."},"cap_reason_counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cap Reason Counts","description":"Distinct journals per exact parse stop reason, including the population cap."},"cap_profiles":{"additionalProperties":{"$ref":"#/components/schemas/ParseCapProfileWire"},"type":"object","title":"Cap Profiles","description":"Group and posting count distributions by exact stop reason."},"candidates_capped":{"type":"boolean","title":"Candidates Capped","description":"Whether the population cap cut the candidate set."},"population_capped":{"type":"integer","title":"Population Capped","description":"Candidates the cap excluded; published whole rather than dropped."},"parsed":{"type":"integer","title":"Parsed","description":"Journals split into more than one balanced sub-journal."},"identity":{"type":"integer","title":"Identity","description":"Journals that were never bundles, so each is its own sub-journal."},"hub":{"type":"integer","title":"Hub","description":"Journals where one control account offsets every other — correctly left whole."},"unbalanced":{"type":"integer","title":"Unbalanced","description":"Journals whose own lines do not net to zero."},"capped":{"type":"integer","title":"Capped","description":"Journals left whole because a bound stopped the parse rather than a reading."},"solver_cap_hits":{"type":"integer","title":"Solver Cap Hits","description":"Of those, the ones the solver itself refused."},"sub_journals_total":{"type":"integer","title":"Sub Journals Total","description":"Sub-journals published across the whole ledger."},"per_bucket":{"additionalProperties":{"type":"integer"},"type":"object","title":"Per Bucket","description":"Sub-journals per confidence bucket, keyed '1'–'4': 1 proven, 2 reserved, 3 ambiguous and available on demand, 4 refused as a split."},"basis":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis","description":"The amount basis the parse netted on, or null when it was skipped."},"decimals":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Decimals","description":"The minor-unit scale the parse netted at."},"parse_run_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parse Run Id","description":"Identity of this parse: the package, the version, and its parameters."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Milliseconds the parsing pass spent on this package."},"skipped_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skipped Reason","description":"Why no mapping was produced, when none was. A skipped parse is a recorded answer: the rest of the report stands and the tables are simply absent."},"confirmation_required":{"anyOf":[{"$ref":"#/components/schemas/MappingConfirmationRequired"},{"type":"null"}],"description":"Set when parsing waits for a person to confirm the ledger mapping, with the mapping the run settled."},"tables":{"items":{"$ref":"#/components/schemas/DerivedTableWire"},"type":"array","title":"Tables","description":"The published tables, empty when the pass was skipped."}},"additionalProperties":false,"type":"object","required":["journals_total","candidates","candidates_capped","population_capped","parsed","identity","hub","unbalanced","capped","solver_cap_hits","sub_journals_total","per_bucket","basis","decimals","parse_run_id","duration_ms","skipped_reason","tables"],"title":"ParseSummaryWire","description":"What general-ledger parsing made of the package (§9).\n\nCounts, never rows: the mapping itself is a derived table the testing engine\njoins, and a report that carried it would be a download. The five outcome\ncounts add up to ``journals_total`` by construction — every journal is\nrepresented exactly once, and a hub, an unbalanced entry or a capped one is a\nnamed outcome rather than a missing row.\n\nThe parquet URLs are withheld for the reason the receipts' SQL is: they name\ninternal storage keys, and a caller has no route that reads them."},"ParseVendorProvenanceDisclosure":{"properties":{"code":{"type":"string","const":"parse_vendor_provenance","title":"Code"},"engine":{"$ref":"#/components/schemas/ParseEngine","description":"Stable engine identity that produced the parse without exposing the underlying supplier."},"fallback_depth":{"type":"integer","minimum":0.0,"title":"Fallback Depth","description":"Number of earlier engines that failed before this engine produced the result."}},"additionalProperties":false,"type":"object","required":["code","engine","fallback_depth"],"title":"ParseVendorProvenanceDisclosure","description":"The file was processed by a vendor other than the router's first choice.\n\nThe parse result is valid. The vendor name is published so a caller can\naccount for differing output quality or formatting between vendors."},"ParsedBlock":{"properties":{"id":{"type":"string","title":"Id","description":"Stable id of this layout block within the parsed document."},"type":{"type":"string","title":"Type","description":"Layout role of the block, for example heading, paragraph, table, figure, or signature. A signature block marks where a signature appears; its content is the placeholder [SIGNATURE]."},"content":{"type":"string","title":"Content","description":"Text or caption carried by this block."},"sheet_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet Name","description":"Owning worksheet, including appendix blocks without a cell range. Null for non-spreadsheet blocks."},"source_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Id","description":"Identity of the embedded image or attachment within this document."},"source_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Name","description":"Embedded source display name, including nested attachment paths."},"image_anchor":{"anyOf":[{"$ref":"#/components/schemas/SheetRange"},{"type":"null"}],"description":"Where a picture is anchored on a worksheet; not the location of its OCR data cells."},"markdown_span":{"anyOf":[{"$ref":"#/components/schemas/TextSpan"},{"type":"null"}],"description":"Unicode code-point span in document.markdown, exclusive end. Separate from native source location."},"table_row_offset":{"type":"integer","minimum":0.0,"title":"Table Row Offset","description":"Offset of body rows in the sheet cell map; repeated table header still addresses row index zero.","default":0},"location":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/PageRegion"},{"$ref":"#/components/schemas/SheetRange"},{"$ref":"#/components/schemas/TextSpan"},{"$ref":"#/components/schemas/RowRange"},{"$ref":"#/components/schemas/TableRegion"},{"$ref":"#/components/schemas/JsonPointer"}],"discriminator":{"propertyName":"kind","mapping":{"json_pointer":"#/components/schemas/JsonPointer","page_region":"#/components/schemas/PageRegion","row_range":"#/components/schemas/RowRange","sheet_range":"#/components/schemas/SheetRange","table_region":"#/components/schemas/TableRegion","text_span":"#/components/schemas/TextSpan"}}},{"type":"null"}],"title":"Location","description":"Where this block sits in the source. Null when the parser did not emit geometry."},"confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Confidence","description":"Probability, from 0 to 1, that this block's text matches the page, from the OCR review when it ran. Null when the block was not reviewed, or its text changed after review."},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Crop URL when output.include_images is true and this block is a figure region."}},"additionalProperties":false,"type":"object","required":["id","type","content"],"title":"ParsedBlock","description":"One structural unit of a parsed document."},"ParsedFile":{"properties":{"item_type":{"type":"string","const":"file","title":"Item Type","default":"file"},"markdown_url":{"type":"string","title":"Markdown Url"},"page_count":{"type":"integer","title":"Page Count","default":0},"char_count":{"type":"integer","title":"Char Count","default":0},"extraction_duration_ms":{"type":"integer","title":"Extraction Duration Ms","default":0},"audio_duration_seconds":{"type":"number","title":"Audio Duration Seconds","description":"Duration of the source audio in seconds; non-zero only for audio parses.","default":0}},"type":"object","required":["markdown_url"],"title":"ParsedFile"},"ParsedSheet":{"properties":{"sheet_name":{"type":"string","title":"Sheet Name"},"markdown_url":{"type":"string","title":"Markdown Url"},"max_row":{"type":"integer","title":"Max Row","default":0},"max_col":{"type":"integer","title":"Max Col","default":0},"char_count":{"type":"integer","title":"Char Count","default":0},"non_empty_cell_count":{"type":"integer","title":"Non Empty Cell Count","default":0}},"type":"object","required":["sheet_name","markdown_url"],"title":"ParsedSheet"},"ParsedTable":{"properties":{"item_type":{"type":"string","const":"table","title":"Item Type","default":"table"},"sheets":{"items":{"$ref":"#/components/schemas/ParsedSheet"},"type":"array","title":"Sheets"}},"type":"object","title":"ParsedTable"},"PasswordlessInvitationExchangeRequest":{"properties":{"token":{"type":"string","format":"password","title":"Token","writeOnly":true}},"type":"object","required":["token"],"title":"PasswordlessInvitationExchangeRequest","description":"Secret copied from an invitation URL fragment."},"PasswordlessInvitationExchangeResponse":{"properties":{"created":{"type":"boolean","title":"Created","description":"True when this sign-in wrote something: a new identity, a membership from an accepted invitation, or the default organization for an identity that belonged nowhere."},"user":{"$ref":"#/components/schemas/ConsoleUserInfo"},"organizations":{"items":{"$ref":"#/components/schemas/OrganizationInfo"},"type":"array","title":"Organizations","description":"Every organization the user belongs to. Empty means they belong to none yet."},"can_create_organization":{"type":"boolean","title":"Can Create Organization","description":"Whether this user may still create an organization themselves."},"can_run_evals":{"type":"boolean","title":"Can Run Evals","description":"Whether this identity may use the eval console (a Nace staff email domain). The console hides the section when false; the routes enforce it regardless.","default":false},"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","const":"bearer","title":"Token Type","default":"bearer"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"invited_organization_id":{"type":"string","format":"uuid","title":"Invited Organization Id"}},"type":"object","required":["created","user","organizations","can_create_organization","access_token","expires_at","invited_organization_id"],"title":"PasswordlessInvitationExchangeResponse","description":"A resolved console identity plus its bounded first-party credential."},"PathPrefixQueryScope":{"properties":{"type":{"type":"string","const":"path_prefix","title":"Type","default":"path_prefix"},"prefix":{"type":"string","maxLength":1024,"minLength":1,"title":"Prefix"}},"additionalProperties":false,"type":"object","required":["prefix"],"title":"PathPrefixQueryScope","description":"The question ran against one folder subtree."},"PathPrefixSelection":{"properties":{"type":{"type":"string","const":"path_prefix","title":"Type","default":"path_prefix"},"path_prefix":{"type":"string","maxLength":1024,"title":"Path Prefix","default":""},"stale_only":{"type":"boolean","title":"Stale Only","description":"Re-ingest only files whose observed and ingested hashes diverged.","default":false}},"additionalProperties":false,"type":"object","title":"PathPrefixSelection","description":"A folder. ``\"\"`` or ``\"/\"`` means the whole workspace."},"PerceptionImprovement":{"properties":{"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"result":{"type":"string","title":"Result"},"lane_ids":{"items":{"type":"string"},"type":"array","title":"Lane Ids"},"pr_urls":{"items":{"type":"string"},"type":"array","title":"Pr Urls"}},"type":"object","required":["title","summary","result"],"title":"PerceptionImprovement","description":"An NDI change introduced in one iteration."},"PerceptionLane":{"properties":{"id":{"type":"string","pattern":"^(parse|ground|split|classify|extract)-[a-z0-9-]+$","title":"Id"},"operation":{"type":"string","enum":["parse","ground","split","classify","extract"],"title":"Operation"},"document_type":{"type":"string","title":"Document Type"},"baseline_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Baseline Score"},"ndi_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Ndi Score"},"official_comparator":{"anyOf":[{"$ref":"#/components/schemas/OfficialComparator"},{"type":"null"}]},"status":{"type":"string","enum":["verified_leader","provisional_leader","improved","behind","limited_evidence","regressed"],"title":"Status"},"median_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Median Seconds"},"p95_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"P95 Seconds"},"usage_units":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Usage Units"},"estimated_cost_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Estimated Cost Usd"},"evidence":{"type":"string","title":"Evidence"},"frontier_references":{"items":{"$ref":"#/components/schemas/FrontierReference"},"type":"array","title":"Frontier References"}},"type":"object","required":["id","operation","document_type","baseline_score","ndi_score","status","evidence"],"title":"PerceptionLane","description":"One endpoint and document-format accuracy lane."},"PerceptionLeaderboard":{"properties":{"latest_version":{"type":"string","title":"Latest Version"},"snapshots":{"items":{"$ref":"#/components/schemas/PerceptionSnapshot"},"type":"array","title":"Snapshots"}},"type":"object","required":["latest_version","snapshots"],"title":"PerceptionLeaderboard","description":"All immutable checkpoints, oldest first."},"PerceptionSnapshot":{"properties":{"version":{"type":"string","title":"Version"},"published_at":{"type":"string","format":"date","title":"Published At"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"dataset":{"$ref":"#/components/schemas/DatasetReference"},"frontier_dataset":{"anyOf":[{"$ref":"#/components/schemas/DatasetReference"},{"type":"null"}]},"verified_leaders":{"type":"integer","maximum":31.0,"minimum":0.0,"title":"Verified Leaders"},"leaders_with_provisional":{"type":"integer","maximum":31.0,"minimum":0.0,"title":"Leaders With Provisional"},"close_signals":{"anyOf":[{"type":"integer","maximum":31.0,"minimum":0.0},{"type":"null"}],"title":"Close Signals"},"lanes":{"items":{"$ref":"#/components/schemas/PerceptionLane"},"type":"array","title":"Lanes"},"improvements":{"items":{"$ref":"#/components/schemas/PerceptionImprovement"},"type":"array","title":"Improvements"},"provider_campaigns":{"items":{"$ref":"#/components/schemas/ProviderCampaign"},"type":"array","title":"Provider Campaigns"}},"type":"object","required":["version","published_at","title","summary","dataset","verified_leaders","leaders_with_provisional","lanes"],"title":"PerceptionSnapshot","description":"The complete cumulative leaderboard at one historical checkpoint."},"PlaygroundQuota":{"properties":{"remaining":{"type":"integer","title":"Remaining"},"limit":{"type":"integer","title":"Limit"},"reset_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Reset At"}},"additionalProperties":false,"type":"object","required":["remaining","limit"],"title":"PlaygroundQuota","description":"How many anonymous tries remain in the current window."},"PopulationCandidateWire":{"properties":{"attempts":{"items":{"$ref":"#/components/schemas/KeyAttempt"},"type":"array","title":"Attempts","description":"Bounded aggregate candidate measurement and rejection explanations."},"label":{"type":"string","title":"Label","description":"The composer's candidate label; use the existing role-slot review flow."},"tables":{"items":{"type":"string"},"type":"array","title":"Tables","description":"Bounded physical member names."},"paths":{"items":{"type":"string"},"type":"array","title":"Paths","description":"Bounded member paths in this package scope."},"member_count":{"type":"integer","title":"Member Count","description":"Complete member count, including members beyond the listing bound."},"rows":{"type":"integer","title":"Rows","description":"Census row count across all members."},"journal_key":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Journal Key","description":"Accepted complete-population identity, or unknown."},"basis":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis","description":"Basis measured by the accepted key proof."},"balanced_share":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balanced Share","description":"Measured journal balance share; not a selection rule."},"selected":{"type":"boolean","title":"Selected","description":"Whether this exact member set fills the journal-lines slot."},"classification":{"type":"string","enum":["primary","duplicate_projection","supporting_reversal","candidate"],"title":"Classification","description":"How complete-population evidence relates this source to the settled primary.","default":"candidate"},"classification_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Classification Reason","description":"Bounded explanation of the automatic classification, where one was proven."},"unresolved_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unresolved Reason","description":"Why this population has no accepted identity."}},"additionalProperties":false,"type":"object","required":["label","tables","paths","member_count","rows","selected"],"title":"PopulationCandidateWire"},"PreparationSummaryWire":{"properties":{"name":{"type":"string","title":"Name","description":"Stable configured relationship name."},"status":{"type":"string","enum":["ready","unavailable","failed"],"title":"Status","description":"Whether a complete reusable generation was published."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Bounded reason when the relationship is not ready."},"reused":{"type":"boolean","title":"Reused","description":"Whether an existing complete generation was reused.","default":false},"bucket_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bucket Count","description":"Published bucket count when preparation is ready."},"left_rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Left Rows","description":"Rows published for the left side when ready."},"right_rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Right Rows","description":"Rows published for the right side when ready."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"Combined byte size of both published sides when ready."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Milliseconds spent loading or preparing this relationship.","default":0}},"additionalProperties":false,"type":"object","required":["name","status"],"title":"PreparationSummaryWire","description":"Bounded status of one configured reusable JET relationship."},"PreparedIdentityNormalizationConfig":{"properties":{"kind":{"type":"string","const":"identity","title":"Kind","description":"Keep the stored text unchanged.","default":"identity"}},"additionalProperties":false,"type":"object","title":"PreparedIdentityNormalizationConfig","description":"Compare a VARCHAR key exactly as stored."},"PreparedKeyConfig":{"properties":{"left_column":{"type":"string","minLength":1,"title":"Left Column","description":"Column on the left table."},"right_column":{"type":"string","minLength":1,"title":"Right Column","description":"Column on the right table."},"left_normalization":{"oneOf":[{"$ref":"#/components/schemas/PreparedIdentityNormalizationConfig"},{"$ref":"#/components/schemas/PreparedLeftPadNormalizationConfig"}],"title":"Left Normalization","description":"Reviewed normalization applied to the left column.","discriminator":{"propertyName":"kind","mapping":{"identity":"#/components/schemas/PreparedIdentityNormalizationConfig","left_pad":"#/components/schemas/PreparedLeftPadNormalizationConfig"}}},"right_normalization":{"oneOf":[{"$ref":"#/components/schemas/PreparedIdentityNormalizationConfig"},{"$ref":"#/components/schemas/PreparedLeftPadNormalizationConfig"}],"title":"Right Normalization","description":"Reviewed normalization applied to the right column.","discriminator":{"propertyName":"kind","mapping":{"identity":"#/components/schemas/PreparedIdentityNormalizationConfig","left_pad":"#/components/schemas/PreparedLeftPadNormalizationConfig"}}}},"additionalProperties":false,"type":"object","required":["left_column","right_column"],"title":"PreparedKeyConfig","description":"One ordered equality component of a prepared relationship."},"PreparedLeftPadNormalizationConfig":{"properties":{"kind":{"type":"string","const":"left_pad","title":"Kind","description":"Left-pad the stored text to a fixed width.","default":"left_pad"},"width":{"type":"integer","maximum":1024.0,"exclusiveMinimum":0.0,"title":"Width","description":"Width of the normalized key."},"fill":{"type":"string","maxLength":1,"minLength":1,"title":"Fill","description":"Single character used for padding."}},"additionalProperties":false,"type":"object","required":["width","fill"],"title":"PreparedLeftPadNormalizationConfig","description":"Apply the declared single-character left padding before comparison."},"PreparedRelationshipConfig":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name","description":"Stable name for the prepared relationship."},"left":{"$ref":"#/components/schemas/PreparedTableSelectionConfig","description":"Workspace table used as the left side."},"right":{"$ref":"#/components/schemas/PreparedTableSelectionConfig","description":"Workspace table used as the right side."},"keys":{"items":{"$ref":"#/components/schemas/PreparedKeyConfig"},"type":"array","maxItems":8,"minItems":1,"title":"Keys","description":"Ordered equality key components."},"bucket_count":{"type":"integer","maximum":1024.0,"exclusiveMinimum":0.0,"title":"Bucket Count","description":"Number of hash buckets materialized on each side."}},"additionalProperties":false,"type":"object","required":["name","left","right","keys","bucket_count"],"title":"PreparedRelationshipConfig","description":"One reviewed large-table relationship ledger understanding should prepare."},"PreparedTableSelectionConfig":{"properties":{"path":{"type":"string","minLength":1,"title":"Path","description":"Workspace path or published dataset root."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"Worksheet or component when the path has more than one table."}},"additionalProperties":false,"type":"object","required":["path"],"title":"PreparedTableSelectionConfig","description":"One logical source table selected by its stable workspace coordinate."},"ProcedureReadinessWire":{"properties":{"status":{"type":"string","enum":["ready","limited","unavailable","unknown"],"title":"Status","description":"Whether this procedure's inputs are available."},"reasons":{"items":{"type":"string"},"type":"array","title":"Reasons","description":"Limits or missing evidence for this procedure."}},"additionalProperties":false,"type":"object","required":["status"],"title":"ProcedureReadinessWire","description":"Readiness for one procedure, never a blanket permission to run JET."},"ProposedStructure":{"properties":{"journal_key":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Journal Key","description":"Ordered journal identity to measure."},"account":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Account","description":"Exact physical columns forming the ordered account identity. Use one complete account-code column, or the evidenced account segments and namespace qualifiers needed to distinguish accounts. May share qualifiers with journal_key; remains a nomination awaiting measured validation."},"amount":{"oneOf":[{"$ref":"#/components/schemas/PairedAmount"},{"$ref":"#/components/schemas/SignedAmount"}],"title":"Amount","description":"Proposed amount columns and their interpretation.","discriminator":{"propertyName":"kind","mapping":{"paired":"#/components/schemas/PairedAmount","signed":"#/components/schemas/SignedAmount"}}},"effective_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Date","description":"Proposed typed posting date column."},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period","description":"Proposed fiscal period column."},"line_ordinal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line Ordinal","description":"Proposed numeric line ordinal column."},"entity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity","description":"Proposed entity qualifier, retained for reviewer context."}},"additionalProperties":false,"type":"object","required":["journal_key","account","amount"],"title":"ProposedStructure"},"ProviderCampaign":{"properties":{"id":{"type":"string","pattern":"^[a-z0-9-]+$","title":"Id"},"name":{"type":"string","title":"Name"},"operation":{"type":"string","enum":["parse","ground","split","classify","extract"],"title":"Operation"},"metric":{"type":"string","title":"Metric"},"scope":{"type":"string","title":"Scope"},"qualification":{"type":"string","title":"Qualification"},"dataset":{"anyOf":[{"$ref":"#/components/schemas/DatasetReference"},{"type":"null"}]},"results":{"items":{"$ref":"#/components/schemas/ProviderCampaignResult"},"type":"array","title":"Results"}},"type":"object","required":["id","name","operation","metric","scope","qualification","results"],"title":"ProviderCampaign","description":"A comparison whose provider rows share one metric and corpus scope."},"ProviderCampaignResult":{"properties":{"provider":{"type":"string","title":"Provider"},"score":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Score"},"median_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Median Seconds"},"p95_seconds":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"P95 Seconds"},"cost_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Cost Usd"},"cost_kind":{"type":"string","enum":["captured","estimated","captured_lower_bound","proxy_upper_bound","not_captured","not_run"],"title":"Cost Kind"},"qualification":{"type":"string","title":"Qualification"}},"type":"object","required":["provider","cost_kind","qualification"],"title":"ProviderCampaignResult","description":"One provider's result within a named, fixed-scope campaign."},"ProvisionEvalWorkspaceRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"pattern":"^[A-Za-z0-9._-]+$","title":"Name"},"source":{"type":"string","maxLength":500,"minLength":1,"title":"Source"}},"type":"object","required":["name","source"],"title":"ProvisionEvalWorkspaceRequest","description":"Create → upload → ingest → record one prepared workspace.\n\n``source`` is what the CLI's ``provision_ndi_workspace.py`` takes — an\n``hf://org/repo[/slug]`` corpus URI or a directory inside the worker's\ndataset root — plus one the CLI has no need for: the name of a registered\ncorpus builder, which rebuilds the corpus from upstream first. That form\nexists for the corpora we cannot republish ourselves."},"ProvisionEvalWorkspaceResponse":{"properties":{"name":{"type":"string","title":"Name"},"workflow_id":{"type":"string","title":"Workflow Id","description":"Provisioning runs on the eval queue; poll the prepared-workspace list."}},"type":"object","required":["name","workflow_id"],"title":"ProvisionEvalWorkspaceResponse"},"PutTenantRequest":{"properties":{"display_name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1,"description":"Human-readable name of the tenant."},{"type":"null"}],"title":"Display Name"},"disabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disabled","description":"True disables the tenant (its requests answer tenant_disabled); false re-enables it."},"limits":{"anyOf":[{"$ref":"#/components/schemas/TenantLimitsRequest"},{"type":"null"}],"description":"Limits to set on the tenant."},"workspace_storage_limit_bytes":{"anyOf":[{"type":"integer","maximum":9.223372036854776e+18,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Workspace Storage Limit Bytes","description":"Allowance for current source-file bytes across this tenant’s managed workspaces. Omit to preserve the allowance; null removes it. Enforcement requires WORKSPACE_STORAGE_LIMITS_ENABLED."},"data_retention":{"anyOf":[{"$ref":"#/components/schemas/GranularRetention"},{"type":"null"}],"description":"How the tenant's document operations retain data: short or zero_retention. Omit it when creating to inherit your own setting, or when updating to leave it unchanged."}},"additionalProperties":false,"type":"object","title":"PutTenantRequest","description":"Create a tenant, or update the one with this ``external_ref``. Omitted fields stay as they are."},"QaFileRequest":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path","description":"The uploaded file's full path relative to the workspace root, exactly as it was uploaded and as listings and search results print it — e.g. `evidence/doc-7f83/contract.pdf`. Not a bare file name (a file's `file_name`), a folder, a file id, or a path that starts with the workspace id."},"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query"},"include_citations":{"type":"boolean","title":"Include Citations","default":true},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component"},"output_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Output Schema","description":"A 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."}},"additionalProperties":false,"type":"object","required":["path","query"],"title":"QaFileRequest","description":"Request body for ``qa-file``.\n\n``path`` names an **uploaded source file** — the same addressing as\n``file-metadata``; a workspace-internal derivative path is refused with\n``invalid_request``. ``component`` scopes the question to one public\ncomponent by name (a pdf section or a workbook tab — the names\n``file-metadata`` lists). For a PDF it may also name one of the figures\n``file-metadata`` lists (``figure p3-1``: vision over that picture alone)\nor a page (``page 3``: vision over the whole rendered page)."},"QaFileResponse":{"properties":{"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id"},"answer":{"type":"string","title":"Answer"},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"citations":{"items":{"$ref":"#/components/schemas/Evidence"},"type":"array","title":"Citations"},"engine":{"type":"string","enum":["recursive_llm","vision","agent"],"title":"Engine"},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"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)."},"unavailable":{"items":{"$ref":"#/components/schemas/UnavailableTable"},"type":"array","title":"Unavailable","default":[]},"timed_out":{"type":"boolean","title":"Timed Out","default":false}},"additionalProperties":false,"type":"object","required":["answer","citations","engine"],"title":"QaFileResponse","description":"Response body for ``qa-file``.\n\n``engine`` reports what answered: ``recursive_llm`` for prose, ``vision``\nfor an image, and ``agent`` when the file has several parts and a QA agent\nworked across them. Citations always name the uploaded file, never\nanything internal.\n\n``job_id`` is the durable job row created for this run; poll or retrieve\nit via ``GET /v1/jobs/{job_id}`` to get the stored answer after the fact.\n\n``unavailable`` is always empty since table files moved to ``query-tables``\n(which reports unqueryable selections there); the field is retained for\nwire compatibility."},"QaFileResult":{"properties":{"result_type":{"type":"string","const":"qa_file","title":"Result Type","default":"qa_file"},"steps_used":{"type":"integer","title":"Steps Used","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"The agent's step budget ran out before it completed an answer. A successful run, not a failure.","default":false},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The prose the run returned. Null only on a pre-history row."},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"engine":{"anyOf":[{"type":"string","enum":["recursive_llm","vision","agent"]},{"type":"null"}],"title":"Engine"},"scope_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope Path","description":"The uploaded file the question was asked about."},"scope_component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope Component","description":"The component (tab / section) the ask was narrowed to."},"citations":{"items":{"$ref":"#/components/schemas/Evidence"},"type":"array","title":"Citations"},"unavailable":{"items":{"$ref":"#/components/schemas/UnavailableTable"},"type":"array","title":"Unavailable"},"timed_out":{"type":"boolean","title":"Timed Out","description":"A guard fired before the engine answered. The body holds the partial-answer wording, not a failure.","default":false},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The engine's self-graded confidence; None when it could not grade."}},"additionalProperties":false,"type":"object","title":"QaFileResult","description":"One qa-file run, stored whole so the answer can be reopened.\n\nEvery field past ``exhausted`` arrived with job-backed history; rows written\nbefore it carry only the two receipt fields and still validate, so nothing\nneeds backfilling. A reopened run answers the same question over the same\nscope: ``scope_path`` and ``scope_component`` are what the caller asked\nabout, not where the answer came from."},"QaJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"automatic_agent","title":"Kind","description":"The automatic search agent, which answers every QA turn.","default":"automatic_agent"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/AutomaticAgentResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"QaJob","description":"One turn of a ``qa`` conversation: the automatic search agent's job, answered or asking back."},"QaRequest":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"What to answer, in the caller's own words. Stripped before its length is checked; a blank query is refused rather than run."},"context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Context","description":"Free-form background for the model — the engagement, the entity, what the caller already knows. It informs the answer; it does not widen or narrow which files the caller may see."},"path_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Prefix","description":"Put every uploaded file under one folder subtree, workspace-relative, in the run's scope; `paths`, where the body takes it, adds more files. Omit both for the whole workspace."},"paths":{"anyOf":[{"items":{"type":"string","maxLength":1024,"minLength":1},"type":"array","minItems":1},{"type":"null"}],"title":"Paths","description":"Scope the conversation to exactly these uploaded files. Every tool the agent runs sees only these files and the content ingested from them. Each entry names an uploaded source file (never a folder — scope folders with path_prefix; the two add up). Unknown or inaccessible paths are refused up front."},"session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Session Id","description":"Continue a conversation: the `session_id` echoed on an earlier turn's result. With the same folder/file scope and access grants the agent resumes the conversation, so a follow-up can lean on what was already asked and answered; a changed scope or grants starts a fresh conversation and returns a new `session_id`. Omit to start one. Only the API key that started it may continue it; a conversation whose turn is still running returns 409 session_busy."},"allow_clarification":{"type":"boolean","title":"Allow Clarification","description":"Let the agent ask instead of guessing when a question is genuinely ambiguous and the reading materially changes the answer. Such a turn's result carries the questions in `clarification_questions` with `answer` null; reply in the same conversation with `clarification_answers` or a rephrased query. A turn that sends `clarification_answers` never asks again. On by default; off means the agent always answers with its best reading, stated in the answer.","default":true},"clarification_answers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ClarificationAnswer"},"type":"array","maxItems":2,"minItems":1},{"type":"null"}],"title":"Clarification Answers","description":"Answers to the clarifying questions this conversation's last turn asked, one per question, in order. Send them with that turn's `session_id` and its `query`; the agent then answers that query with the answers applied."},"output_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Output Schema","description":"A 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. Applies only to the turn that sends it: to keep structured answers across a conversation, send it on every turn, including a reply to clarifying questions. A turn that asks clarifying questions returns them with `structured_answer` null."}},"additionalProperties":false,"type":"object","required":["query"],"title":"QaRequest","description":"Body for ``POST /workspaces/{workspace_id}/qa`` — one turn of a question-answering conversation.\n\nEach turn runs the automatic search agent alone: no router, no fact\npipeline and no opening search. The agent finds what the turn needs itself,\nin the light of the conversation so far, then reads and computes until it can\nanswer. No model, effort or tool-surface field: the service resolves the\nconfiguration."},"QaTableResultFile":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"handle":{"type":"string","title":"Handle"},"path":{"type":"string","title":"Path"},"file_name":{"type":"string","title":"File Name"},"format":{"type":"string","const":"parquet","title":"Format","default":"parquet"},"row_count":{"type":"integer","title":"Row Count"},"sql":{"type":"string","title":"Sql"},"source_paths":{"items":{"type":"string"},"type":"array","title":"Source Paths"},"grounding":{"anyOf":[{"$ref":"#/components/schemas/TableQueryGrounding"},{"type":"null"}],"description":"Exact source regions and bounded receipt data when capture-time provenance was available."},"download_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Download Url","description":"Minted on read; null when the artifact is gone."},"preview_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview Url","description":"Minted on read; null when the artifact is gone."},"download_url_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Download Url Expires At"}},"additionalProperties":false,"type":"object","required":["file_id","handle","path","file_name","row_count","sql"],"title":"QaTableResultFile","description":"A Parquet result this run retained, addressable in the caller's workspace.\n\nThe canonical ``s3://`` / ``file://`` location is deliberately absent: it is\nkept privately alongside the stored result (``StoredQaTablesResult``), and\nevery read mints a fresh, expiring pair of URLs from it. A stored URL would\nbe expired by the time anyone reopened the run."},"QaTablesResult":{"properties":{"result_type":{"type":"string","const":"qa_tables","title":"Result Type","default":"qa_tables"},"steps_used":{"type":"integer","title":"Steps Used","default":0},"exhausted":{"type":"boolean","title":"Exhausted","description":"The agent's step budget ran out before it completed an answer. A successful run, not a failure.","default":false},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The prose the run returned. Null only on a pre-history row."},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"The engine's own reported trouble on an otherwise 200 run."},"timed_out":{"type":"boolean","title":"Timed Out","default":false},"source_paths":{"items":{"type":"string"},"type":"array","title":"Source Paths","description":"The table selections the question was asked over."},"source_components":{"items":{"type":"string"},"type":"array","title":"Source Components","description":"The named tabs among those selections."},"citations":{"items":{"$ref":"#/components/schemas/Evidence"},"type":"array","title":"Citations"},"tables":{"items":{"$ref":"#/components/schemas/QueryTablePreview"},"type":"array","title":"Tables"},"result_files":{"items":{"$ref":"#/components/schemas/QaTableResultFile"},"type":"array","title":"Result Files"},"result_materialization_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Materialization Error"},"unavailable":{"items":{"$ref":"#/components/schemas/UnavailableTable"},"type":"array","title":"Unavailable"},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The engine's self-graded confidence; None when it could not grade."}},"additionalProperties":false,"type":"object","title":"QaTablesResult","description":"One query-tables run, stored whole so the answer can be reopened.\n\nAs with :class:`QaFileResult`, everything past ``exhausted`` arrived with\njob-backed history and is optional, so receipt-only rows still validate.\nBoth lanes land in this one shape: the SQL lane fills ``tables`` and\n``result_files``, the agent lane fills ``answer`` and ``citations`` only."},"QueryTableCitation":{"properties":{"result_file":{"$ref":"#/components/schemas/QueryTableResultFile"},"source_paths":{"items":{"type":"string"},"type":"array","title":"Source Paths"},"sql":{"type":"string","title":"Sql"},"grounding":{"anyOf":[{"$ref":"#/components/schemas/TableQueryGrounding"},{"type":"null"}],"description":"Exact source regions and bounded receipt data when capture-time provenance was available."}},"additionalProperties":false,"type":"object","required":["result_file","source_paths","sql"],"title":"QueryTableCitation","description":"Provenance for one generated TablesQA result file."},"QueryTableColumn":{"properties":{"name":{"type":"string","title":"Name"},"data_type":{"type":"string","title":"Data Type"}},"additionalProperties":false,"type":"object","required":["name","data_type"],"title":"QueryTableColumn","description":"One public column in a retained result preview."},"QueryTablePreview":{"properties":{"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"handle":{"type":"string","title":"Handle"},"row_count":{"type":"integer","title":"Row Count"},"columns":{"items":{"$ref":"#/components/schemas/QueryTableColumn"},"type":"array","maxItems":50,"title":"Columns","default":[]},"rows":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","maxItems":20,"title":"Rows","default":[]},"preview_truncated":{"type":"boolean","title":"Preview Truncated","default":false}},"additionalProperties":false,"type":"object","required":["handle","row_count"],"title":"QueryTablePreview","description":"One retained result table with a bounded inline preview."},"QueryTableResultFile":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"handle":{"type":"string","title":"Handle"},"path":{"type":"string","title":"Path"},"file_name":{"type":"string","title":"File Name"},"format":{"type":"string","const":"parquet","title":"Format"},"row_count":{"type":"integer","title":"Row Count"},"download_url":{"type":"string","title":"Download Url"},"preview_url":{"type":"string","title":"Preview Url"},"download_url_expires_at":{"type":"string","format":"date-time","title":"Download Url Expires At"}},"additionalProperties":false,"type":"object","required":["file_id","handle","path","file_name","format","row_count","download_url","preview_url","download_url_expires_at"],"title":"QueryTableResultFile","description":"A workspace-visible Parquet file retained from a TablesQA query."},"QueryTableSelection":{"properties":{"path":{"type":"string","title":"Path"},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"One tab of this workbook. Omit to select the whole file. Repeat the path in another row to select several tabs."}},"additionalProperties":false,"type":"object","required":["path"],"title":"QueryTableSelection","description":"One selection row: a whole table file, or one tab of one workbook.\n\n``component`` is workbook-local vocabulary — the same strings\n``file-metadata`` publishes as ``component`` and ``qa-file`` accepts as\n``component=``, matched exact-name first, then the unambiguous sanitized\nalias. There is deliberately no cross-file component filter: the same tab\nname in two workbooks is two rows. Naming a component of a single-table\nupload (csv/jsonl/parquet — one table, no named parts) is refused rather\nthan silently ignored: the caller selected something that does not exist,\nand answering anyway would answer a different question."},"QueryTablesRequest":{"properties":{"paths":{"items":{"$ref":"#/components/schemas/QueryTableSelection"},"type":"array","maxItems":32,"minItems":1,"title":"Paths"},"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query"},"include_citations":{"type":"boolean","title":"Include Citations","default":true},"output_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Output Schema","description":"A 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."}},"additionalProperties":false,"type":"object","required":["paths","query"],"title":"QueryTablesRequest","description":"Question over a bounded set of workspace-uploaded table selections.\n\nEvery row's ``path`` must name a **table file** — a spreadsheet (xlsx,\nxls, xlsm, xlsb, ods) or record file (csv, tsv, parquet, jsonl, ndjson,\njson); a document, media, or image path is refused with\n``invalid_request`` naming ``qa-file``. Every tab is\naskable whatever its ingestion produced — extracted rows, a rendered\nsheet, or both."},"QueryTablesResponse":{"properties":{"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id"},"answer":{"type":"string","title":"Answer"},"structured_answer":{"anyOf":[{"$ref":"#/components/schemas/JsonValue"},{"type":"null"}],"description":"`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."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"timed_out":{"type":"boolean","title":"Timed Out","default":false},"confidence":{"anyOf":[{"$ref":"#/components/schemas/ConfidenceLevel"},{"type":"null"}],"description":"The engine's self-graded confidence in the answer — how well the queried tables support 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)."},"citations":{"items":{"$ref":"#/components/schemas/Evidence"},"type":"array","title":"Citations","default":[]},"result_citations":{"items":{"$ref":"#/components/schemas/QueryTableCitation"},"type":"array","title":"Result Citations","default":[]},"result_materialization_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Materialization Error"},"unavailable":{"items":{"$ref":"#/components/schemas/UnavailableTable"},"type":"array","title":"Unavailable","default":[]},"tables":{"items":{"$ref":"#/components/schemas/QueryTablePreview"},"type":"array","title":"Tables","default":[]}},"additionalProperties":false,"type":"object","required":["answer"],"title":"QueryTablesResponse","description":"Answer, provenance, unavailable inputs, and retained result previews.\n\nTwo lanes fill this shape. An all-queryable selection runs the SQL engine\nand returns everything: ``tables`` previews, ``result_citations``, and SQL\nreceipts in ``citations``. A selection holding tabs without extracted rows\nruns a QA agent over the files' rendered sheets and row extractions\ntogether — the answer and quoted ``citations`` are filled, while\n``tables`` and ``result_citations`` stay empty (no SQL results exist to\nretain). ``unavailable`` reports selections with no usable content on\neither lane.\n\n``job_id`` is the durable job row created for this run; retrieve it via\n``GET /v1/jobs/{job_id}`` to inspect or replay the stored answer."},"ReadFileRequest":{"properties":{"path":{"type":"string","maxLength":1024,"minLength":1,"title":"Path","description":"The uploaded file's full path relative to the workspace root, exactly as it was uploaded and as listings and search results print it — e.g. `evidence/doc-7f83/contract.pdf`. Not a bare file name (a file's `file_name`), a folder, a file id, or a path that starts with the workspace id."},"pages":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Pages","description":"1-based page numbers to read; omitted: every page. Spreadsheets have no pages."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"One tab or section to read, named as file-metadata lists it; omitted: the whole file."},"max_chars":{"type":"integer","maximum":1000000.0,"minimum":1.0,"title":"Max Chars","description":"Character budget for the returned text; past it `truncated` is true.","default":200000},"line_start":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Line Start","description":"First line to return, 1-based, counted in the text this read would return without a line range (after component and page selection). Omitted: line 1."},"line_end":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Line End","description":"Last line to return, inclusive and 1-based like line_start. Omitted: the last line."}},"additionalProperties":false,"type":"object","required":["path"],"title":"ReadFileRequest","description":"Request body for ``read-file``.\n\n``path`` names an **uploaded source file** — the only namespace this tool\nserves. A workspace-internal derivative path is refused with\n``invalid_request`` naming the uploaded file that owns it.\n\n``component`` scopes the read to one public component by name — a\nspreadsheet tab or a pdf section, as listed by ``file-metadata``.\n\n``pages`` is 1-based and selects on the file's absolute page numbers;\nout-of-range pages are ignored (absent from ``pages_returned``). Selected\npages come back de-duplicated in document order, whatever order they were\nasked in. Spreadsheets have no pages — scope those with ``component``\ninstead."},"ReadFileResponse":{"properties":{"path":{"type":"string","title":"Path"},"file_id":{"type":"string","format":"uuid","title":"File Id"},"content":{"type":"string","title":"Content"},"pages_returned":{"items":{"type":"integer"},"type":"array","title":"Pages Returned"},"truncated":{"type":"boolean","title":"Truncated"},"components_returned":{"items":{"type":"string"},"type":"array","title":"Components Returned"},"components_omitted":{"items":{"type":"string"},"type":"array","title":"Components Omitted"},"sql_tables":{"items":{"type":"string"},"type":"array","title":"Sql Tables","description":"The run-sql names of the tables holding the rows of the long tables printed in the returned sections — count, total or rank those rows there rather than from the text."},"line_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line Start","description":"First line returned (1-based) when the request named a line range; None otherwise."},"line_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line End","description":"Last line returned (inclusive) when the request named a line range; None otherwise or when line_start is past the end of the text."},"line_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Line Count","description":"How many lines the whole selected text has, when the request named a line range; None otherwise."},"table":{"anyOf":[{"$ref":"#/components/schemas/GrepTable"},{"type":"null"}],"description":"When a line range starts inside a table, below its header row: that table's lines, title and header, so the rows read with their column names."},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["path","file_id","content","pages_returned","truncated","components_returned","components_omitted"],"title":"ReadFileResponse","description":"Response body for ``read-file``.\n\nA file with several components (a spreadsheet's tabs, a pdf's sections)\nanswers with their text concatenated in the file's own order, each part\nprefixed by a one-line header naming the component. ``components_returned``\nlists what contributed to ``content``; ``components_omitted`` lists\ncomponents that were cut for size — the character budget ran out, or a\npart was too large to serve — or that have no text rendering at all (a\nquery-only tab; ask it with ``qa-file``) — so an absent component is\nalways visible, never a silently missing tab. Unnamed components (a\nrecording, a raw upload) are listed by kind. A table a PDF page holds\ncomes as rows — one ``| a | b |`` line each under a header that joins the\nstacked column headings — the way grep and hybrid-search print it."},"ReadFileResult":{"properties":{"result_type":{"type":"string","const":"read_file","title":"Result Type","default":"read_file"},"output":{"$ref":"#/components/schemas/ReadFileResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"ReadFileResult"},"ReconcileRequest":{"properties":{"path_prefix":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Path Prefix"},"auto_ingest":{"type":"boolean","title":"Auto Ingest","default":false}},"additionalProperties":false,"type":"object","title":"ReconcileRequest","description":"Body for ``POST /v1/workspaces/{workspace_id}/reconciliations``.\n\nReconciliation compares the customer-visible storage tree against the\nledger and records divergences there. The scan itself never changes stored\nbytes or derived representations. ``auto_ingest`` additionally chains\ningestion into the same request for the routine case.\n\nWhat ``reconcile`` can detect:\n\n* ``discovered`` — objects in storage that have no ledger row yet.\n* ``stale`` — ledger rows whose ``observed_hash`` no longer matches the\n  object in storage.\n* ``orphans`` — ledger rows whose object is gone from storage.\n\n``path_prefix`` scopes the scan; omit it (or pass ``\"\"``) to scan the\nwhole workspace.  ``auto_ingest`` queues an ingestion for everything the\nscan found, so the routine case is one call. Without it, ledger changes are\nstill recorded and the result tells you what diverged; no ingestion starts."},"ReconciliationJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"reconciliation","title":"Kind","default":"reconciliation"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ReconciliationResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"ReconciliationJob"},"ReconciliationResult":{"properties":{"result_type":{"type":"string","const":"reconciliation","title":"Result Type","default":"reconciliation"},"files_scanned":{"type":"integer","title":"Files Scanned"},"discovered":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Discovered","description":"In storage, absent from the ledger."},"marked_stale":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Marked Stale","description":"observed_hash != ingested_hash."},"orphans_removed":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Orphans Removed","description":"In the ledger, absent from storage."},"ingestion_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Ingestion Job Id","description":"Set when auto_ingest was requested."}},"additionalProperties":false,"type":"object","required":["files_scanned"],"title":"ReconciliationResult","description":"Reconciliation only ever *detects*; ingestion is what acts."},"RejectedCandidate":{"properties":{"primary_source_id":{"type":"string","title":"Primary Source Id","description":"Primary handle returned by the model."},"reason":{"type":"string","title":"Reason","description":"Why catalog validation refused the candidate."},"conflicts":{"items":{"$ref":"#/components/schemas/StructureRoleConflict"},"type":"array","title":"Conflicts","description":"Column-level role conflicts that made the proposed structure invalid."}},"additionalProperties":false,"type":"object","required":["primary_source_id","reason"],"title":"RejectedCandidate"},"RenameOrganizationRequest":{"properties":{"display_name":{"type":"string","maxLength":128,"minLength":1,"title":"Display Name"}},"type":"object","required":["display_name"],"title":"RenameOrganizationRequest"},"ReplaceFileJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"file_replace","title":"Kind","default":"file_replace"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/ReplaceFileResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"ReplaceFileJob"},"ReplaceFileResult":{"properties":{"result_type":{"type":"string","const":"file_replace","title":"Result Type","default":"file_replace"},"file":{"$ref":"#/components/schemas/File"},"previous_version":{"type":"integer","title":"Previous Version"}},"additionalProperties":false,"type":"object","required":["file","previous_version"],"title":"ReplaceFileResult"},"ReplaceWorkspaceSharesRequest":{"properties":{"user_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"User Ids","description":"Complete set of console users who should have explicit access; send an empty list to remove every share."}},"additionalProperties":false,"type":"object","title":"ReplaceWorkspaceSharesRequest","description":"The complete explicit share set that should remain after this request."},"RepresentationState":{"properties":{"organized_files":{"type":"boolean","title":"Organized Files","default":false},"search_index":{"type":"boolean","title":"Search Index","default":false},"knowledge_graph":{"type":"boolean","title":"Knowledge Graph","default":false}},"additionalProperties":false,"type":"object","title":"RepresentationState","description":"Whether each representation is current for a file.\n\nAnswers \"is this file actually searchable right now\", which\n``ingestion_status`` alone cannot: a file can be ingested while its graph\ngeneration is still building."},"ResultState":{"type":"string","enum":["available","expired","not_retained","cancelled","storage_unavailable"],"title":"ResultState","description":"Why ``Job.result`` is null.\n\n``available`` with a null result means the job has not succeeded yet;\n``expired`` means its content was removed; ``not_retained`` means the client is\nprovisioned ``zero_retention`` and already had its one chance to read it;\n``cancelled`` means the job, or the root job it ran for, was cancelled. A\ncancelled job serves no results (it is not charged, including delivered parts) — not its\nown progressive values, and not a delegated child's result. It is a read\nstate only, derived on the wire; no row stores it.\n``storage_unavailable`` withholds a retained result while its workspace binding\nrefuses access; ``Job.result_error`` explains the current refusal.\nA late poll returns the job with a state, never a 404 — \"this expired\" and\n\"this never existed\" are a scheduling problem and a bug respectively, and a\n404 makes them identical."},"RoleSourceWire":{"properties":{"table":{"type":"string","title":"Table","description":"Physical table owning the role."},"column":{"type":"string","title":"Column","description":"Column on the owning table."},"evidence":{"type":"string","title":"Evidence","description":"Binding slot, source profile, exact alias, or sole typed date."}},"additionalProperties":false,"type":"object","required":["table","column","evidence"],"title":"RoleSourceWire","description":"Physical ownership, independent of the line/header grain convention."},"RowRange":{"properties":{"kind":{"type":"string","const":"row_range","title":"Kind","default":"row_range"},"start_row":{"type":"integer","minimum":0.0,"title":"Start Row"},"end_row":{"type":"integer","minimum":0.0,"title":"End Row"},"column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column"}},"additionalProperties":false,"type":"object","required":["start_row","end_row"],"title":"RowRange","description":"A 0-based inclusive row run on a parquet table."},"RowRangeMatch":{"properties":{"match_type":{"type":"string","const":"row_range","title":"Match Type","default":"row_range"},"start_row":{"type":"integer","title":"Start Row"},"end_row":{"type":"integer","title":"End Row"},"column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["start_row","end_row"],"title":"RowRangeMatch"},"RowRangeQueryRegion":{"properties":{"kind":{"type":"string","const":"row_range","title":"Kind","default":"row_range"},"region_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Region Id","description":"Opaque identity for paging this exact region when a receipt has several regions on one file."},"source_path":{"type":"string","title":"Source Path","description":"Uploaded file path this region belongs to."},"start_row":{"type":"integer","title":"Start Row","description":"First row of the run, 0-based and inclusive."},"end_row":{"type":"integer","title":"End Row","description":"Last row of the run, 0-based and inclusive."},"columns":{"items":{"type":"string"},"type":"array","title":"Columns","description":"Cited column names, in table order."},"filter_columns":{"items":{"type":"string"},"type":"array","title":"Filter Columns","description":"Columns the verified claim filtered on to select these rows, minus any already in columns. Empty on legacy payloads."},"read_columns":{"items":{"type":"string"},"type":"array","title":"Read Columns","description":"Columns the query read from this table (output lineage), minus any already in columns or filter_columns. Populated on a 'provenance'-basis region only; empty otherwise and on legacy payloads."},"matched_rows":{"type":"integer","title":"Matched Rows","description":"How many source rows the region covers.","default":0},"bounding":{"type":"boolean","title":"Bounding","description":"True when this is a bounding range over a large match set rather than exact runs.","default":false},"derivative_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Derivative Path","description":"Pageable derivative (parquet or jsonl) when it is not the uploaded source itself."},"runs":{"items":{"$ref":"#/components/schemas/ArtifactRowRun"},"type":"array","title":"Runs","description":"Exact matched-row runs inside the span, so a bounding range stays pageable as matches only. May cover fewer than matched_rows when the verifier truncated its run list; empty on legacy payloads."},"runs_truncated":{"type":"boolean","title":"Runs Truncated","description":"True when runs is an exact ordered prefix of matched islands and more matched rows exist. Later pages require guarded replay; false when the runs are complete or on legacy payloads.","default":false},"runs_replayable":{"type":"boolean","title":"Runs Replayable","description":"True only when grounding-rows can reconstruct this exact region predicate for pages beyond runs. Regions without a safe replay fail closed instead of returning broader rows.","default":false},"basis":{"type":"string","enum":["verified","inputs","provenance"],"title":"Basis","description":"How this region was established. 'verified': a claim whose cited value was mechanically re-computed from exactly these rows. 'inputs': one table's contribution to a derived (multi-table) figure — the rows were verified to match the claim's filters, but the figure itself is not re-computable from this table alone. 'provenance': no claim covered this query, so the region records what the query's captured provenance proved it read — never a whole-table guess. Absent on legacy payloads, which are all 'verified'.","default":"verified"},"scan_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scan Index","description":"Which scan of the query read these rows, when the region records one scan rather than the whole table. A query can read one file more than once — a narrow CTE and a broad one, say — and each such scan grounds separately, so this identifies the scan to replay for further row pages. Absent on a whole-table span, on verified regions, and on legacy payloads."},"scan_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scan Label","description":"The scan named the way the query spells it: 'main query', 'CTE <name>', or 'subquery <n>'. Present exactly when scan_index is."}},"additionalProperties":false,"type":"object","required":["source_path","start_row","end_row"],"title":"RowRangeQueryRegion","description":"A verified region on a pageable tabular artifact, addressed by row number.\n\nA parquet upload stored as-is uses its own row order. A jsonl or parquet\nderivative uses the queried artifact's row order; ``derivative_path`` names\nthat artifact when it differs from the caller-facing ``source_path``."},"RunSqlRequest":{"properties":{"sql":{"type":"string","maxLength":4096,"minLength":1,"title":"Sql","description":"One read-only SELECT (DuckDB dialect) over the registered tables and earlier `res_…` handles."}},"additionalProperties":false,"type":"object","required":["sql"],"title":"RunSqlRequest","description":"One read-only SELECT over the workspace's queryable tables.\n\nTable names come from metadata — ``file-metadata`` publishes each\nqueryable tab's ``table_name`` and ``folder-metadata``'s table census\nlists them all — and from earlier run-sql results (every response's\n``res_…`` handle is a registered table on the next call, so results can\nbe joined, aggregated, or paged with LIMIT/OFFSET). Joins across files\nare ordinary SQL joins. A statement that is not a read, or that reads an\nunregistered table, is refused with ``invalid_request`` naming the rule\nand the registered tables."},"RunSqlResponse":{"properties":{"sql":{"type":"string","title":"Sql","description":"The normalized statement that ran — the result's provenance."},"duplicate":{"type":"boolean","title":"Duplicate","default":false},"result":{"$ref":"#/components/schemas/QueryTablePreview"},"source_paths":{"items":{"type":"string"},"type":"array","title":"Source Paths","description":"The uploaded files the statement read — carried on the response itself so source attribution survives when no result file is materialized (job-attributed agent statements)."},"result_citation":{"anyOf":[{"$ref":"#/components/schemas/QueryTableCitation"},{"type":"null"}]},"result_materialization_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Materialization Error"},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["sql","result"],"title":"RunSqlResponse","description":"One executed statement: shape, bounded preview, and the retained result.\n\nThe stored result is complete whatever the preview shows;\n``result_citation.result_file.download_url`` fetches the whole parquet.\n``duplicate`` marks a statement answered from an earlier identical run's\nstored result — free, and safe to build on."},"RunSqlResult":{"properties":{"result_type":{"type":"string","const":"run_sql","title":"Result Type","default":"run_sql"},"output":{"$ref":"#/components/schemas/RunSqlResponse","description":"The operation response returned to the caller, retained with its job."}},"additionalProperties":false,"type":"object","required":["output"],"title":"RunSqlResult"},"RunViewItem":{"properties":{"run_key":{"type":"string","format":"uuid","title":"Run Key","description":"project_id when present, otherwise the job id."},"viewed":{"type":"boolean","title":"Viewed"},"terminal":{"type":"boolean","title":"Terminal","description":"True when every live job in the run has finished (succeeded, failed, or cancelled)."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"The job kind this run reads as, so a console can route it to the surface that announces it. Null once the run's jobs are no longer readable."}},"type":"object","required":["run_key","viewed","terminal"],"title":"RunViewItem"},"RunViewListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RunViewItem"},"type":"array","title":"Items"},"unread_count":{"type":"integer","title":"Unread Count","description":"Watched runs that have finished and this user has not opened."}},"type":"object","required":["items","unread_count"],"title":"RunViewListResponse"},"SchemaError":{"properties":{"path":{"type":"string","title":"Path","description":"JSON Pointer of the schema node that failed validation."},"message":{"type":"string","title":"Message","description":"Why this node is not accepted as an extract schema."}},"additionalProperties":false,"type":"object","required":["path","message"],"title":"SchemaError","description":"One violation from ``POST /v1/extract/schema-validation``."},"ScoreAnswer":{"properties":{"type":{"type":"string","const":"score","title":"Type","default":"score"},"score":{"type":"number","title":"Score","description":"Expected position on the scale, from 0 (the first level) to the last level's index."},"legend":{"items":{"type":"string"},"type":"array","title":"Legend","description":"The scale's levels in order, lowest first, as the question named them."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Each level's probability, keyed by its index in the legend."},"confidence":{"type":"number","title":"Confidence","description":"The decision model's average confidence in this answer, from 0 to 1. Lower means it was less sure; it is not the probability of any one level."}},"additionalProperties":false,"type":"object","required":["score","legend","probabilities","confidence"],"title":"ScoreAnswer"},"ScoreQuestion":{"properties":{"type":{"type":"string","const":"score","title":"Type"},"instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instructions","description":"The question that the scale answers."},"criteria":{"items":{"type":"string"},"type":"array","maxItems":255,"minItems":1,"title":"Criteria","description":"The ordered levels of the scale, lowest first."}},"additionalProperties":false,"type":"object","required":["type","criteria"],"title":"ScoreQuestion","description":"Place the state on an ordered scale. Its answer is a score along the levels."},"ScoredCategory":{"properties":{"category":{"type":"string","title":"Category"},"confidence":{"type":"number","title":"Confidence"}},"additionalProperties":false,"type":"object","required":["category","confidence"],"title":"ScoredCategory"},"SearchEvidence":{"properties":{"source_path":{"type":"string","title":"Source Path","description":"The uploaded file the quote belongs to, e.g. 'reports/policy.pdf'. This is the file to ground the quote against."},"source_file_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Source File Id","description":"The id of the file at source_path, resolved server-side. Always set on newly finalized results; null only on results stored before unresolvable citations were dropped."},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page","description":"1-based page number, when the agent saw one."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"Public component of the file the quote came from — the tab name for a spreadsheet, the section for a split document; the same vocabulary file-metadata lists. Pass it as the ground target's sheet when grounding a spreadsheet quote. None for a single-component file or when attribution was unavailable."},"quote":{"type":"string","title":"Quote","description":"The key passage, as retrieved from the file."},"passages":{"items":{"type":"string"},"type":"array","title":"Passages","description":"Contiguous pieces of the source file that quote was stitched from, in the file's own text. Ground each piece as its own target when this list is present, with max_matches 2. A piece that returns two matches repeats in the file, so which copy the quote used is unknown. A ' | ' marks a table cell boundary added by the check. Replace it with a space before grounding. Filled only for PDF, Word and PowerPoint sources that Ground reads from the PDF text layer. Absent when quote is already one contiguous passage, could not be checked, or could not be verified."},"relevance":{"type":"string","title":"Relevance","description":"Deprecated: empty on new results, where `reasoning` says how the evidences support the answer.","default":""},"queries":{"items":{"$ref":"#/components/schemas/TableQueryGrounding"},"type":"array","title":"Queries","description":"The SQL the run executed over this evidence's table, with a bounded preview of each result — server-recorded from the run's tables engine, never model-authored. Attached whenever the run queried the cited table (or the row extraction of the same spreadsheet tab), so a verbatim quote from a queried sheet carries the computation trail alongside it; empty when the run never queried the cited file's tables."},"derivation":{"anyOf":[{"$ref":"#/components/schemas/DerivationTrace"},{"type":"null"}],"description":"Computation DAG for derived answers; None when the evidence is a direct extraction or the run recorded no dependency edges."}},"additionalProperties":false,"type":"object","required":["source_path","quote"],"title":"SearchEvidence","description":"One piece of evidence the search agent cited, named as the caller's own file.\n\nThe agent retrieves from workspace-internal ingestion derivatives, but those\nare an implementation detail the caller never addresses: every citation is\nresolved server-side, through the caller's access gate, to the uploaded file\nit belongs to (``source_path`` + ``source_file_id``). A citation that cannot be\nresolved to a visible file — hallucinated, deleted mid-run, or access-refused —\nis dropped rather than published under a path the caller cannot use.\n\nNo locator: pinning a quote to a region of the original document is a\nseparate ``ground`` call the caller makes on the file at ``source_path``\n(``source_file_id``). Ground ``quote`` as the target text, or each entry of\n``passages`` as its own target when that list is present. For a quote taken\nfrom a spreadsheet, pass ``component`` as the target's ``sheet``."},"SearchLlmUsage":{"properties":{"requests":{"type":"integer","title":"Requests","description":"Completed LLM requests, tool-internal ones included.","default":0},"input_tokens":{"type":"integer","title":"Input Tokens","description":"Prompt tokens across every request, cached ones included.","default":0},"output_tokens":{"type":"integer","title":"Output Tokens","description":"Completion tokens across every request.","default":0},"cached_input_tokens":{"type":"integer","title":"Cached Input Tokens","description":"The share of input_tokens served from a provider prompt cache — billed at a reduced rate, so it is reported separately rather than subtracted.","default":0},"by_model":{"items":{"$ref":"#/components/schemas/ModelTokenUsage"},"type":"array","title":"By Model","description":"The same spend per model that served it, highest first."}},"additionalProperties":false,"type":"object","title":"SearchLlmUsage","description":"What answering one search query cost in LLM work.\n\nPresent only when the run was asked to account for itself *and* spend reached its\nledger; ``null`` otherwise, so a caller can tell \"nothing was measured\" from\n\"nothing was spent\". An empty ledger publishes ``null`` rather than a zeroed\nobject for that reason: zeros would claim a measured run cost nothing, when what\nan empty ledger most likely records is accounting that never landed.\n\nThe totals cover recorded model calls at any depth: the agent's own\nturns, and the calls the retrieval tools made on its behalf — a document read by\nthe recursive-LLM engine, a scan cracked by the vision engine, a tables question\nanswered by the SQL agent. That is the number a per-query cost figure needs, and it\nis invariably several times the agent's own turn count.\n\n``by_model`` is the same spend split by the model that served it, because a run\nlegitimately spends on several at different prices — a total alone cannot be turned\ninto money. The totals are the sum of ``by_model`` and are published anyway so the\ncommon case needs no arithmetic.\n\nObserved retries are included. These public token totals are not a complete cost\ncertificate: provider omissions and failed persistence can leave gaps. Internal\ncoverage and non-token counters stay in the ledger and are not added to this wire\nshape without a separate SDK contract update."},"SearchResponse":{"properties":{"hits":{"items":{"$ref":"#/components/schemas/Evidence"},"type":"array","title":"Hits"},"candidates_seen":{"type":"integer","title":"Candidates Seen"},"truncated":{"type":"boolean","title":"Truncated"},"coverage":{"$ref":"#/components/schemas/Coverage"},"job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Job Id","description":"The external operation job; absent for commands inside a search job."}},"additionalProperties":false,"type":"object","required":["hits","candidates_seen","truncated","coverage"],"title":"SearchResponse","description":"Response of ``hybrid-search``.\n\n``candidates_seen`` is the pre-access-filter count so the caller can tell\nwhen truncation happened upstream of the access gate.\n\nEvery ``hits[].path`` is an uploaded **source** path. Each hit also carries the\ningestion derivative it was actually read from, but those fields are internal\nto the host (the agent tools address files that way) and are excluded from this\nbody — a ``/v1`` caller only ever sees the files it uploaded."},"SetGrantsRequest":{"properties":{"labels":{"items":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"type":"array","maxItems":16,"title":"Labels"}},"type":"object","title":"SetGrantsRequest","description":"The complete set of access labels this key may see in one workspace.\n\nReplaces the whole grant, so revoking a label is the same operation as\ngranting one. An empty list leaves the key seeing only unlabelled documents."},"SetKeyDisabledRequest":{"properties":{"disabled":{"type":"boolean","title":"Disabled","description":"True to suspend the key, false to let it authenticate again."}},"type":"object","required":["disabled"],"title":"SetKeyDisabledRequest","description":"Suspend or resume a key.\n\nSeparate from revocation because it is reversible: an integration that has\nstarted misbehaving can be cut off now and switched back on once it is\nfixed, without re-keying every caller."},"SetKeyLabelsRequest":{"properties":{"labels":{"items":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$"},"type":"array","maxItems":16,"title":"Labels"}},"type":"object","title":"SetKeyLabelsRequest","description":"Labels this key should hold across every labelled workspace.\n\nEach workspace grant becomes the intersection of this list and that\nworkspace's declared labels. Empty means the key sees only unlabelled\ndocuments in every labelled workspace."},"SetKeyLabelsResponse":{"properties":{"key_prefix":{"type":"string","title":"Key Prefix"},"grants":{"items":{"$ref":"#/components/schemas/KeyGrantSummary"},"type":"array","title":"Grants"}},"type":"object","required":["key_prefix","grants"],"title":"SetKeyLabelsResponse"},"SetRoleRequest":{"properties":{"role":{"type":"string","enum":["owner","admin","member"],"title":"Role"}},"type":"object","required":["role"],"title":"SetRoleRequest"},"SharedColumn":{"properties":{"name":{"type":"string","title":"Name"},"table_count":{"type":"integer","title":"Table Count","description":"How many census tables carry the column — may exceed len(appears_in)."},"appears_in":{"items":{"$ref":"#/components/schemas/SharedColumnOccurrence"},"type":"array","title":"Appears In"}},"additionalProperties":false,"type":"object","required":["name","table_count","appears_in"],"title":"SharedColumn","description":"A column name appearing in several tables — an UNVERIFIED join candidate.\n\nSame name and compatible stats SUGGEST a relation (equal distinct counts, a\ncontained value range); they do not prove one. Verify with one\n``query-tables`` join before relying on it."},"SharedColumnOccurrence":{"properties":{"path":{"type":"string","title":"Path"},"component":{"type":"string","title":"Component"},"data_type":{"type":"string","title":"Data Type"},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count"},"distinct_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Distinct Count","description":"Approximate; compare to row_count for key-likeness."},"min_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Value","description":"Rendered and clipped; a format exemplar for id columns."},"max_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Max Value"}},"additionalProperties":false,"type":"object","required":["path","component","data_type"],"title":"SharedColumnOccurrence","description":"One table carrying a shared column, with the stats its profile recorded."},"SheetQueryRegion":{"properties":{"kind":{"type":"string","const":"sheet","title":"Kind","default":"sheet"},"source_path":{"type":"string","title":"Source Path","description":"Uploaded file path this region points at."},"sheet_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet Name","description":"Workbook tab, when applicable."},"a1_range":{"type":"string","title":"A1 Range","description":"A1 range on the original sheet, e.g. 'B12:D15'."},"matched_rows":{"type":"integer","title":"Matched Rows","description":"How many source rows the region covers.","default":0},"bounding":{"type":"boolean","title":"Bounding","description":"True when this is a bounding box over a large match set rather than exact runs.","default":false},"basis":{"type":"string","enum":["verified","inputs","provenance"],"title":"Basis","description":"How this region was established. 'verified': a claim whose cited value was mechanically re-computed from exactly these rows. 'inputs': one table's contribution to a derived (multi-table) figure — the rows were verified to match the claim's filters, but the figure itself is not re-computable from this table alone. 'provenance': no claim covered this query, so the region records what the query's captured provenance proved it read — never a whole-table guess. Absent on legacy payloads, which are all 'verified'.","default":"verified"},"scan_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scan Index","description":"Which scan of the query read these rows, when the region records one scan rather than the whole table. A query can read one file more than once — a narrow CTE and a broad one, say — and each such scan grounds separately, so this identifies the scan to replay for further row pages. Absent on a whole-table span, on verified regions, and on legacy payloads."},"scan_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scan Label","description":"The scan named the way the query spells it: 'main query', 'CTE <name>', or 'subquery <n>'. Present exactly when scan_index is."}},"additionalProperties":false,"type":"object","required":["source_path","a1_range"],"title":"SheetQueryRegion","description":"A verified region on a source file with an addressable grid.\n\nCoordinates are expressed in the caller's uploaded workbook or CSV, never\nin the internal parquet derivative."},"SheetRange":{"properties":{"kind":{"type":"string","const":"sheet_range","title":"Kind","default":"sheet_range"},"sheet":{"type":"string","title":"Sheet","description":"Workbook tab name this range belongs to."},"a1_range":{"type":"string","title":"A1 Range","description":"A1 cell range on that sheet, for example B12:D15."}},"additionalProperties":false,"type":"object","required":["sheet","a1_range"],"title":"SheetRange","description":"A cell range on a spreadsheet sheet."},"SignedAmount":{"properties":{"kind":{"type":"string","const":"signed","title":"Kind","description":"One signed amount column."},"column":{"type":"string","minLength":1,"title":"Column","description":"Signed amount column on every primary member."}},"additionalProperties":false,"type":"object","required":["kind","column"],"title":"SignedAmount"},"SkippedCheckWire":{"properties":{"check":{"type":"string","title":"Check","description":"Which question of the integrity battery went unanswered, by its check id."},"reason":{"type":"string","title":"Reason","description":"Which role was missing, or the error the statement returned."}},"additionalProperties":false,"type":"object","required":["check","reason"],"title":"SkippedCheckWire","description":"One check the battery could not run, and why."},"SourceIncompleteDisclosure":{"properties":{"code":{"type":"string","const":"source_incomplete","title":"Code"},"received_bytes":{"type":"integer","minimum":1.0,"title":"Received Bytes","description":"Size of the file as received, whose final record ended before the record did."}},"additionalProperties":false,"type":"object","required":["code","received_bytes"],"title":"SourceIncompleteDisclosure","description":"The source file ended mid-document, so the result covers only the part that arrived.\n\nThe job succeeded on the bytes that were present, and a lane that can read a\npartial file still returns everything it could read. Without this disclosure\nthat output is indistinguishable from a complete document, which is the\ndangerous reading: a short result looks like a short source.\n\nNo original size is published because an incomplete file carries no record of\nhow long it should have been. ``received_bytes`` is what a caller can compare\nagainst the size it believes it sent."},"SplitArtifact":{"properties":{"url":{"type":"string","title":"Url","description":"Authenticated URL of a materialized file for this segment."}},"additionalProperties":false,"type":"object","required":["url"],"title":"SplitArtifact"},"SplitCategory":{"properties":{"id":{"type":"string","title":"Id"},"label":{"type":"string","title":"Label"},"description":{"type":"string","title":"Description","default":""},"subclasses":{"items":{"$ref":"#/components/schemas/SplitSubclass"},"type":"array","title":"Subclasses"},"instance_key":{"anyOf":[{"$ref":"#/components/schemas/SplitInstanceKey"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["id","label"],"title":"SplitCategory"},"SplitConfidence":{"properties":{"band":{"type":"string","enum":["unavailable","low","medium","high"],"title":"Band","description":"Coarse confidence band for this split decision.","default":"unavailable"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score","description":"Numeric score when the runtime produced one. Null otherwise."}},"additionalProperties":false,"type":"object","title":"SplitConfidence"},"SplitInstance":{"properties":{"key":{"type":"string","title":"Key","description":"Instance-key name from the request class, when instance splitting ran."},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value","description":"Extracted instance-key value for this segment."}},"additionalProperties":false,"type":"object","required":["key"],"title":"SplitInstance"},"SplitInstanceKey":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"required":{"type":"boolean","title":"Required","default":false}},"additionalProperties":false,"type":"object","required":["name","description"],"title":"SplitInstanceKey"},"SplitJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"split","title":"Kind","default":"split"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/SplitResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"SplitJob"},"SplitOutputOptions":{"properties":{"include_content":{"type":"boolean","title":"Include Content","description":"When true, each segment includes its extracted markdown in content.","default":false},"materialize_files":{"type":"boolean","title":"Materialize Files","description":"When true, each document segment includes a downloadable artifact URL. Spreadsheet segments always include a single-sheet XLSX URL, even when this is false.","default":false}},"additionalProperties":false,"type":"object","title":"SplitOutputOptions"},"SplitRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The packet to split: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"classes":{"items":{"$ref":"#/components/schemas/SplitCategory"},"type":"array","minItems":1,"title":"Classes","description":"Document classes to split the packet into; spreadsheets classify worksheets against these classes."},"unknown_policy":{"type":"string","enum":["include","force","error"],"title":"Unknown Policy","description":"What to do with pages that match no class. include keeps them as unclassified; force assigns the best class; error fails the job.","default":"include"},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to consider. Omit to use the whole document."},"overlap_policy":{"type":"string","enum":["exclusive","shared_boundary_page"],"title":"Overlap Policy","description":"Whether a boundary page may belong to two adjacent segments or only one.","default":"exclusive"},"quality":{"type":"string","enum":["auto","fast","accurate"],"title":"Quality","description":"Latency versus accuracy preference for this run. Only auto is accepted today.","default":"auto"},"split_rules":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Split Rules","description":"Optional free-text guidance for how to cut the packet (for example, split on cover sheets)."},"output":{"$ref":"#/components/schemas/SplitOutputOptions","description":"Whether segments include markdown content and/or materialized file URLs."}},"additionalProperties":false,"type":"object","required":["source","classes"],"title":"SplitRequest","description":"Canonical schema for packet splitting.\n\nDocuments split into logical page-range segments. Spreadsheets split\ndeterministically into one materialized XLSX artifact per worksheet and\nclassify each worksheet against ``classes``."},"SplitRequestEcho":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name","description":"Optional display name. Public Parse, Split, Classify, Extract, and Ground runs use a stable server default when blank. The console calls a named run a 'project'."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id; jobs submitted together share it. Not a server-side resource."},"output_workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Output Workspace Id","description":"Workspace for retained result artifacts. Defaults to the unique source workspace, or a reused Parse's output workspace. Required for ambiguous destinations involving customer storage. Does not change source access."},"corpus_sources":{"items":{"$ref":"#/components/schemas/WorkspaceFileSource"},"type":"array","maxItems":50,"title":"Corpus Sources","description":"Workspace files visible in the run tray, including files not submitted by this request."},"parse_mode":{"type":"string","enum":["low","medium","high"],"title":"Parse Mode","description":"How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.","default":"low"},"parse":{"anyOf":[{"$ref":"#/components/schemas/ParseSettings"},{"type":"null"}],"description":"Settings for the Parse that runs before this operation, using the same fields as Parse. Omit to use the default Parse. parse.parse_mode and the top-level parse_mode must agree when both are set, and so must parse.page_ranges and page_ranges. A setting that does not apply is reported in warnings."},"source":{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"title":"Source","description":"The packet to split: a fresh upload, an HTTPS URL, a workspace file, or a prior parse job.","discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},"classes":{"items":{"$ref":"#/components/schemas/SplitCategory"},"type":"array","minItems":1,"title":"Classes","description":"Document classes to split the packet into; spreadsheets classify worksheets against these classes."},"unknown_policy":{"type":"string","enum":["include","force","error"],"title":"Unknown Policy","description":"What to do with pages that match no class. include keeps them as unclassified; force assigns the best class; error fails the job.","default":"include"},"page_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageRange"},"type":"array","maxItems":200},{"type":"null"}],"title":"Page Ranges","description":"One-based inclusive page ranges to consider. Omit to use the whole document."},"overlap_policy":{"type":"string","enum":["exclusive","shared_boundary_page"],"title":"Overlap Policy","description":"Whether a boundary page may belong to two adjacent segments or only one.","default":"exclusive"},"quality":{"type":"string","enum":["auto","fast","accurate"],"title":"Quality","description":"Latency versus accuracy preference for this run. Only auto is accepted today.","default":"auto"},"split_rules":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Split Rules","description":"Optional free-text guidance for how to cut the packet (for example, split on cover sheets)."},"output":{"$ref":"#/components/schemas/SplitOutputOptions","description":"Whether segments include markdown content and/or materialized file URLs."},"request_type":{"type":"string","const":"split","title":"Request Type","default":"split"}},"additionalProperties":false,"type":"object","required":["source","classes"],"title":"SplitRequestEcho","description":"A stored ``split`` request, read back."},"SplitResult":{"properties":{"result_type":{"type":"string","const":"split","title":"Result Type","default":"split"},"file_name":{"type":"string","title":"File Name","description":"Source filename recorded for this run."},"lane":{"type":"string","title":"Lane","description":"Which parser lane produced this payload, for example document or spreadsheet."},"page_count":{"type":"integer","title":"Page Count","description":"Pages considered while splitting."},"segments":{"items":{"$ref":"#/components/schemas/SplitSegment"},"type":"array","title":"Segments","description":"Ordered packet segments, including unclassified ones when allowed."},"units":{"type":"integer","title":"Units","description":"Measured work units for this split. The job's `credits` is the final billed amount."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Parse settings this run accepted but did not apply, each naming the setting and why, for example a page selection on a file with no pages. Left out when empty."}},"additionalProperties":false,"type":"object","required":["file_name","lane","page_count","segments","units"],"title":"SplitResult"},"SplitSegment":{"properties":{"id":{"type":"string","title":"Id","description":"Stable id of this cut within the split result."},"sequence":{"type":"integer","minimum":0.0,"title":"Sequence","description":"0-based order of this segment in the packet."},"status":{"type":"string","enum":["matched","unclassified"],"title":"Status","description":"Whether this cut was assigned a class. matched has class (Python SDK: split_class); unclassified was kept because unknown_policy is include."},"class":{"anyOf":[{"$ref":"#/components/schemas/SplitSegmentCategory"},{"type":"null"}],"description":"The winning request class for a matched segment. Null when unclassified. JSON name is class; the Python SDK attribute is split_class."},"classes":{"anyOf":[{"items":{"$ref":"#/components/schemas/SplitSegmentCategory"},"type":"array"},{"type":"null"}],"title":"Classes","description":"Alternate class assignments when more than one class applied."},"start_page":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Start Page","description":"Inclusive first page of this cut. For workbooks, equals sheet_index + 1."},"end_page":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"End Page","description":"Inclusive last page of this cut. For workbooks, equals start_page."},"sheet_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet Name","description":"Workbook tab for a spreadsheet segment. Null for PDFs."},"json_pointer":{"anyOf":[{"type":"string","pattern":"^(?:$|/)"},{"type":"null"}],"title":"Json Pointer","description":"JSON Pointer into a structured source when the cut is not a page range."},"instance":{"anyOf":[{"$ref":"#/components/schemas/SplitInstance"},{"type":"null"}],"description":"Instance-key value when the request class asked for instance splitting."},"classification_confidence":{"$ref":"#/components/schemas/SplitConfidence","description":"How confident the assigned class is for this segment."},"boundary_confidence":{"$ref":"#/components/schemas/SplitConfidence","description":"How confident the start and end page cut is."},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Segment markdown when output.include_content is true. Null otherwise."},"artifacts":{"items":{"$ref":"#/components/schemas/SplitArtifact"},"type":"array","title":"Artifacts","description":"Downloadable files when output.materialize_files is true. Spreadsheet segments always include a single-sheet XLSX URL even when that flag is false."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Non-fatal notes about this segment, such as a forced class assignment."}},"additionalProperties":false,"type":"object","required":["id","sequence","status"],"title":"SplitSegment"},"SplitSegmentCategory":{"properties":{"id":{"type":"string","title":"Id","description":"Stable id of the class this segment was assigned."},"label":{"type":"string","title":"Label","description":"Display name of the assigned class."},"description":{"type":"string","title":"Description","description":"Caller-supplied description of what belongs in this class.","default":""},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id","description":"Parent class id when this assignment is a subclass."},"subcategory_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subcategory Id","description":"Subclass id when the segment matched a nested class."}},"additionalProperties":false,"type":"object","required":["id","label"],"title":"SplitSegmentCategory"},"SplitSubclass":{"properties":{"id":{"type":"string","title":"Id"},"label":{"type":"string","title":"Label"},"description":{"type":"string","title":"Description","default":""}},"additionalProperties":false,"type":"object","required":["id","label"],"title":"SplitSubclass"},"SpreadsheetRange":{"properties":{"kind":{"type":"string","const":"spreadsheet_range","title":"Kind","default":"spreadsheet_range"},"sheet":{"type":"string","title":"Sheet"},"a1_range":{"type":"string","title":"A1 Range"}},"additionalProperties":false,"type":"object","required":["sheet","a1_range"],"title":"SpreadsheetRange"},"SpreadsheetRangeMatch":{"properties":{"match_type":{"type":"string","const":"spreadsheet_range","title":"Match Type","default":"spreadsheet_range"},"sheet_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sheet Name"},"cell_range":{"type":"string","title":"Cell Range"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["cell_range"],"title":"SpreadsheetRangeMatch"},"SqlReceipt":{"properties":{"result_id":{"type":"string","title":"Result Id","description":"Stable per-run identity of this statement, in execution order (e.g. 'sql_3')."},"sql":{"type":"string","title":"Sql","description":"The statement as executed, verbatim."},"handle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Handle","description":"Content-addressed key of this statement's stored result, derived from the statement text. Server-side identity: it is what lets the run's own publication find the stored result and its capture-time provenance, and it is NOT an address an agent may query or chain from — `result_id` is the identity the caller and the row pager use. Null on a run that stored no result for the statement. A `cat_` handle names an exploratory document-catalog query: it stores no result beyond the rows carried here."},"table_bindings":{"items":{"$ref":"#/components/schemas/SqlTableBinding"},"type":"array","title":"Table Bindings","description":"The tables this statement registered, each with the view name it was referenced by."},"replay":{"anyOf":[{"$ref":"#/components/schemas/SqlReplayReceipt"},{"type":"null"}],"description":"Independent recomputation metadata for this statement; null on legacy results."},"columns":{"items":{"type":"string"},"type":"array","title":"Columns","description":"Result column names, in result order."},"rows":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Rows","description":"Result rows, values rendered as text so a decimal, a date and a NULL all survive the wire."},"row_count":{"type":"integer","title":"Row Count","description":"Rows carried below — not the statement's unbounded result size.","default":0},"result_row_count":{"type":"integer","title":"Result Row Count","description":"Rows in the statement's complete stored result. Equal to `row_count` when nothing was cut; the number a total or an exception count must be read from when `truncated` is set.","default":0},"truncated":{"type":"boolean","title":"Truncated","description":"Whether rows past the stored cap were cut from this receipt.","default":false},"grounding_status":{"anyOf":[{"type":"string","enum":["exact","unavailable","zero_result"]},{"type":"null"}],"title":"Grounding Status","description":"Whether this statement's stored result already carried proof of which source rows it read when the receipt was recorded. 'exact' means it did; 'unavailable' means the proof could not be read; 'zero_result' means there were no rows to ground. Null when nothing had been captured yet — the ordinary case for a lane that captures at publication time, so this is a record of what execution happened to know and NOT a prediction of whether the receipt can be grounded. What was actually proven is published as `grounding_status` on the matching evidence query, beside the `regions` it earned."},"views_used":{"items":{"type":"string"},"type":"array","title":"Views Used","description":"Session views registered when this statement ran, in definition order — the registry snapshot it executed under. A statement naming a view is replayable only against these, which is what makes named views admissible where chaining a previous call's result handle is not."},"saved_as":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Saved As","description":"The session view this statement was registered as, when it was. Every name in another receipt's ``views_used`` appears here on exactly one receipt, so the run's receipts define every view they cite."},"view_sql":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"View Sql","description":"The definition registered under `saved_as`, when it is not this statement itself. Null on an ordinary `save_as`, where `sql` IS the definition. Set by `build_journal_view`, which registers the per-journal frame and runs a bounded probe over it rather than materializing the whole frame — so the definition every later `views_used` refers to is still published by exactly one receipt."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Pre-execution lint notes attached to this statement — non-blocking, and published as part of its working."},"executor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executor","description":"The named executor that generated this statement (`reconcile_movement`, `test_timing`, `find_duplicates`, `field_completeness`, `journal_balance`), when one did, `custom_sql` for a statement the fixed-pipeline engine authored under its escape, or `ledger_understanding` for the ledger-understanding census's own statement, which ran before this run and is cited rather than re-run. Null when no named generator produced it — a population count, an absence probe, or SQL the agent wrote itself. Both engines use the same words here."},"parameters":{"additionalProperties":{"type":"string"},"type":"object","title":"Parameters","description":"The executor's resolved call, flattened to text — the clock and its true grain, the window's day offsets, the signature, the tolerance, the population. Empty on a statement no executor generated. This is what makes a figure trace to a named, parameterized computation rather than to SQL alone."}},"additionalProperties":false,"type":"object","required":["result_id","sql"],"title":"SqlReceipt","description":"One SQL statement a journal-entry-testing run executed, with its result.\n\nThe audit trail of a JET answer: every headline figure is meant to be\nreadable out of one of these. Unlike\n:class:`TableQueryGrounding` — whose SQL is written by a sub-agent and\npublished as supporting detail — the statement here is the deliverable's\nown working, so it is published whole rather than digested.\n\n``rows`` is bounded (``JET_RECEIPT_MAX_ROWS``) and ``truncated`` says\nwhether the bound cut anything, so an \"every exception is listed\" reading\nis never made from a silently capped table. ``result_row_count`` is the\nfigure that reading actually needs: the statement's whole result is stored,\nand this is its size, whatever the bound carried below."},"SqlReplayReceipt":{"properties":{"schema_version":{"type":"integer","const":1,"title":"Schema Version","default":1},"kind":{"type":"string","enum":["aggregate","rowset"],"title":"Kind","description":"The verification lane appropriate for this statement."},"engine":{"type":"string","const":"duckdb","title":"Engine","description":"The query engine that executed the statement."},"engine_version":{"type":"string","title":"Engine Version","description":"The query-engine version that executed the statement."},"engine_threads":{"type":"integer","exclusiveMinimum":0.0,"title":"Engine Threads","description":"DuckDB thread count used for this execution."},"normalized_sql":{"type":"string","title":"Normalized Sql","description":"The normalized single SELECT statement to execute during independent replay."},"sql_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Sql Sha256","description":"SHA-256 identity of the normalized statement."},"logical_plan_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Logical Plan Sha256","description":"SHA-256 identity of the parser tree after source-position fields are removed."},"catalog_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Catalog Sha256","description":"SHA-256 identity of the ordered source bindings used by this statement."},"result_artifact_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Result Artifact Sha256","description":"SHA-256 identity of the complete retained result Parquet produced by the service."},"result_data_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Result Data Sha256","description":"SHA-256 identity of the complete typed result rows."},"result_digest_version":{"type":"string","title":"Result Digest Version","description":"Versioned Arrow serialization scheme used for the typed-result identity."},"result_dependencies":{"items":{"type":"string"},"type":"array","title":"Result Dependencies","description":"Earlier retained result handles read by this statement, in deterministic order."}},"additionalProperties":false,"type":"object","required":["kind","engine","engine_version","engine_threads","normalized_sql","sql_sha256","logical_plan_sha256","catalog_sha256","result_artifact_sha256","result_data_sha256","result_digest_version"],"title":"SqlReplayReceipt","description":"Immutable inputs and engine identity for independent result recomputation."},"SqlTableBinding":{"properties":{"path":{"type":"string","title":"Path","description":"The uploaded table file this view read, e.g. 'ledger/journal.xlsx'."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"The source worksheet, including when selected alone. Null for a direct upload or a historical unnamed tab."},"table_name":{"type":"string","title":"Table Name","description":"The view name the SQL referenced this table by, for THIS run."},"source_sha256":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"title":"Source Sha256","description":"SHA-256 identity of the ingested source generation behind this table binding."}},"additionalProperties":false,"type":"object","required":["path","table_name"],"title":"SqlTableBinding","description":"One table a receipted statement registered, in both namespaces at once.\n\n``path`` (plus ``component`` for one tab of a workbook) is the caller's own\nuploaded file; ``table_name`` is the view name the statement referenced it\nby. Both halves are load-bearing: view names are settled per run, so SQL\nthat hardcodes one is only replayable alongside the mapping that produced\nit — a statement published without its bindings cannot be re-run."},"StatusCounts":{"properties":{"pending":{"type":"integer","title":"Pending","description":"Rows inserted but workflow not yet running.","default":0},"running":{"type":"integer","title":"Running","description":"Rows the worker has claimed but not finalised.","default":0},"succeeded":{"type":"integer","title":"Succeeded","description":"Terminal — workflow finished cleanly.","default":0},"failed":{"type":"integer","title":"Failed","description":"Terminal — workflow surfaced a typed error.","default":0}},"additionalProperties":false,"type":"object","title":"StatusCounts","description":"Row counts for ``api_requests`` grouped by terminal/non-terminal state."},"StorageConnectionValidationResult":{"properties":{"result_type":{"type":"string","const":"storage_connection_validate","title":"Result Type","default":"storage_connection_validate"},"connection_id":{"type":"string","format":"uuid","title":"Connection Id","description":"Connection whose API and worker access was validated."},"credential_generation":{"type":"integer","title":"Credential Generation","description":"Credential generation activated by this validation."}},"additionalProperties":false,"type":"object","required":["connection_id","credential_generation"],"title":"StorageConnectionValidationResult"},"StructureProposal":{"properties":{"journal_key":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Journal Key","description":"Ordered identity to measure, not an accepted key."},"amount":{"oneOf":[{"$ref":"#/components/schemas/PairedAmount"},{"$ref":"#/components/schemas/SignedAmount"}],"title":"Amount","description":"Amount basis to measure over the whole primary.","discriminator":{"propertyName":"kind","mapping":{"paired":"#/components/schemas/PairedAmount","signed":"#/components/schemas/SignedAmount"}}},"account":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}],"minLength":1,"title":"Account","description":"Line-owned account column or ordered composite account identity."},"effective_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Date","description":"Optional line-owned effective date column."},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period","description":"Optional period column; does not interpret its values."},"line_ordinal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line Ordinal","description":"Optional ordinal whose uniqueness is checked within each journal."}},"additionalProperties":false,"type":"object","required":["journal_key","amount","account"],"title":"StructureProposal"},"StructureRoleConflict":{"properties":{"column":{"type":"string","title":"Column","description":"Physical column assigned to incompatible structural roles."},"assigned_roles":{"items":{"type":"string"},"type":"array","title":"Assigned Roles","description":"Conflicting semantic roles in proposal order."},"allowed":{"type":"boolean","const":false,"title":"Allowed","description":"Whether this role combination is permitted.","default":false},"resolution":{"type":"string","title":"Resolution","description":"Action that makes the structural nomination valid."}},"additionalProperties":false,"type":"object","required":["column","assigned_roles","resolution"],"title":"StructureRoleConflict"},"SubdirectorySummary":{"properties":{"name":{"type":"string","title":"Name","description":"The subfolder's name; append it to the described folder to descend."},"overall_files":{"type":"integer","title":"Overall Files","description":"Files in the subfolder's whole subtree that the caller can see."},"top_categories":{"items":{"$ref":"#/components/schemas/CategoryCount"},"type":"array","title":"Top Categories","description":"The subtree's most common categories, most files first, capped."},"failed_files":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Failed Files","description":"Files in the subtree with ingestion_status=failed; absent when none."}},"additionalProperties":false,"type":"object","required":["name","overall_files"],"title":"SubdirectorySummary","description":"Orientation summary for one immediate subdirectory, covering its whole subtree.\n\nCarries enough to pick a descent target without listing the subtree: the\nfile count, the most-populous categories (capped at\nFOLDER_SUBDIR_TOP_CATEGORIES), and the failed-ingestion count when nonzero."},"SuggestDomainDescriptionRequest":{"properties":{"display_name":{"type":"string","maxLength":200,"minLength":1,"title":"Display Name","description":"The domain's display name. Meaningless names should yield an empty description."}},"additionalProperties":false,"type":"object","required":["display_name"],"title":"SuggestDomainDescriptionRequest","description":"Ask the model for a classifier-facing description of a named domain."},"SuggestDomainDescriptionResponse":{"properties":{"description":{"type":"string","maxLength":4000,"title":"Description","description":"Suggested domain description for taxonomy generation. Empty when the name is not a recognizable subject."}},"additionalProperties":false,"type":"object","required":["description"],"title":"SuggestDomainDescriptionResponse","description":"Classifier-facing brief for taxonomy generation, or empty when the name is unusable."},"SystemOneRequest":{"properties":{"state":{"$ref":"#/components/schemas/JsonValue","description":"The situation to decide about: text, or any JSON value such as a record or a list of rows."},"questions":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/NoulQuestion"},{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"propertyNames":{"minLength":1},"type":"object","maxProperties":512,"minProperties":1,"title":"Questions","description":"The questions to answer in one call, keyed by the name each answer returns under."}},"additionalProperties":false,"type":"object","required":["state","questions"],"title":"SystemOneRequest"},"SystemOneResponse":{"properties":{"model":{"type":"string","title":"Model","description":"The decision model that answered, as this deployment names it."},"answers":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/NoulAnswer"},{"$ref":"#/components/schemas/ChoiceAnswer"},{"$ref":"#/components/schemas/ScoreAnswer"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceAnswer","noul":"#/components/schemas/NoulAnswer","score":"#/components/schemas/ScoreAnswer"}}},"type":"object","title":"Answers","description":"One answer per question, keyed by the question's name."},"usage":{"$ref":"#/components/schemas/SystemOneUsage","description":"Token usage of the decision call, for cost tracking."},"evaluation_time_ms":{"type":"number","title":"Evaluation Time Ms","description":"Time the decision model spent on the call, in milliseconds."},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id","description":"Correlation id of this request, the same one error bodies carry."}},"additionalProperties":false,"type":"object","required":["model","answers","usage","evaluation_time_ms","request_id"],"title":"SystemOneResponse"},"SystemOneUsage":{"properties":{"input_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Input Tokens","description":"Tokens the decision model read, when the model reports them."},"output_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Output Tokens","description":"Tokens the decision model produced, when the model reports them."}},"additionalProperties":false,"type":"object","required":["input_tokens","output_tokens"],"title":"SystemOneUsage"},"TableCardWire":{"properties":{"path":{"type":"string","title":"Path","description":"The source file this table was ingested from."},"component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Component","description":"The worksheet or tab inside that file, where it has one."},"table_name":{"type":"string","title":"Table Name","description":"The name SQL over this workspace registers the table under."},"role":{"type":"string","title":"Role","description":"What this table is in the package: journal_lines, journal_headers, trial_balance, chart_of_accounts, calendar, user_master, source_listing, or other."},"rows":{"type":"integer","title":"Rows","description":"Rows in the table, as the ingest census counted them."},"line_shaped":{"type":"boolean","title":"Line Shaped","description":"Whether this table is a journal-line file: a journal key and either a debit/credit pair or a live-measured signed amount."},"partition_family":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Partition Family","description":"The family this table shares with its siblings when one ledger is split per period."},"journal_key":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Journal Key","description":"The columns the accepted journal key is spelled over, or null when none qualified."},"key_balanced_share":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Key Balanced Share","description":"Share of that key's groups netting to zero on the tested amount basis."},"key_median_lines":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Key Median Lines","description":"Median lines per journal under that key."},"columns":{"items":{"$ref":"#/components/schemas/ColumnCardWire"},"type":"array","title":"Columns","description":"Every column of the table, in the table's own column order."}},"additionalProperties":false,"type":"object","required":["path","table_name","role","rows","line_shaped","columns"],"title":"TableCardWire","description":"One table as the stage reads it, with the grain figures a reader acts on."},"TableCensusEntry":{"properties":{"path":{"type":"string","title":"Path","description":"Uploaded source path owning the table."},"component":{"type":"string","title":"Component","description":"The table's public component name (tab or section) — pass to file-metadata."},"table_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table Name","description":"SQL view name the table is registered under for run-sql, when its profile is readable."},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count","description":"Rows in the queryable table, when ingestion measured them."},"column_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Column Count","description":"Columns, when measured."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"The owning FILE's size — per-file, so a workbook's tabs repeat it."}},"additionalProperties":false,"type":"object","required":["path","component","size_bytes"],"title":"TableCensusEntry","description":"One queryable table in the census (a spreadsheet tab or a document section's rows): where it is and how big."},"TableColumnInfo":{"properties":{"name":{"type":"string","title":"Name","description":"Column name as it must be quoted in SQL."},"data_type":{"type":"string","title":"Data Type","description":"SQL type of the column (e.g. BIGINT, VARCHAR, TIMESTAMP)."},"null_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Null Count","description":"Rows where this column is NULL."},"all_null":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"All Null","description":"True when the profile proved every row NULL (null_count equals the profile's own exact row count — the component's row_count can come from sheet metadata with a different denominator). Absent otherwise."},"distinct_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Distinct Count","description":"APPROXIMATE distinct value count (HyperLogLog). Compare to the component's row_count for key candidates, but verify exact uniqueness with a query."},"min_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Value","description":"Smallest value as text, clipped; a format exemplar for ids."},"max_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Max Value","description":"Largest value as text, clipped."},"sum_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sum Value","description":"Sum of the column as text; numeric columns on profiles that measured it."},"sample_values":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sample Values","description":"The column's COMPLETE distinct value list (low-cardinality columns only), each value clipped. Superseded by ``top_values`` when the profile carries a census — then this field is omitted rather than duplicated."},"top_values":{"anyOf":[{"items":{"$ref":"#/components/schemas/TableColumnValueCount"},"type":"array"},{"type":"null"}],"title":"Top Values","description":"Frequency census: most common values WITH row counts, most frequent first. Complete when it lists every distinct value; ``top_values_coverage`` says how much of the column a cut census covers."},"top_values_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top Values Coverage","description":"Fraction of the column's non-null rows the census covers (0..1)."}},"additionalProperties":false,"type":"object","required":["name","data_type"],"title":"TableColumnInfo","description":"One column of a queryable component's schema, with the statistics ingestion profiled.\n\nThe stats are the briefing the platform's own SQL engine reads before it\nwrites a query — null/distinct counts, value range, numeric sum, and a\nbounded frequency census — served here so a caller can plan a\n``query-tables`` selection without probe queries. Every rendered value is\nclipped server-side; fields are absent when the profile predates them or\nthe type does not support them. The caller's access gate is the same one\n``read-file`` and ``query-tables`` pass, so nothing here exceeds what those\nalready serve."},"TableColumnValueCount":{"properties":{"value":{"type":"string","title":"Value","description":"The value, rendered as text and clipped to the value character cap."},"count":{"type":"integer","title":"Count","description":"Rows carrying this value."}},"additionalProperties":false,"type":"object","required":["value","count"],"title":"TableColumnValueCount","description":"One census entry: a column value and how many rows carry it."},"TableQueryColumn":{"properties":{"name":{"type":"string","title":"Name"},"data_type":{"type":"string","title":"Data Type"}},"additionalProperties":false,"type":"object","required":["name","data_type"],"title":"TableQueryColumn","description":"One column of an executed SQL query's result preview."},"TableQueryGrounding":{"properties":{"sql":{"type":"string","title":"Sql"},"supports_answer":{"type":"boolean","title":"Supports Answer","description":"False for exploratory SQL the tables engine ran but did not mark as part of the answer's calculation trail.","default":true},"result_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Id","description":"Stable identity of the stored query result behind this receipt. Lets the grounding-rows endpoint replay this exact query for matched-row pages beyond the regions' inline runs."},"source_paths":{"items":{"type":"string"},"type":"array","title":"Source Paths","description":"The uploaded table files this query read — directly, or through a prior result it built on — e.g. 'planning/FS GF Custom.xlsx'."},"row_count":{"type":"integer","title":"Row Count","description":"Rows in the query's full result, not in the preview below.","default":0},"columns":{"items":{"$ref":"#/components/schemas/TableQueryColumn"},"type":"array","title":"Columns"},"rows":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Rows","description":"Leading result rows, values rendered as text — a bounded preview, never the full result."},"preview_truncated":{"type":"boolean","title":"Preview Truncated","description":"Whether the preview cut rows or columns.","default":false},"verified":{"type":"boolean","title":"Verified","description":"True when at least one claim behind this query passed mechanical verification against the source data. Independent of 'regions': a source without an addressable grid verifies but cannot be pointed at, so an empty 'regions' never means unverified.","default":false},"regions":{"items":{"oneOf":[{"$ref":"#/components/schemas/SheetQueryRegion"},{"$ref":"#/components/schemas/RowRangeQueryRegion"}],"discriminator":{"propertyName":"kind","mapping":{"row_range":"#/components/schemas/RowRangeQueryRegion","sheet":"#/components/schemas/SheetQueryRegion"}}},"type":"array","title":"Regions","description":"Original-file coordinates for the verified claims whose source file has an addressable grid."},"grounding_status":{"anyOf":[{"type":"string","enum":["exact","unavailable","zero_result"]},{"type":"null"}],"title":"Grounding Status","description":"Capture-time provenance status behind this query's regions. 'exact': the exact-provenance sidecar proved every row the query read, so its 'provenance'-basis regions are trustworthy (source regions may be broader than the minimal contributing set when grounding_reason carries a 'regions_broad:…' qualifier). 'unavailable': no exact proof could be captured (a legacy result, or a statement shape the capturer cannot instrument) — no 'provenance'-basis regions are attached, never a guessed whole-table span. 'zero_result': the query matched no rows, so there is nothing to ground. None on legacy payloads and on a query with no unclaimed table left to ground."},"grounding_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grounding Reason","description":"Qualification on grounding_status, when present. Set for 'unavailable' (explains why proof was not possible) and for 'exact' when capture succeeded but the source regions are broader than the minimal contributing set (e.g. 'regions_broad:narrowing_specs_unavailable'). None when grounding is fully exact or absent."}},"additionalProperties":false,"type":"object","required":["sql"],"title":"TableQueryGrounding","description":"One SQL query executed against the caller's tables while answering.\n\nThe grounding behind a computed evidence: when the agent answers a\ncount/sum/join question it runs a SQL agent over the uploaded tables, and\nthis is the receipt — the query text and a bounded preview of what it\nreturned. Attached to the evidence it grounds rather than published\nglobally, so a computed figure and its computation travel together.\n\n``source_paths`` name uploaded files, resolved server-side through the\ncaller's access gate exactly like ``source_path`` on the evidence itself."},"TableRegion":{"properties":{"kind":{"type":"string","const":"table_region","title":"Kind","default":"table_region"},"source_file_name":{"type":"string","title":"Source File Name"},"row_ranges":{"items":{"$ref":"#/components/schemas/TableRowRange"},"type":"array","title":"Row Ranges"},"columns":{"items":{"type":"string"},"type":"array","title":"Columns"},"sql":{"type":"string","title":"Sql"},"matched_rows":{"type":"integer","minimum":0.0,"title":"Matched Rows","default":0},"exact":{"type":"boolean","title":"Exact"}},"additionalProperties":false,"type":"object","required":["source_file_name","sql","exact"],"title":"TableRegion","description":"Rows and columns from a Parquet source, with reproducible SQL provenance."},"TableRowRange":{"properties":{"start":{"type":"integer","minimum":0.0,"title":"Start"},"end":{"type":"integer","minimum":0.0,"title":"End"}},"additionalProperties":false,"type":"object","required":["start","end"],"title":"TableRowRange","description":"Inclusive 0-based row range in a table source."},"Taxonomy-Output":{"properties":{"classes":{"items":{"$ref":"#/components/schemas/TaxonomyClass"},"type":"array","maxItems":400,"title":"Classes"},"allow_other":{"type":"boolean","const":true,"title":"Allow Other","description":"Cannot be disabled: a document that fits nothing is labelled 'other', never force-fitted.","default":true}},"additionalProperties":false,"type":"object","title":"Taxonomy","description":"The classification vocabulary."},"TaxonomyCategory":{"properties":{"key":{"type":"string","title":"Key","description":"Stable top-level category key, e.g. 'reports'."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Shown to the stage-1 router; improves accuracy."},"subcategories":{"items":{"$ref":"#/components/schemas/TaxonomySubcategory"},"type":"array","minItems":1,"title":"Subcategories"}},"additionalProperties":false,"type":"object","required":["key","subcategories"],"title":"TaxonomyCategory"},"TaxonomyClass":{"properties":{"group":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Group"},"subgroup":{"type":"string","maxLength":64,"pattern":"^[a-z0-9]+(?:_[a-z0-9]+)*$","title":"Subgroup"},"description":{"type":"string","title":"Description","description":"Written for the classifier — it IS the prompt."},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"Renames land here so old folder paths stay resolvable."}},"additionalProperties":false,"type":"object","required":["group","subgroup","description"],"title":"TaxonomyClass","description":"One leaf of the two-level taxonomy.\n\nThe two levels are ``group`` then ``subgroup`` — exactly two, which is what\nmakes a folder path predictable and a classification prompt short enough to\nbe accurate."},"TaxonomySubcategory":{"properties":{"key":{"type":"string","title":"Key","description":"Stable subcategory key, e.g. 'financial_reports'."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Shown to the classifier; improves accuracy."}},"additionalProperties":false,"type":"object","required":["key"],"title":"TaxonomySubcategory"},"Tenant":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"NDI's id for the tenant; X-NDI-Tenant accepts it too."},"external_ref":{"type":"string","title":"External Ref","description":"The partner's own reference for the tenant, unique per partner."},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Human-readable name of the tenant."},"disabled":{"type":"boolean","title":"Disabled","description":"Whether the tenant is disabled. Its data is kept."},"limits":{"$ref":"#/components/schemas/TenantLimits","description":"The limits in force for the tenant."},"data_retention":{"$ref":"#/components/schemas/GranularRetention","description":"The data-retention setting in force for the tenant. Existing zero_retention tenants keep their policy when new Zero retention provisioning is disabled."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the tenant was created."}},"additionalProperties":false,"type":"object","required":["id","external_ref","display_name","disabled","limits","data_retention","created_at"],"title":"Tenant","description":"One of the partner's child tenants. Send ``X-NDI-Tenant: ext:<external_ref>`` to act for it."},"TenantBucketWorkspaceStorage":{"properties":{"type":{"type":"string","const":"tenant_bucket","title":"Type","default":"tenant_bucket"},"provider":{"type":"string","const":"s3","title":"Provider","default":"s3"},"location":{"type":"string","title":"Location","description":"Workspace namespace in the tenant's configured bucket."}},"additionalProperties":false,"type":"object","required":["location"],"title":"TenantBucketWorkspaceStorage"},"TenantLimits":{"properties":{"rpm":{"type":"integer","title":"Rpm","description":"Requests per minute this tenant may make."},"max_concurrent_jobs":{"type":"integer","title":"Max Concurrent Jobs","description":"Parse, split, classify, categorize, extract, ground and agent jobs this tenant may have running at once; more wait in the queue. NDI's own per-tenant cap applies when it is lower."}},"additionalProperties":false,"type":"object","required":["rpm","max_concurrent_jobs"],"title":"TenantLimits","description":"The limits in force for a tenant."},"TenantLimitsRequest":{"properties":{"rpm":{"anyOf":[{"type":"integer","minimum":1.0,"description":"Requests per minute this tenant may make."},{"type":"null"}],"title":"Rpm"},"max_concurrent_jobs":{"anyOf":[{"type":"integer","minimum":1.0,"description":"Parse, split, classify, categorize, extract, ground and agent jobs this tenant may have running at once; more wait in the queue. NDI's own per-tenant cap applies when it is lower."},{"type":"null"}],"title":"Max Concurrent Jobs"}},"additionalProperties":false,"type":"object","title":"TenantLimitsRequest","description":"Per-tenant limits a partner asks for; values above the partner's own caps are lowered to them."},"TenantPurgeJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"tenant_purge","title":"Kind","default":"tenant_purge"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/TenantPurgeResult"},{"type":"null"}],"description":"Present once the purge has finished."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"TenantPurgeJob"},"TenantPurgeResult":{"properties":{"result_type":{"type":"string","const":"tenant_purge","title":"Result Type","default":"tenant_purge"},"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id","description":"The tenant whose data was purged, as NDI identifies it."},"external_ref":{"type":"string","title":"External Ref","description":"The partner's own reference the tenant had. It stops resolving once the purge succeeds."},"verified":{"type":"boolean","title":"Verified","description":"True when no content of the tenant remains anywhere and every kept metadata row is de-identified."},"stores":{"items":{"$ref":"#/components/schemas/TenantPurgeStoreReport"},"type":"array","title":"Stores","description":"One line per store, with what the verification pass still found."},"billing_record_kept":{"type":"boolean","title":"Billing Record Kept","description":"True when the content-free billing record (job ids, kinds, timestamps, units, credits) was kept."}},"additionalProperties":false,"type":"object","required":["tenant_id","external_ref","verified","stores","billing_record_kept"],"title":"TenantPurgeResult","description":"The tenant's content is gone; no row is deleted: its billing record and metadata rows stay, de-identified.\n\n``verified`` is true only when every store reports nothing remaining. An unfinished\ncancelled job counts against ``jobs`` and a workspace teardown that could not verify\nits own storage, index and graph counts against ``workspaces``. A purge that ends\nunverified is a ``succeeded`` job on purpose, like a workspace delete: the report says\nwhat is left, and a second DELETE re-runs it."},"TenantPurgeStore":{"type":"string","enum":["jobs","workspaces","files","upload_sessions","profile_cache","answer_cache","catalog","ledger_decisions","parse_exports","webhooks","api_keys","members","users","cli_sessions","limit_overrides","schemas_and_labels","perception_cache","storage","redis"],"title":"TenantPurgeStore","description":"One place tenant data lives, and so one line of a purge's verification report.\n\nA purge never deletes a Postgres row: each store's rows are emptied or de-identified and marked deleted, and\nonly stored objects and Redis keys are removed."},"TenantPurgeStoreReport":{"properties":{"store":{"$ref":"#/components/schemas/TenantPurgeStore","description":"The store this line reports."},"remaining":{"type":"integer","minimum":0.0,"title":"Remaining","description":"Rows that still hold the tenant's content or identifying data or still grant access, objects, and open executions still found there. Kept rows that are already emptied do not count. Zero when clean."}},"additionalProperties":false,"type":"object","required":["store","remaining"],"title":"TenantPurgeStoreReport","description":"What the verification pass still finds of the tenant in one store."},"TextCell":{"properties":{"kind":{"type":"string","const":"text","title":"Kind","default":"text"},"text":{"type":"string","title":"Text"}},"additionalProperties":false,"type":"object","required":["text"],"title":"TextCell"},"TextRange":{"properties":{"kind":{"type":"string","const":"text_range","title":"Kind","default":"text_range"},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page"},"pages":{"items":{"type":"integer"},"type":"array","title":"Pages"},"char_start":{"type":"integer","title":"Char Start"},"char_end":{"type":"integer","title":"Char End"}},"additionalProperties":false,"type":"object","required":["char_start","char_end"],"title":"TextRange","description":"A character span in a derivative's text, with the page(s) it falls on.\n\n``pages`` is every page the span overlaps — a chunk that straddles a page\nmarker belongs to both, and a reader handed only the first would miss the\npart of the span that carries the match. ``page`` is the first of them,\nkept because most producers and consumers only ever deal in one page."},"TextRangeMatch":{"properties":{"match_type":{"type":"string","const":"text_range","title":"Match Type","default":"text_range"},"start_char":{"type":"integer","title":"Start Char"},"end_char":{"type":"integer","title":"End Char"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"}},"type":"object","required":["start_char","end_char"],"title":"TextRangeMatch"},"TextSpan":{"properties":{"kind":{"type":"string","const":"text_span","title":"Kind","default":"text_span"},"page":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Page","description":"1-based page when the span maps to a known page. Null for text-only sources."},"char_start":{"type":"integer","minimum":0.0,"title":"Char Start","description":"Inclusive start offset in the derived text."},"char_end":{"type":"integer","minimum":0.0,"title":"Char End","description":"Exclusive end offset in the derived text."}},"additionalProperties":false,"type":"object","required":["char_start","char_end"],"title":"TextSpan","description":"A character span in derived text (optional page when known)."},"ToolCallTrace":{"properties":{"tool":{"type":"string","title":"Tool"},"arguments_digest":{"type":"string","title":"Arguments Digest"},"hits":{"type":"integer","title":"Hits"},"duration_ms":{"type":"integer","title":"Duration Ms"}},"additionalProperties":false,"type":"object","required":["tool","arguments_digest","hits","duration_ms"],"title":"ToolCallTrace","description":"Carries an argument digest rather than raw arguments.\n\nRaw arguments would be a side channel around ``Coverage``: a caller could\nread back what the loop searched for on its behalf."},"TruncationTarget":{"type":"string","enum":["classification_input","document_content","spreadsheet_region","extraction_array"],"title":"TruncationTarget","description":"Processing area where content was reduced before producing a result."},"TruncationUnit":{"type":"string","enum":["characters","tokens","rows","columns","cells","items"],"title":"TruncationUnit","description":"Unit used to quantify a content reduction."},"UnavailableTable":{"properties":{"path":{"type":"string","title":"Path"},"error":{"type":"string","title":"Error"},"error_kind":{"anyOf":[{"type":"string","enum":["conversion_rejected","conversion_failed","profile_rejected","profile_failed"]},{"type":"null"}],"title":"Error Kind"}},"additionalProperties":false,"type":"object","required":["path","error"],"title":"UnavailableTable","description":"A requested path (or one of its ingested sheets) that could not be queried.\n\n``error_kind`` is ``None`` only when the failure happened before ingest\ncould even classify it (an access or resolution error, which raises as a\ntyped HTTP error instead of reaching this list).\n\nLives here rather than beside the tool responses because a stored job\nresult reports the same unusable inputs the synchronous response did — one\ndefinition, so a reopened run cannot describe them differently."},"UpdateAccessLabelRequest":{"properties":{"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"}},"additionalProperties":false,"type":"object","title":"UpdateAccessLabelRequest","description":"Partial update. Name changes are refused — rename by delete + create."},"UpdateDomainRequest":{"properties":{"display_name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Display Name"},"taxonomy":{"anyOf":[{"$ref":"#/components/schemas/ndi_service__app__platform_api__domains__schemas__Taxonomy"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"UpdateDomainRequest","description":"Any subset of the create request.\n\nEditing a ``draft`` mutates it. Editing a ``published`` domain creates\nversion *n+1* as a new draft and leaves version *n* untouched — there is no\nway to change the vocabulary under a live corpus, because a workspace that\ncould not explain its own folder structure is worse than one with an old\nvocabulary."},"UpdateJobRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Name"}},"additionalProperties":false,"type":"object","title":"UpdateJobRequest","description":"Body for ``PATCH /jobs/{job_id}``.\n\n``name`` is the only mutable caller-facing field on a job — everything else\nis either the frozen request or worker-owned state. An explicit ``null``\nclears the custom name; public document runs then display their stable server fallback."},"UpdateWorkspaceRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name","description":"New display name for an ordinary workspace. Platform-provisioned names are fixed. Omit to keep the current name; null is not accepted."},"knowledge_graph":{"anyOf":[{"$ref":"#/components/schemas/KnowledgeGraphConfig"},{"type":"null"}],"description":"The workspace's complete new knowledge-graph policy, or omitted to leave it unchanged. Supplying it replaces every field it holds, so send the block read back from the workspace with your edits applied rather than only the key you are changing."},"currency":{"anyOf":[{"$ref":"#/components/schemas/CurrencyPolicy"},{"type":"null"}],"description":"The workspace's complete new currency-reading policy, or omitted to leave it unchanged. Whole-block like ``knowledge_graph``: an empty object resets to the USD default, and ``{\"default\": null}`` is how the policy is cleared to assume nothing. Applies from the next ingestion onwards: amounts already extracted as ambiguous stay that way until their file is re-ingested, since the catalog records what a past extraction could read."},"ledger_understanding":{"anyOf":[{"$ref":"#/components/schemas/LedgerUnderstandingConfig"},{"type":"null"}],"description":"The workspace's complete new ledger-understanding policy, or omitted to leave it unchanged. Whole-block like ``knowledge_graph``. Turning the trigger off stops future ingestions chaining a run; it never refuses an explicit one, and it does not withdraw a report already measured."},"global_context":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Global Context","description":"The workspace's new global context, or omitted to leave it unchanged; `\"\"` clears it. Standing background for every query in this workspace — how its journals are keyed, which entity it covers, what an auditor already knows. A je-testing or search request that omits `context` runs with this text; a request that sends `context` replaces it for that run, and `\"\"` runs with none. Empty means none. Surrounding whitespace is stripped."}},"additionalProperties":false,"type":"object","title":"UpdateWorkspaceRequest","description":"Change a workspace's mutable configuration.\n\nPresence-aware: a field omitted from the body is left exactly as it is, so a\ncaller changing one block cannot clear another by not mentioning it. A field\nthat *is* supplied replaces its block whole — the rule ``set_key_grants``\nfollows for label grants, which is what keeps turning a policy off the same\noperation as turning it on, with no add/remove asymmetry to get wrong.\n\nThe display name of an ordinary workspace (platform-provisioned names stay fixed),\nthe knowledge-graph, currency and ledger-understanding policies and the global\ncontext are mutable. The domain and the label list are not: both are part of the versioned config\nrecord that every derived artifact is stamped with, so editing them in place\nwould silently re-describe material that was derived under the old one."},"UploadFileJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"file_upload","title":"Kind","default":"file_upload"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/UploadFileResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"UploadFileJob"},"UploadFileResult":{"properties":{"result_type":{"type":"string","const":"file_upload","title":"Result Type","default":"file_upload"},"file":{"$ref":"#/components/schemas/File"},"deduplicated":{"type":"boolean","title":"Deduplicated","description":"Identical bytes were already present."}},"additionalProperties":false,"type":"object","required":["file","deduplicated"],"title":"UploadFileResult","description":"Also the result of ``JobKind.UPLOAD_SESSION_COMPLETE``.\n\nA chunked upload's completion produces exactly this shape — the file it\nlanded, and whether it deduplicated — so it deliberately reuses this\nresult rather than minting a near-identical discriminated variant whose\n``result_type`` would just be a second name for the same two fields."},"UploadGrantResponse":{"properties":{"token":{"type":"string","title":"Token","description":"Send in the X-Upload-Token header of the upload request."},"upload_url":{"type":"string","title":"Upload Url","description":"The upload_file route the token is valid against."},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When the grant stops verifying."}},"additionalProperties":false,"type":"object","required":["token","upload_url","expires_at"],"title":"UploadGrantResponse","description":"A minted upload grant, ready to hand to an end client.\n\nThe holder sends ``token`` in the ``X-Upload-Token`` header of a multipart\n``POST`` to ``upload_url`` (the workspace's ``upload_file`` route). The\ngrant authorizes that one method only, and is single-use where the\ndeployment runs Redis."},"UploadSessionCompleteJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"upload_session_complete","title":"Kind","default":"upload_session_complete"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/UploadFileResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"UploadSessionCompleteJob"},"UploadSessionPart":{"properties":{"part_number":{"type":"integer","title":"Part Number"},"size_bytes":{"type":"integer","title":"Size Bytes"}},"additionalProperties":false,"type":"object","required":["part_number","size_bytes"],"title":"UploadSessionPart","description":"One landed part, as reported by ``GET .../upload-sessions/{session_id}``."},"UploadSessionPartResponse":{"properties":{"part_number":{"type":"integer","title":"Part Number"},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Bytes actually received for this part."}},"additionalProperties":false,"type":"object","required":["part_number","size_bytes"],"title":"UploadSessionPartResponse","description":"Result of ``PUT .../upload-sessions/{session_id}/parts/{part_number}``."},"UploadSessionStatusResponse":{"properties":{"session_id":{"type":"string","format":"uuid","title":"Session Id"},"status":{"type":"string","enum":["open","completing","completed","aborted"],"title":"Status"},"chunk_size":{"type":"integer","title":"Chunk Size"},"total_parts":{"type":"integer","title":"Total Parts"},"parts":{"items":{"$ref":"#/components/schemas/UploadSessionPart"},"type":"array","title":"Parts","description":"Parts landed so far, unordered."},"received_bytes":{"type":"integer","title":"Received Bytes","description":"Sum of parts[*].size_bytes."},"declared_size_bytes":{"type":"integer","title":"Declared Size Bytes"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"additionalProperties":false,"type":"object","required":["session_id","status","chunk_size","total_parts","parts","received_bytes","declared_size_bytes","expires_at"],"title":"UploadSessionStatusResponse","description":"Result of ``GET .../upload-sessions/{session_id}`` — for resuming after a drop.\n\nA resuming client diffs ``parts`` against what it already sent and PUTs\nonly what is missing; it never needs to re-derive part numbers itself."},"UploadSource":{"properties":{"type":{"type":"string","const":"upload","title":"Type","default":"upload"},"upload_id":{"type":"string","format":"uuid","title":"Upload Id","description":"Id returned by POST /v1/uploads. Ordinary bytes remain until their consuming jobs or tenant are deleted."}},"additionalProperties":false,"type":"object","required":["upload_id"],"title":"UploadSource","description":"Bytes staged through ``POST /v1/uploads``. Retained until explicit deletion, except under Zero retention."},"UrlSource":{"properties":{"type":{"type":"string","const":"url","title":"Type","default":"url"},"url":{"type":"string","maxLength":2048,"pattern":"^https://","title":"Url","description":"HTTPS URL the service fetches."},"file_name":{"type":"string","maxLength":512,"title":"File Name","description":"Filename to record for the fetched bytes."}},"additionalProperties":false,"type":"object","required":["url","file_name"],"title":"UrlSource","description":"A public or presigned HTTPS location we fetch server-side."},"UsageBucket":{"properties":{"key":{"type":"string","title":"Key"},"units":{"type":"integer","title":"Units"},"jobs":{"type":"integer","title":"Jobs"},"pages":{"type":"integer","title":"Pages"},"bytes_ingested":{"type":"integer","title":"Bytes Ingested"},"credits":{"type":"integer","title":"Credits","description":"Final credits of the jobs in this bucket whose usage is final. What a bill charges."},"unfinalized_jobs":{"type":"integer","title":"Unfinalized Jobs","description":"Jobs in this bucket whose usage is not final yet, so they are not in `credits`."}},"additionalProperties":false,"type":"object","required":["key","units","jobs","pages","bytes_ingested","credits","unfinalized_jobs"],"title":"UsageBucket","description":"One aggregation bucket returned by ``GET /usage``.\n\n``credits`` is what the bill charges. The admission allowance also counts measured failed and cancelled work and\nin-flight reservations, so a ``quota_exceeded`` ``credits_used`` can exceed these credits."},"UsageLine":{"properties":{"part":{"type":"string","enum":["parse","operation","image_ocr"],"title":"Part","description":"parse: reading the document into text. operation: the tool's own work on what was parsed. image_ocr: reading the images inside an email, HTML or spreadsheet file. A ground job's image_ocr is the email images it read to find targets its text search missed."},"quantity":{"type":"integer","minimum":0.0,"title":"Quantity","description":"How many units of work this part measured, including waived or included work."},"unit":{"type":"string","enum":["page","item","unit","image"],"title":"Unit","description":"What quantity counts: page is a page or page-equivalent (a spreadsheet's non-empty cells, a minute of audio), item is a ground item, image is an image Parse read inside an email, HTML or spreadsheet file, unit is a job priced by its units directly (agent steps)."},"credits_per_unit":{"type":"integer","minimum":0.0,"title":"Credits Per Unit","description":"The credit schedule's rate for one unit of this part; zero for OCR included in the ordinary price."},"multiplier":{"type":"integer","minimum":1.0,"title":"Multiplier","description":"2 on the parse and image_ocr parts of a parse_mode \"high\" job, otherwise 1."},"credits":{"type":"integer","minimum":0.0,"title":"Credits","description":"quantity x credits_per_unit x multiplier: what this part added to the job's credits. 0 when waived or included in the ordinary price."},"waiver":{"anyOf":[{"$ref":"#/components/schemas/UsageWaiver"},{"type":"null"}],"description":"Verified reuse that waived this work. Null for charged work and for included OCR without reuse."}},"additionalProperties":false,"type":"object","required":["part","quantity","unit","credits_per_unit","multiplier","credits"],"title":"UsageLine","description":"One part of a job's final credits."},"UsageOverviewPoint":{"properties":{"day":{"type":"string","format":"date","title":"Day"},"documents":{"type":"integer","title":"Documents"}},"additionalProperties":false,"type":"object","required":["day","documents"],"title":"UsageOverviewPoint","description":"One calendar day in the usage-overview series."},"UsageOverviewResponse":{"properties":{"window":{"type":"string","enum":["7d","30d","90d"],"title":"Window"},"period_start":{"type":"string","format":"date","title":"Period Start"},"period_end":{"type":"string","format":"date","title":"Period End"},"documents_processed":{"type":"integer","title":"Documents Processed"},"documents_processed_prior":{"type":"integer","title":"Documents Processed Prior"},"active_jobs":{"type":"integer","title":"Active Jobs"},"queued_jobs":{"type":"integer","title":"Queued Jobs"},"avg_processing_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Processing Seconds"},"avg_processing_seconds_prior":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Processing Seconds Prior"},"series":{"items":{"$ref":"#/components/schemas/UsageOverviewPoint"},"type":"array","title":"Series"}},"additionalProperties":false,"type":"object","required":["window","period_start","period_end","documents_processed","documents_processed_prior","active_jobs","queued_jobs","avg_processing_seconds","avg_processing_seconds_prior","series"],"title":"UsageOverviewResponse","description":"Dashboard figures for a rolling ``7d`` / ``30d`` / ``90d`` window.\n\nPrior-period fields are the same-length window immediately before\n``period_start``. The frontend derives the percentage / delta; this\nresponse only reports the two raw values. Average processing time is\n``null`` when the window has no succeeded document-operation jobs."},"UsageWaiver":{"properties":{"part":{"type":"string","enum":["parse","job"],"title":"Part","description":"parse: the parse part was not charged. job: nothing in the job was charged."},"reason":{"type":"string","enum":["reused_parse","repeat_of_job"],"title":"Reason","description":"reused_parse: the job read a parse your earlier job already paid for. repeat_of_job: the job repeated your earlier job exactly and was answered with its result."},"source_job_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Source Job Id","description":"Always null: billing history must not disclose another job as its visibility changes."}},"additionalProperties":false,"type":"object","required":["part","reason"],"title":"UsageWaiver","description":"Why part of a job, or the whole job, was not charged."},"ValueCountWire":{"properties":{"value":{"type":"string","title":"Value","description":"The value as the column spells it, rendered as text."},"rows":{"type":"integer","title":"Rows","description":"Rows carrying this value, as the census counted them."}},"additionalProperties":false,"type":"object","required":["value","rows"],"title":"ValueCountWire","description":"One value of a column's domain and how many rows carry it."},"VisualRegion":{"properties":{"kind":{"type":"string","const":"visual_region","title":"Kind","default":"visual_region"},"page":{"type":"integer","title":"Page"},"bbox":{"prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}],"type":"array","maxItems":4,"minItems":4,"title":"Bbox"}},"additionalProperties":false,"type":"object","required":["page","bbox"],"title":"VisualRegion"},"VisualRegionMatch":{"properties":{"match_type":{"type":"string","const":"visual_region","title":"Match Type","default":"visual_region"},"page":{"type":"integer","title":"Page","description":"1-indexed page number."},"x":{"type":"number","title":"X"},"y":{"type":"number","title":"Y"},"w":{"type":"number","title":"W"},"h":{"type":"number","title":"H"},"confidence":{"type":"number","title":"Confidence","default":1.0},"matched_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Matched Text"},"cropped_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cropped Image Url"}},"type":"object","required":["page","x","y","w","h"],"title":"VisualRegionMatch"},"WordAnchor":{"properties":{"part":{"type":"string","pattern":"^word/(?:document|header\\d+|footer\\d+|footnotes|endnotes)\\.xml$","title":"Part","description":"OOXML package member containing the matched paragraph."},"paragraph_index":{"type":"integer","minimum":0.0,"title":"Paragraph Index","description":"Zero-based w:p index in this part, counting start tags including table-cell paragraphs."},"char_start":{"type":"integer","minimum":0.0,"title":"Char Start","description":"Inclusive code-point offset in visible paragraph text: w:t runs joined with tabs and breaks."},"char_end":{"type":"integer","exclusiveMinimum":0.0,"title":"Char End","description":"Exclusive code-point offset in the same paragraph text."}},"additionalProperties":false,"type":"object","required":["part","paragraph_index","char_start","char_end"],"title":"WordAnchor","description":"Native OOXML paragraph span, independent of converted-PDF pagination."},"Workspace":{"properties":{"storage":{"oneOf":[{"$ref":"#/components/schemas/ManagedWorkspaceStorage"},{"$ref":"#/components/schemas/TenantBucketWorkspaceStorage"},{"$ref":"#/components/schemas/ExternalWorkspaceStorage"}],"title":"Storage","description":"The workspace's durable storage backend and external connection health.","discriminator":{"propertyName":"type","mapping":{"external":"#/components/schemas/ExternalWorkspaceStorage","managed":"#/components/schemas/ManagedWorkspaceStorage","tenant_bucket":"#/components/schemas/TenantBucketWorkspaceStorage"}}},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id","description":"The console user who owns the workspace, or null for an organization-owned integration workspace."},"share_count":{"type":"integer","minimum":0.0,"title":"Share Count","description":"Number of users explicitly granted workspace access; excludes the owner."},"name":{"type":"string","title":"Name"},"domain_id":{"type":"string","format":"uuid","title":"Domain Id"},"domain_slug":{"type":"string","title":"Domain Slug"},"domain_version":{"type":"integer","title":"Domain Version"},"access":{"$ref":"#/components/schemas/AccessConfig"},"knowledge_graph":{"$ref":"#/components/schemas/KnowledgeGraphConfig"},"currency":{"$ref":"#/components/schemas/CurrencyPolicy"},"ledger_understanding":{"$ref":"#/components/schemas/LedgerUnderstandingConfig","description":"When this workspace understands its general ledger — table and column roles, the journal key and its balance proof, and the integrity battery. A workspace configured before this block existed reads back the default."},"global_context":{"type":"string","title":"Global Context","description":"Standing background for every query in this workspace — how its journals are keyed, which entity it covers, what an auditor already knows. A je-testing or search request that omits `context` runs with this text; a request that sends `context` replaces it for that run, and `\"\"` runs with none. Empty means none. Surrounding whitespace is stripped.","default":""},"config_version":{"type":"integer","title":"Config Version"},"status":{"$ref":"#/components/schemas/WorkspaceStatus"},"purpose":{"anyOf":[{"$ref":"#/components/schemas/WorkspacePurpose"},{"type":"null"}],"description":"Set when the platform provisioned this workspace on a person's behalf rather than at a caller's request. Such a workspace cannot be deleted. Null for every workspace created through this API."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["workspace_id","owner_user_id","share_count","name","domain_id","domain_slug","domain_version","access","knowledge_graph","currency","config_version","status","created_at","updated_at"],"title":"Workspace","description":"A provisioned workspace, as the API returns it.\n\nStorage metadata identifies the durable backend without exposing credentials."},"WorkspaceDeleteJob":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id","description":"Server-minted id. Poll GET /v1/jobs/{job_id} or pass wait_seconds on create."},"kind":{"type":"string","const":"workspace_delete","title":"Kind","default":"workspace_delete"},"status":{"$ref":"#/components/schemas/ndi_service__app__platform_api__contracts__JobStatus","description":"Lifecycle: queued, running, succeeded, failed, or cancelled."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Display name (the console's 'project'). Public Parse, Split, Classify, Extract, and Ground runs supply a stable server default when blank; citation-generated Ground jobs are excluded. mutable via PATCH /v1/jobs/{job_id}."},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id","description":"Caller-minted grouping id shared by jobs submitted together. Filterable on GET /v1/jobs."},"workspace_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id","description":"The workspace this job reads. Null for a document operation whose source is an upload, a URL, or a prior parse result."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Key that was replayed to return this job. Absent when the create call had no Idempotency-Key."},"force":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force","description":"The request's own `force` flag, echoed regardless of outcome. Present for kinds whose request carries one (e.g. kg_build, where a true value cleared the durable store before the job ran) so a caller can tell that apart from a build that failed leaving the prior store untouched — `result` alone cannot, since it is absent on failure either way."},"source":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UploadSource"},{"$ref":"#/components/schemas/UrlSource"},{"$ref":"#/components/schemas/WorkspaceFileSource"},{"$ref":"#/components/schemas/ParseResultSource"}],"discriminator":{"propertyName":"type","mapping":{"parse_result":"#/components/schemas/ParseResultSource","upload":"#/components/schemas/UploadSource","url":"#/components/schemas/UrlSource","workspace_file":"#/components/schemas/WorkspaceFileSource"}}},{"type":"null"}],"title":"Source","description":"What this job read, for the document operations that take a single `source` (parse, split, classify, extract, ground); null for every other kind. Together with `workspace_id` this is what lets a caller re-open the document a past run was about — both `workspace_file` and `upload` sources remain until explicit deletion. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","description":"The question this job was asked, for the search kinds that carry one (intelligent_search, qa_file, qa_tables, filtered_search); null for every other kind. Read from the stored request, so it rides the same retention path as `result`: null once `result_state` leaves `available`. Narrow by design — the frozen access context never reaches the wire. File scope is summarised separately as `query_scope`."},"query_scope":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/WorkspaceQueryScope"},{"$ref":"#/components/schemas/FileQueryScope"},{"$ref":"#/components/schemas/PathPrefixQueryScope"},{"$ref":"#/components/schemas/FilesQueryScope"}],"discriminator":{"propertyName":"type","mapping":{"file":"#/components/schemas/FileQueryScope","files":"#/components/schemas/FilesQueryScope","path_prefix":"#/components/schemas/PathPrefixQueryScope","workspace":"#/components/schemas/WorkspaceQueryScope"}}},{"type":"null"}],"title":"Query Scope","description":"Where this search ran, summarised for history UIs: the whole workspace, one file path, one folder prefix, or a count of files. Null for non-query jobs, filtered-search page continuations, and once `result_state` leaves `available`. Never lists multiple filenames, never the raw request, and never the frozen API-key id."},"effort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effort","description":"How hard this run worked, for the search kinds that carry it. A deep-search job (kind deep_search_v2) created before the effort knob was removed echoes its requested level: 'low', 'medium', or 'high'; newer deep-search jobs, which all run one configuration, read null. An intelligent_search row carries an internal selector instead: 'fast' is fact-search, 'automatic' is automatic-search, and 'deep' (or the legacy 'balanced') is a deep-search or console QA chat job created before the 2026-09 consolidation — those two are not distinguishable by this field. Null for every other kind. Read from the stored request, so it rides the same retention path as `query` and `result`: null once `result_state` leaves `available`."},"surface":{"anyOf":[{"type":"string","enum":["deep_search","qa","workbook"]},{"type":"null"}],"title":"Surface","description":"Which console history this deep-search job belongs to. `deep_search` is the public route and the Deep Search page; `qa` and `workbook` are the console chat skins over the same agent. It does not pick the implementation. Null for fact-search and every non-deep-search kind. Jobs stored before this field existed echo `deep_search`. Read from the stored payload, so it rides the same retention path as `query`."},"progress":{"anyOf":[{"$ref":"#/components/schemas/JobProgress"},{"type":"null"}],"description":"Live progress while the job is running. Null while queued and after the job finishes."},"result":{"anyOf":[{"$ref":"#/components/schemas/WorkspaceDeleteResult"},{"type":"null"}],"description":"Present only on succeeded, and only while retained."},"result_state":{"$ref":"#/components/schemas/ResultState","description":"Why result may be null. storage_unavailable means its workspace binding currently refuses content access; available with a null result means the job has not succeeded yet; expired and not_retained mean the payload was dropped by retention; cancelled means the job, or the job it ran for, was cancelled, so no result is served (a job cancelled before completion is not charged).","default":"available"},"result_error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Current storage refusal withholding content. Separate from the recorded job outcome; cleared when access returns."},"error":{"anyOf":[{"$ref":"#/components/schemas/Error"},{"type":"null"}],"description":"Typed failure envelope when status is failed. Null on any other status, and while result_error withholds content."},"units":{"type":"integer","title":"Units","description":"Measured work in legacy credit units, retained even when a failed or cancelled job is not billed. Kept for compatibility: `credits` is the authoritative billed amount.","default":0},"credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits","description":"Final credits billed for this job, priced once under `credit_schedule_version`. Null until `usage_final` is true. Never changes afterwards, including after payload expiry or deletion. Failed and cancelled-before-completion jobs finalize with 0 credits, including delivered parts; ones finalized before that policy keep their credits. Always null on a stage job that Automatic Search delegated: its work is billed on the parent job."},"usage_final":{"type":"boolean","title":"Usage Final","description":"True once `credits` is final and will not change. False while the job is queued or running, and until any cleanup of its delegated stages has been accounted for. A failed tool job (read_file, run_sql, hybrid_search, grep, file_metadata, folder_metadata) created with an Idempotency-Key stays false for one hour after it fails, because a retry with the same key re-runs it; after that hour it is final and the retry returns the stored error.","default":false},"credit_schedule_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credit Schedule Version","description":"Version of the credit schedule `credits` were priced under. Null until `usage_final` is true."},"usage_finalized_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Usage Finalized At","description":"When `credits` became final. Null until `usage_final` is true."},"cost":{"anyOf":[{"$ref":"#/components/schemas/JobCost"},{"type":"null"}],"description":"Final USD component prices under the sheet pinned at acceptance; null before finalization or when no dollar sheet was configured. Does not change legacy credit billing."},"usage":{"anyOf":[{"$ref":"#/components/schemas/JobUsage"},{"type":"null"}],"description":"What `credits` were charged for: one line per part (the parse, the tool's own work), with the quantity, rate and multiplier behind each. Null until `usage_final` is true, and on jobs finalized before usage breakdowns were introduced."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the job row was created."},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At","description":"When execution began. Null while still queued."},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At","description":"When the job reached a terminal status."},"payload_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Payload Expires At","description":"Cleanup deadline after explicit deletion. Null for retained content; Zero retention uses its delivery window."},"deleted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deleted At","description":"When the caller hid this run from listings, via `delete_job`. A soft delete: the job still reads by id and still counts toward `GET /v1/usage` — what it stops doing is appearing in `GET /v1/jobs`."}},"additionalProperties":false,"type":"object","required":["job_id","status","created_at"],"title":"WorkspaceDeleteJob"},"WorkspaceDeleteResult":{"properties":{"result_type":{"type":"string","const":"workspace_delete","title":"Result Type","default":"workspace_delete"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id"},"files_deleted":{"type":"integer","title":"Files Deleted","default":0},"index_documents_deleted":{"type":"integer","title":"Index Documents Deleted","default":0},"kg_nodes_deleted":{"type":"integer","title":"Kg Nodes Deleted","default":0},"prefix_deleted":{"type":"boolean","title":"Prefix Deleted","default":false},"verified":{"type":"boolean","title":"Verified","default":false}},"additionalProperties":false,"type":"object","required":["workspace_id"],"title":"WorkspaceDeleteResult","description":"Hard tenant deletion: storage prefix, indexes, and graph."},"WorkspaceFileSource":{"properties":{"type":{"type":"string","const":"workspace_file","title":"Type","default":"workspace_file"},"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id","description":"Workspace that owns the file."},"file_id":{"type":"string","format":"uuid","title":"File Id","description":"File id from GET /v1/workspaces/{workspace_id}/files."}},"additionalProperties":false,"type":"object","required":["workspace_id","file_id"],"title":"WorkspaceFileSource","description":"A file already in a workspace.\n\nThe single seam between the two contexts: a granular operation may read a\nworkspace file and still write nothing back. The file need **not** be\ningested — granular operations read source bytes, not representations."},"WorkspacePurpose":{"type":"string","enum":["perception_playground"],"title":"WorkspacePurpose","description":"Why the platform provisioned a workspace nobody asked for.\n\nA purposed workspace is platform-managed: it is created on a person's\nbehalf and it refuses deletion, so a caller can tell from a list response\nwhich row will answer 409 rather than discovering it by trying."},"WorkspaceQueryScope":{"properties":{"type":{"type":"string","const":"workspace","title":"Type","default":"workspace"}},"additionalProperties":false,"type":"object","title":"WorkspaceQueryScope","description":"The question ran against the whole workspace."},"WorkspaceShares":{"properties":{"workspace_id":{"type":"string","format":"uuid","title":"Workspace Id","description":"Workspace whose sharing configuration this response describes."},"owner_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Owner User Id","description":"Console user who owns the workspace, or null for an organization-owned integration workspace."},"user_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"User Ids","description":"Console users with explicit access to the workspace; excludes the owner."}},"additionalProperties":false,"type":"object","required":["workspace_id","owner_user_id","user_ids"],"title":"WorkspaceShares","description":"The owner and explicit users who may access one workspace."},"WorkspaceStats":{"properties":{"files_total":{"type":"integer","title":"Files Total"},"files_by_ingestion_status":{"additionalProperties":{"type":"integer"},"propertyNames":{"$ref":"#/components/schemas/IngestionStatus"},"type":"object","title":"Files By Ingestion Status"},"bytes_total":{"type":"integer","title":"Bytes Total"},"pages_ingested":{"type":"integer","title":"Pages Ingested"},"index_documents":{"type":"integer","title":"Index Documents"},"kg_nodes":{"type":"integer","title":"Kg Nodes","description":"Nodes in the workspace's published knowledge graph; 0 when none is built."},"kg_edges":{"type":"integer","title":"Kg Edges","description":"Edges in the workspace's published knowledge graph; 0 when none is built."},"last_ingestion_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Ingestion At"},"last_reconciliation_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Reconciliation At"},"next_expiry_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Expiry At","description":"Earliest artifact ``expires_at``; null when nothing expires."},"files_expiring_within_7d":{"type":"integer","title":"Files Expiring Within 7D"}},"additionalProperties":false,"type":"object","required":["files_total","files_by_ingestion_status","bytes_total","pages_ingested","index_documents","kg_nodes","kg_edges","last_ingestion_at","last_reconciliation_at","next_expiry_at","files_expiring_within_7d"],"title":"WorkspaceStats","description":"Per-workspace content summary.\n\n``files_by_ingestion_status`` is the completeness instrument: a caller does\nnot need to page through ``list_files`` to know whether anything is stale.\n``stale > 0`` means observed and ingested hashes diverged — call\n``POST .../ingestions`` with ``stale_only=true`` to catch up.  ``expired >\n0`` means derived representations were dropped by retention; a re-ingest is\nneeded to make those files searchable again."},"WorkspaceStatus":{"type":"string","enum":["active","deleting"],"title":"WorkspaceStatus","description":"Lifecycle states visible on the API surface.\n\n``deleted`` is a final internal state; a deleted workspace never appears in\nany list or ``get`` response — it is as if it never existed."},"ndi_service__app__platform_api__contracts__JobStatus":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"title":"JobStatus","description":"``cancelled`` is a first-class terminal status, not a ``failed`` variant.\n\nConflating them makes error-rate metrics lie and forces every client to\nstring-match an error code."},"ndi_service__app__platform_api__document_operations__schemas__ExtractSchemaValidationRequest":{"properties":{"schema_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schema Id","description":"Catalog schema family id (sch_...). Mutually exclusive with an inline schema."},"schema_version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Schema Version","description":"Pin a published catalog version. Omit with schema_id to use the latest version."},"schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Schema","description":"Inline JSON Schema to validate. Mutually exclusive with schema_id."}},"additionalProperties":false,"type":"object","title":"ExtractSchemaValidationRequest","description":"Body for ``POST /v1/extract/schema-validation``.\n\nSame mutual-exclusion rule as :class:`ExtractRequest`: exactly one of\n``schema_id`` or ``schema`` must be present. Optional ``schema_version``\npins a registry version when resolving ``schema_id``."},"ndi_service__app__platform_api__document_operations__schemas__ExtractSchemaValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid","description":"True when the schema can be used as an extract schema."},"errors":{"items":{"$ref":"#/components/schemas/SchemaError"},"type":"array","title":"Errors","description":"Every validation violation found. Empty when valid is true."},"normalized_schema":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Normalized Schema","description":"Compiled schema when valid is true. Null when the input was rejected."}},"additionalProperties":false,"type":"object","required":["valid"],"title":"ExtractSchemaValidationResponse","description":"Result of ``POST /v1/extract/schema-validation``.\n\nOn a valid schema, ``valid=True`` and ``normalized_schema`` carries the\ncompiled form.  On an invalid schema, ``valid=False`` and ``errors``\nlists every violation found — the whole list, not just the first."},"ndi_service__app__platform_api__document_operations__schemas__GroundOptions":{"properties":{"max_matches":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Max Matches","description":"Maximum matches to return per target, ranked best-first. An HTML source is capped the same way, but only visible rendered text is matched: text hidden by its own style attribute, a hidden or aria-hidden attribute, or an unopened <dialog> is never returned. Hiding that comes from a stylesheet or a media query is not evaluated. A hint ranks the visible occurrence nearest that nearby text first; without a hint, rank 1 is the first visible occurrence.","default":10},"minimum_semantic_score":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Minimum Semantic Score","description":"Deprecated minimum score for semantic and model-scored matches. The exact-match PDF, Word and PowerPoint runtime ignores it: a semantic pick there is kept only when the model rates it above no answer. Exact and normalized matches are unaffected."},"include_previews":{"type":"boolean","title":"Include Previews","description":"When true, matches include cropped_image_url for visual regions. Fetch with the same API key.","default":false},"require_visual_region":{"type":"boolean","title":"Require Visual Region","description":"When true, only matches that have a visual region are kept. Not supported by the current runtime.","default":false},"use_word_level_grounding":{"type":"boolean","title":"Use Word Level Grounding","description":"Experimental. Match targets against word-level OCR bboxes. PDF sources only. Targets shorter than 2 normalized characters return status failed with error needle_too_short.","default":false}},"additionalProperties":false,"type":"object","title":"GroundOptions"},"ndi_service__app__platform_api__document_operations__schemas__UploadResponse":{"properties":{"upload_id":{"type":"string","format":"uuid","title":"Upload Id","description":"Handle to pass as source.upload_id on a later document operation."},"file_name":{"type":"string","title":"File Name","description":"Original filename as received."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Byte length of the staged file, after upload completes."},"content_hash":{"type":"string","title":"Content Hash","description":"SHA-256 hex digest of the staged bytes. Confirms the upload is the file you sent, not a workspace file id."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Zero retention cleanup deadline; null for ordinary uploads kept until explicit deletion."}},"additionalProperties":false,"type":"object","required":["upload_id","file_name","size_bytes","content_hash","expires_at"],"title":"UploadResponse","description":"Returned by ``POST /v1/uploads`` on success.\n\n``upload_id`` is the handle passed to :class:`~ndi_service.app.platform_api.contracts.UploadSource`.\nOrdinary bytes stay until explicit deletion; Zero retention remains separate."},"ndi_service__app__platform_api__domains__schemas__Taxonomy":{"properties":{"classes":{"items":{"$ref":"#/components/schemas/TaxonomyClass"},"type":"array","maxItems":400,"title":"Classes"},"allow_other":{"type":"boolean","const":true,"title":"Allow Other","description":"Cannot be disabled: a document that fits nothing is labelled 'other', never force-fitted.","default":true}},"additionalProperties":false,"type":"object","title":"Taxonomy","description":"The classification vocabulary."},"ndi_service__app__platform_api__operations__schemas__UsageResponse":{"properties":{"period_start":{"type":"string","format":"date","title":"Period Start"},"period_end":{"type":"string","format":"date","title":"Period End"},"group_by":{"type":"string","title":"Group By"},"buckets":{"items":{"$ref":"#/components/schemas/UsageBucket"},"type":"array","title":"Buckets"},"units_total":{"type":"integer","title":"Units Total"},"credits_total":{"type":"integer","title":"Credits Total","description":"Sum of `credits` across all buckets: final credits for the period."}},"additionalProperties":false,"type":"object","required":["period_start","period_end","group_by","buckets","units_total","credits_total"],"title":"UsageResponse","description":"Usage report covering ``[period_start, period_end]``.\n\n``units_total`` sums measured work, including free failed and cancelled jobs.\n``credits_total`` sums final billable credits for the period."},"ndi_service__app__platform_api__results__CategorizeResult":{"properties":{"result_type":{"type":"string","const":"categorize","title":"Result Type","default":"categorize"},"assignments":{"items":{"$ref":"#/components/schemas/CategoryAssignment"},"type":"array","title":"Assignments"},"units":{"type":"integer","title":"Units"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Parse settings this run accepted but did not apply, each naming the setting and why, for example a page selection on a file with no pages. Left out when empty."}},"additionalProperties":false,"type":"object","required":["assignments","units"],"title":"CategorizeResult"},"ndi_service__app__platform_api__results__ExtractResult":{"properties":{"result_type":{"type":"string","const":"extract","title":"Result Type","default":"extract"},"enrichment_status":{"type":"string","enum":["pending","complete","degraded"],"title":"Enrichment Status","description":"Pending means values are available while citations and other enrichment are still running. Complete means enrichment finished; degraded means it finished with a reported enrichment failure. Always read the job status for cancellation or failure.","default":"complete"},"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Object shaped by the request schema. Missing values are null, not omitted."},"fields":{"items":{"$ref":"#/components/schemas/ExtractedField"},"type":"array","title":"Fields","description":"One entry per schema field, including not_found. A missing value is never silently dropped."},"schema_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schema Id","description":"Catalog schema family id when a registry schema was used."},"schema_version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Schema Version","description":"Catalog version that was frozen at accept time."},"converted_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Converted Pdf Url","description":"Authenticated PDF preview used to measure citation regions for an office source."},"units":{"type":"integer","title":"Units","description":"Measured work units for this extraction. The job's `credits` is the final billed amount."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Non-fatal notes about the request, e.g. instructions no schema field can satisfy."},"disclosures":{"items":{"oneOf":[{"$ref":"#/components/schemas/ClassificationGapFillDisclosure"},{"$ref":"#/components/schemas/ClassificationUnreadPagesDisclosure"},{"$ref":"#/components/schemas/ExtractionNullOnSuccessDisclosure"},{"$ref":"#/components/schemas/ParseVendorProvenanceDisclosure"},{"$ref":"#/components/schemas/ParseFidelityDisclosure"},{"$ref":"#/components/schemas/ContentTruncatedDisclosure"},{"$ref":"#/components/schemas/SourceIncompleteDisclosure"}],"discriminator":{"propertyName":"code","mapping":{"classification_gap_fill":"#/components/schemas/ClassificationGapFillDisclosure","classification_unread_pages":"#/components/schemas/ClassificationUnreadPagesDisclosure","content_truncated":"#/components/schemas/ContentTruncatedDisclosure","extraction_null_on_success":"#/components/schemas/ExtractionNullOnSuccessDisclosure","parse_fidelity":"#/components/schemas/ParseFidelityDisclosure","parse_vendor_provenance":"#/components/schemas/ParseVendorProvenanceDisclosure","source_incomplete":"#/components/schemas/SourceIncompleteDisclosure"}}},"type":"array","title":"Disclosures","description":"Structured signals about how this result was produced. Empty when all behaviours matched what the caller would assume without them."},"unrefined_field_paths":{"items":{"type":"string"},"type":"array","title":"Unrefined Field Paths","description":"JSON paths of found fields whose citation does not point at the exact line the value was read from: it is a broader document region, or absent. The values are correct. The exact location could not be measured, for example because the quote's words are laid out differently on the page than in the text, or the value is printed identically in several places and nothing said which one. A value is never boxed at its first occurrence instead. Empty when citations are off."}},"additionalProperties":false,"type":"object","required":["fields","units"],"title":"ExtractResult"},"ndi_service__app__platform_api__results__GroundResult":{"properties":{"result_type":{"type":"string","const":"ground","title":"Result Type","default":"ground"},"targets":{"items":{"$ref":"#/components/schemas/GroundTargetResult"},"type":"array","title":"Targets","description":"One result per request target, in request order."},"units":{"type":"integer","title":"Units","description":"Measured work units for this ground job. The job's `credits` is the final billed amount."},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url","description":"Storage URL of the MediaTimeline JSON used for grounding."},"converted_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Converted Pdf Url","description":"PDF the office source was converted to before grounding. Match regions are measured on this PDF. Null when the source was already a PDF or did not need conversion."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Parse settings this run accepted but did not apply, each naming the setting and why, for example a page selection on a file with no pages. Left out when empty."}},"additionalProperties":false,"type":"object","required":["targets","units"],"title":"GroundResult"},"ndi_service__app__platform_api__results__ParseResult":{"properties":{"result_type":{"type":"string","const":"parse","title":"Result Type","default":"parse"},"file_name":{"type":"string","title":"File Name","description":"Source filename recorded for this run."},"lane":{"type":"string","title":"Lane","description":"Which parser lane produced this payload, for example document or spreadsheet."},"document":{"$ref":"#/components/schemas/ParseDocument","description":"Parsed text, blocks, chunks, and optional spreadsheet sidecars."},"ocr_applied":{"type":"boolean","title":"Ocr Applied","description":"True when OCR actually ran, regardless of the requested ocr.mode."},"units":{"type":"integer","title":"Units","description":"Measured work units for this parse, typically one per page. The job's `credits` is the final billed amount."},"converted_pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Converted Pdf Url","description":"PDF the office source was converted to before parsing. Block geometry is measured on this PDF. Null when the source was already a PDF or did not need conversion."},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url","description":"Authenticated job-scoped MediaTimeline JSON for audio/video. Null for non-media and historical jobs."},"transcript":{"anyOf":[{"$ref":"#/components/schemas/MediaTimeline"},{"type":"null"}],"description":"Inline MediaTimeline for audio/video so the console JSON tab can show segments. Null for non-media, historical jobs, and list responses."},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"Parse settings this run accepted but did not apply, each naming the setting and why, for example a page selection on a file with no pages. Left out when empty."},"disclosures":{"items":{"oneOf":[{"$ref":"#/components/schemas/ClassificationGapFillDisclosure"},{"$ref":"#/components/schemas/ClassificationUnreadPagesDisclosure"},{"$ref":"#/components/schemas/ExtractionNullOnSuccessDisclosure"},{"$ref":"#/components/schemas/ParseVendorProvenanceDisclosure"},{"$ref":"#/components/schemas/ParseFidelityDisclosure"},{"$ref":"#/components/schemas/ContentTruncatedDisclosure"},{"$ref":"#/components/schemas/SourceIncompleteDisclosure"}],"discriminator":{"propertyName":"code","mapping":{"classification_gap_fill":"#/components/schemas/ClassificationGapFillDisclosure","classification_unread_pages":"#/components/schemas/ClassificationUnreadPagesDisclosure","content_truncated":"#/components/schemas/ContentTruncatedDisclosure","extraction_null_on_success":"#/components/schemas/ExtractionNullOnSuccessDisclosure","parse_fidelity":"#/components/schemas/ParseFidelityDisclosure","parse_vendor_provenance":"#/components/schemas/ParseVendorProvenanceDisclosure","source_incomplete":"#/components/schemas/SourceIncompleteDisclosure"}}},"type":"array","title":"Disclosures","description":"Structured signals about how this result was produced. Empty when all behaviours matched what the caller would assume without them."}},"additionalProperties":false,"type":"object","required":["file_name","lane","document","ocr_applied","units"],"title":"ParseResult"},"ndi_service__app__schemas__public__CategorizeResult":{"properties":{"result_type":{"type":"string","const":"categorize","title":"Result Type","default":"categorize"},"status":{"type":"string","enum":["success","failed"],"title":"Status","default":"success"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"items":{"items":{"oneOf":[{"$ref":"#/components/schemas/CategorizedSegment"},{"$ref":"#/components/schemas/CategorizedSheet"}],"discriminator":{"propertyName":"kind","mapping":{"document_segment":"#/components/schemas/CategorizedSegment","sheet":"#/components/schemas/CategorizedSheet"}}},"type":"array","title":"Items"}},"type":"object","title":"CategorizeResult"},"ndi_service__app__schemas__public__ExtractResult":{"properties":{"result_type":{"type":"string","const":"extract","title":"Result Type","default":"extract"},"status":{"type":"string","enum":["success","failed"],"title":"Status","default":"success"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"data":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object"},{"type":"null"}],"title":"Data","description":"Extracted values matching the request schema. Fields the document does not contain are null (scalars) or empty arrays."},"json_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Json Url","description":"URL of the extraction JSON artifact (same content as ``data``)."},"page_count":{"type":"integer","title":"Page Count","default":0},"sheet_count":{"type":"integer","title":"Sheet Count","default":0}},"type":"object","title":"ExtractResult"},"ndi_service__app__schemas__public__ExtractSchemaValidationRequest":{"properties":{"schema":{"additionalProperties":{"$ref":"#/components/schemas/JsonValue"},"type":"object","title":"Schema","description":"JSON Schema describing the data to extract. Root must be an object with properties; nesting is bounded; composition keywords ($ref/anyOf/oneOf/allOf/not) are not supported. A field may use one type string or a nullable two-member type such as [\"string\", \"null\"]. Closed objects may use additionalProperties: false; true or schema-valued additionalProperties are not supported. Field descriptions directly guide extraction accuracy. Top-level arrays are extracted segment-by-segment across long documents and concatenated.","examples":[{"additionalProperties":false,"properties":{"invoice_number":{"description":"Invoice identifier.","type":"string"},"inspection_year":{"description":"Inspection year, or null when the document does not establish one.","type":["integer","null"]}},"type":"object"}]}},"additionalProperties":false,"type":"object","required":["schema"],"title":"ExtractSchemaValidationRequest","description":"Body for ``POST /extract/schema/validate``."},"ndi_service__app__schemas__public__ExtractSchemaValidationResponse":{"properties":{"valid":{"type":"boolean","const":true,"title":"Valid","default":true}},"additionalProperties":false,"type":"object","title":"ExtractSchemaValidationResponse","description":"Successful Extract schema preflight response."},"ndi_service__app__schemas__public__GroundOptions":{"properties":{"confidence_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence Threshold","description":"Minimum confidence to include a match.","default":0.5},"return_cropped_images":{"type":"boolean","title":"Return Cropped Images","description":"Also upload cropped images of visual matches.","default":false},"use_word_level_grounding":{"type":"boolean","title":"Use Word Level Grounding","description":"Experimental. PDF sources only. Deterministic word-level grounding. Targets under 2 normalized characters return status failed with error needle_too_short.","default":false}},"additionalProperties":false,"type":"object","title":"GroundOptions","description":"Caller-tunable grounding options. Providers and model settings are server-owned."},"ndi_service__app__schemas__public__GroundResult":{"properties":{"result_type":{"type":"string","const":"ground","title":"Result Type","default":"ground"},"results":{"items":{"$ref":"#/components/schemas/GroundItemResult"},"type":"array","title":"Results"},"total_items_found":{"type":"integer","title":"Total Items Found","default":0},"total_items_requested":{"type":"integer","title":"Total Items Requested","default":0},"duration_ms":{"type":"integer","title":"Duration Ms","default":0},"transcript_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcript Url","description":"Storage URL of the MediaTimeline JSON used for grounding."}},"type":"object","title":"GroundResult"},"ndi_service__app__schemas__public__JobStatus":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"},"action":{"type":"string","title":"Action","description":"One of ``parse``/``ground``/``categorize``/``extract``."},"status":{"type":"string","title":"Status","description":"One of ``pending``/``running``/``succeeded``/``failed``."},"result":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/ndi_service__app__schemas__public__ParseResult"},{"$ref":"#/components/schemas/ndi_service__app__schemas__public__GroundResult"},{"$ref":"#/components/schemas/ndi_service__app__schemas__public__CategorizeResult"},{"$ref":"#/components/schemas/ndi_service__app__schemas__public__ExtractResult"}],"discriminator":{"propertyName":"result_type","mapping":{"categorize":"#/components/schemas/ndi_service__app__schemas__public__CategorizeResult","extract":"#/components/schemas/ndi_service__app__schemas__public__ExtractResult","ground":"#/components/schemas/ndi_service__app__schemas__public__GroundResult","parse":"#/components/schemas/ndi_service__app__schemas__public__ParseResult"}}},{"type":"null"}],"title":"Result","description":"Action-specific result (tagged by ``result_type``); populated only when ``status=succeeded``."},"error":{"anyOf":[{"$ref":"#/components/schemas/JobError"},{"type":"null"}],"description":"Set only when ``status=failed``."},"is_example":{"type":"boolean","title":"Is Example","description":"True for provisioned Playground example jobs.","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"credits_used":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits Used","description":"Credits charged to this job per the ledger. 0 for failed/cancelled jobs (never charged) and zero-credit example jobs; null while the job is non-terminal (not counted yet) or for a succeeded job predating the ledger."}},"type":"object","required":["job_id","action","status","created_at"],"title":"JobStatus","description":"Response for ``GET /jobs/{job_id}`` and the sync endpoints."},"ndi_service__app__schemas__public__ParseResult":{"properties":{"result_type":{"type":"string","const":"parse","title":"Result Type","default":"parse"},"status":{"type":"string","enum":["success","failed"],"title":"Status","default":"success"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"item":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/ParsedFile"},{"$ref":"#/components/schemas/ParsedTable"}],"discriminator":{"propertyName":"item_type","mapping":{"file":"#/components/schemas/ParsedFile","table":"#/components/schemas/ParsedTable"}}},{"type":"null"}],"title":"Item"}},"type":"object","title":"ParseResult"},"ndi_service__app__schemas__public__Taxonomy":{"properties":{"categories":{"items":{"$ref":"#/components/schemas/TaxonomyCategory"},"type":"array","minItems":1,"title":"Categories"},"allow_freeform":{"type":"boolean","title":"Allow Freeform","description":"When true, NDI exposes a reserved top-level 'other' category and may return generated subcategories under it. When false, every result must match a provided subcategory.","default":false}},"additionalProperties":false,"type":"object","required":["categories"],"title":"Taxonomy"},"ndi_service__app__schemas__public__UploadResponse":{"properties":{"file_id":{"type":"string","format":"uuid","title":"File Id"},"file_name":{"type":"string","title":"File Name"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"additionalProperties":false,"type":"object","required":["file_id","file_name","expires_at"],"title":"UploadResponse","description":"Returned by ``POST /upload``: an opaque handle for later job starts."},"ndi_service__app__schemas__public__UsageResponse":{"properties":{"included_credits":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Included Credits","description":"Lifetime credit allowance; null means unlimited."},"credits_used":{"type":"integer","title":"Credits Used","description":"Finalized credit-equivalent resource consumption, including unbilled failures and cancellations."},"credits_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits Remaining","description":"Allowance minus usage, floored at 0; null when the allowance is unlimited."}},"type":"object","required":["credits_used"],"title":"UsageResponse","description":"Response for ``GET /usage`` (and ``GET /console/usage``).\n\nResource consumption is summed after finalization, including free failed or\ncancelled work and excluding reuse waivers. Work in flight is not counted:\nthis is the same view the legacy 402 gate sees. It is not a customer bill;\n``/v1/usage`` reports final billable ``credits_total`` separately."}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"},"HTTPBearer":{"type":"http","description":"OIDC access token from the console sign-in.","scheme":"bearer"},"UploadGrantHeader":{"type":"apiKey","description":"Short-lived upload grant from POST /v1/workspaces/{workspace_id}/upload-grants.","in":"header","name":"X-Upload-Token"},"UploadSessionTokenHeader":{"type":"apiKey","description":"Session token from POST /v1/workspaces/{workspace_id}/upload-sessions.","in":"header","name":"X-Upload-Token"}}}}