{"openapi":"3.1.0","info":{"title":"Talonic API","version":"1.0.0","description":"Structure any document into schema-validated data.\n\nThe Talonic API lets you extract structured data from documents (PDFs, images,\nDOCX, CSV, plain text), manage reusable extraction schemas, track async jobs,\nand organise documents through sources.\n\n## Quick Start\n\n**1. Get your API key**\n\nSign up at [app.talonic.com](https://app.talonic.com) → Settings → API Keys → Create key.\nKeys start with `tlnc_`. All examples below use `tlnc_live_abc123` as a placeholder.\n\n**2. Extract your first document**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n  -H \"Authorization: Bearer tlnc_live_abc123\" \\\n  -F \"file=@invoice.pdf\" \\\n  -F 'schema={\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}'\n```\n\n**Python:**\n```python\nimport requests\nresp = requests.post(\"https://api.talonic.com/v1/extract\",\n    headers={\"Authorization\": \"Bearer tlnc_live_abc123\"},\n    files={\"file\": open(\"invoice.pdf\", \"rb\")},\n    data={\"schema\": '{\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}'})\nprint(resp.json()[\"data\"])\n```\n\n**TypeScript:**\n```typescript\nconst form = new FormData();\nform.append(\"file\", fs.createReadStream(\"invoice.pdf\"));\nform.append(\"schema\", '{\"properties\":{\"vendor_name\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"},\"invoice_date\":{\"type\":\"string\"}}}');\nconst res = await fetch(\"https://api.talonic.com/v1/extract\", {\n  method: \"POST\",\n  headers: { Authorization: \"Bearer tlnc_live_abc123\" },\n  body: form,\n}).then(r => r.json());\nconsole.log(res.data);\n```\n\n**3. What you get back**\n\n```json\n{\n  \"extraction_id\": \"d1a2b3c4-5678-9abc-def0-1234567890ab\",\n  \"request_id\": \"req_x7y8z9a0b1c2d3e4\",\n  \"status\": \"complete\",\n  \"document\": {\n    \"id\": \"f0e1d2c3-b4a5-9687-8765-432109876543\",\n    \"filename\": \"invoice.pdf\",\n    \"pages\": 2,\n    \"size_bytes\": 184320,\n    \"type_detected\": \"Invoice\",\n    \"language_detected\": \"en\"\n  },\n  \"data\": {\n    \"vendor_name\": \"Acme GmbH\",\n    \"total_amount\": 14250.00,\n    \"invoice_date\": \"2025-03-15\"\n  },\n  \"confidence\": {\n    \"overall\": 0.96,\n    \"fields\": {\n      \"vendor_name\": 0.97,\n      \"total_amount\": 0.94,\n      \"invoice_date\": 0.99\n    }\n  },\n  \"processing\": {\n    \"duration_ms\": 1840,\n    \"pages_processed\": 2,\n    \"region\": \"eu-west\"\n  },\n  \"links\": {\n    \"self\": \"/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab\",\n    \"document\": \"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543\"\n  }\n}\n```\n\n- **`data`** — extracted fields as key-value pairs matching your schema.\n- **`confidence.fields`** — per-field score from 0 to 1. Above 0.9 is high confidence; below 0.7 flags for review.\n- **`extraction_id`** — use this to retrieve, correct, or deliver results later.\n- Full response schema: [ExtractSyncResponse](#/components/schemas/ExtractSyncResponse)\n\n**4. Next steps**\n\n- **50+ pages?** Use async mode — see [Async Extraction Flow](#section/Async-Extraction-Flow) below.\n- **Reusable schemas** — save field definitions with `POST /v1/schemas`, then pass `schema_id` on future extractions.\n- **Receive results via webhook** — configure a delivery destination and listen for `document.extracted` events. See the [Delivery](#tag/Delivery) tag.\n\n---\n\n## Authentication\n\nAll requests require a Bearer token in the `Authorization` header.\nAPI keys are prefixed with `tlnc_` and scoped per customer.\n\n```\nAuthorization: Bearer tlnc_live_abc123...\n```\n\n## Async Extraction Pattern\n\nSmall documents (≤5 pages) are processed synchronously and return a `200`\nwith the extracted data immediately. Larger documents return a `202 Accepted`\nwith a `poll_url` — poll `GET /v1/documents/{id}` until `status` transitions\nto `completed`, then fetch results via `GET /v1/documents/{id}/extractions`.\n\nYou can force async processing by passing `options: {\"async\": true}` on\nany extraction request. Combine with webhooks for a fully event-driven flow:\nconfigure a webhook destination under Delivery and listen for the\n`extraction.complete` event.\n\n**Job status lifecycle:** `pending` → `processing` → `complete` | `failed`\n\n## Rate Limits\n\nThe **Free** tier is metered by a recurring **5,000-credit monthly grant**\n(no card required) that refreshes on the 1st of each month (UTC). Free\nrequests run until the monthly credit balance is spent, then return `402`\nuntil the next grant. A generous daily request ceiling is retained purely as\nabuse protection and does not bind a legitimate free user within the monthly\nenvelope. Inspect your balance and reset date via `GET /v1/account`.\n\nPaid tiers are metered per calendar day (UTC):\n\n| Tier       | Extract | Platform | Ingest |\n|------------|---------|----------|--------|\n| Free       | 5,000 credits/month | 5,000 credits/month | 5,000 credits/month |\n| Pro        | 2,000/day | 10,000/day | 2,000/day |\n| Enterprise | Unlimited | Unlimited | Unlimited |\n\nEvery response includes rate-limit headers:\n- `X-RateLimit-Limit` — daily cap for the namespace\n- `X-RateLimit-Remaining` — requests left today\n- `X-RateLimit-Reset` — ISO 8601 timestamp when the window resets (midnight UTC)\n\n## Pagination\n\nList endpoints use cursor-based pagination. Pass `limit` (1–100, default 20),\n`cursor` (opaque token from `pagination.next_cursor`), and `order` (`asc` or `desc`, default `desc`).\n\n## Errors\n\nAll errors return a JSON body with `error` (machine-readable code) and `message`\n(human-readable explanation). Additional fields vary by error type.\n\n| Code | Error              | Description                              |\n|------|--------------------|------------------------------------------|\n| 400  | validation_error   | Request body is malformed or invalid     |\n| 401  | unauthorized       | Missing or invalid API key               |\n| 403  | insufficient_scope | API key lacks the required scope         |\n| 404  | not_found          | Resource does not exist                  |\n| 409  | conflict           | Resource state conflict                  |\n| 413  | payload_too_large  | File exceeds 500 MB limit                |\n| 422  | extraction_failed  | Document could not be processed          |\n| 429  | rate_limit_exceeded| Daily rate limit reached                 |\n| 500  | internal_error     | Unexpected server error (retryable)      |\n\nEvery error response follows this envelope:\n\n```json\n{\n  \"statusCode\": 400,\n  \"code\": \"VALIDATION_ERROR\",\n  \"error\": \"Bad Request\",\n  \"message\": \"name is required.\",\n  \"retryable\": false,\n  \"timestamp\": \"2026-04-25T14:30:00.000Z\",\n  \"path\": \"/v1/schemas\"\n}\n```\n\nThe `code` field is one of: `VALIDATION_ERROR`, `AUTH_REQUIRED`, `TOKEN_EXPIRED`,\n`INSUFFICIENT_PERMISSIONS`, `RESOURCE_NOT_FOUND`, `QUOTA_EXCEEDED`,\n`INSUFFICIENT_CREDITS`, `LLM_RATE_LIMITED`, `LLM_TIMEOUT`, `LLM_UNAVAILABLE`,\n`OCR_FAILED`, `EXTRACTION_FAILED`, `EXTRACTION_TIMEOUT`, `FILE_TOO_LARGE`,\n`DUPLICATE_RESOURCE`, `DATASPACE_RUN_FAILED`, `INTERNAL_ERROR`.\n\n## Async Extraction Flow\n\nDocuments ≤5 pages return results synchronously (`200`). Larger documents\n— or any request with `options: {\"async\": true}` — return `202 Accepted`.\n\n**1. Submit extraction:**\n\n```bash\ncurl -X POST https://api.talonic.com/v1/extract \\\n  -H \"Authorization: Bearer tlnc_live_abc123\" \\\n  -F \"file=@contract.pdf\" \\\n  -F 'options={\"async\": true}'\n```\n\nResponse `202`:\n```json\n{\n  \"request_id\": \"req_x7y8z9a0\",\n  \"status\": \"processing\",\n  \"document\": { \"id\": \"f0e1d2c3-b4a5-9687-8765-432109876543\" },\n  \"poll_url\": \"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543\"\n}\n```\n\n**2. Poll until complete:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543 \\\n  -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\nWhile processing: `{ \"status\": \"processing\" }`\nWhen done: `{ \"status\": \"completed\" }`\n\n**3. Retrieve results:**\n\n```bash\ncurl https://api.talonic.com/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions \\\n  -H \"Authorization: Bearer tlnc_live_abc123\"\n```\n\n**Python — complete async flow with exponential backoff:**\n\n```python\nimport time\nimport requests\n\nAPI_KEY = \"tlnc_live_...\"\nBASE = \"https://api.talonic.com/v1\"\nHEADERS = {\"Authorization\": f\"Bearer {API_KEY}\"}\n\n# Step 1: Submit async extraction\nresp = requests.post(f\"{BASE}/extract\",\n    headers=HEADERS,\n    files={\"file\": open(\"contract.pdf\", \"rb\")},\n    data={\"options\": '{\"async\": true}'})\ndoc_id = resp.json()[\"document\"][\"id\"]\n\n# Step 2: Poll with exponential backoff (2s → 4s → 8s → 16s → 30s cap)\ndelay = 2\nfor _ in range(20):\n    time.sleep(delay)\n    doc = requests.get(f\"{BASE}/documents/{doc_id}\", headers=HEADERS).json()\n    if doc[\"status\"] == \"completed\":\n        break\n    if doc[\"status\"] == \"error\":\n        raise Exception(f\"Extraction failed: {doc.get('error')}\")\n    delay = min(delay * 2, 30)\n\n# Step 3: Retrieve extracted data\nextractions = requests.get(\n    f\"{BASE}/documents/{doc_id}/extractions\", headers=HEADERS).json()\ndata = extractions[\"data\"][0][\"data\"]\nconfidence = extractions[\"data\"][0][\"confidence\"][\"overall\"]\nprint(f\"Extracted {len(data)} fields (confidence: {confidence})\")\nprint(data)\n# → {\"vendor_name\": \"Acme Corp\", \"total_amount\": 1250.00, ...}\n```\n\n**TypeScript — same flow:**\n\n```typescript\nconst API_KEY = \"tlnc_live_...\";\nconst BASE = \"https://api.talonic.com/v1\";\nconst headers = { Authorization: `Bearer ${API_KEY}` };\n\n// Step 1: Submit async extraction\nconst form = new FormData();\nform.append(\"file\", fs.createReadStream(\"contract.pdf\"));\nform.append(\"options\", '{\"async\": true}');\nconst { document } = await fetch(`${BASE}/extract`, {\n  method: \"POST\", headers, body: form,\n}).then((r) => r.json());\n\n// Step 2: Poll with exponential backoff\nlet delay = 2000;\nlet doc: any;\nfor (let i = 0; i < 20; i++) {\n  await new Promise((r) => setTimeout(r, delay));\n  doc = await fetch(`${BASE}/documents/${document.id}`, { headers }).then((r) => r.json());\n  if (doc.status === \"completed\") break;\n  if (doc.status === \"error\") throw new Error(`Extraction failed: ${doc.error}`);\n  delay = Math.min(delay * 2, 30_000);\n}\n\n// Step 3: Retrieve extracted data\nconst { data: extractions } = await fetch(\n  `${BASE}/documents/${document.id}/extractions`, { headers }\n).then((r) => r.json());\nconsole.log(extractions[0].data);\n// → { vendor_name: \"Acme Corp\", total_amount: 1250.00, ... }\n```\n\nRecommended polling: 2s initial, exponential backoff (2→4→8→16→30s cap),\ntimeout after 5 minutes.\n\n**Alternative — Webhooks:** Configure a delivery destination and listen for\n`document.extracted` events. See the Delivery tag.\n\n**Job status state machine:**\n`pending` → `queued` → `processing` → `complete` | `failed`\n\n## Performance\n\n| Document size | Expected latency | Max timeout |\n|---------------|------------------|-------------|\n| 1–5 pages     | Sync, <3s        | 30s         |\n| 6–50 pages    | <30s average     | 5 min       |\n| 50+ pages     | <5 min average   | 30 min      |\n\n**Uptime SLA:** 99.5% (Build), 99.9% (Scale), custom (Enterprise).\n\n**Max file size:** 500 MB. JSON request bodies (schemas, jobs): 1 MB.\n\n**Idempotency:** Pass `Idempotency-Key` header on POST requests. Keys are\nvalid for 24 hours and scoped per API key. Duplicates return the cached\nresponse with `cached: true`.\n","contact":{"name":"Talonic Support","email":"support@talonic.ai","url":"https://talonic.ai"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.talonic.com","description":"Production"},{"url":"http://localhost:3001","description":"Local development"}],"security":[{"BearerAuth":[]}],"tags":[{"name":"Extract","description":"Upload a document and extract structured data in one call. Start here."},{"name":"Nodes","description":"Run a single One Engine stage (transfer, extract, resolve, validate, assemble) as a standalone job over a record set — the composable primitive tier. Chain nodes by passing the record_set_id. For the governed end-to-end run, use Pipelines.\n"},{"name":"Documents","description":"Browse, inspect, and delete processed documents. Includes document type classification and OCR markdown retrieval."},{"name":"Extractions","description":"Access extraction results, retrieve structured data in JSON or CSV, and submit field-level corrections."},{"name":"Schemas","description":"Create and manage reusable extraction schemas, schema graph classes, output dialects, and the field registry."},{"name":"Jobs & Batches","description":"Track async processing jobs, poll for completion, retrieve result grids, and manage batch inference runs at 50% cost."},{"name":"Sources","description":"Create document ingest sources with dedicated API keys. Upload documents for automatic extraction."},{"name":"Delivery","description":"Outbound delivery. Configure destinations (six live connectors: webhook, sftp,\ns3, azure_blob, google_drive, onedrive), create bindings that join signal filters\nto deliverable types + destinations + serializers, and inspect the\nhistory/DLQ/events log. Every delivery is at-least-once with an idempotency key\non the wire.\n\n## Webhook Contract\n\n**Event payload:**\n```json\n{\n  \"event\": {\n    \"event_type\": \"document.extracted\",\n    \"event_id\": \"42\",\n    \"binding_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n    \"idempotency_key\": \"c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4\",\n    \"attempt\": 1,\n    \"delivered_at\": \"2026-04-25T14:30:00.000Z\"\n  },\n  \"payload\": { \"document_id\": \"...\", \"data\": { \"...extracted fields...\" } }\n}\n```\n\n**Event types:** `document.extracted` (deliver with the `document.capture`\ndeliverable for the raw field map; its payload gains optional `metadata`/\n`batch_id` read from the document's own `client_metadata`/`client_batch_id`\ncolumns — document-scoped, not request-scoped, since this deliverable has\nno run-request context; present only when set),\n`document.extraction_failed`,\n`document.structured` (per-document structured fields from a Spec pipeline / `/v1/run`; deliver with the `pipeline.capture` deliverable — its payload carries `run_id` (null outside `/v1/run`), `document_id`, `pipeline_id`, `fields` for submission correlation, and optional `metadata`/`batch_id`; for a `/v1/run`-attributed document these read the ATTRIBUTED REQUEST's per-input merged bag first — correct under byte-identical dedup and append, where the canonical documents row can carry a different submission's tags — falling back to the documents row when no request is attributed; present only when set),\n`run.completed` (a `POST /v1/run` pipeline finished; payload adds `records` —\nan array of `{ document_id, filename, data, metadata?, batch_id? }`, one entry\nper output row, ALWAYS an array even for a single document; `metadata`/\n`batch_id` are the submitting request's per-input merged bag (echo-sourced,\nso dedup/append never leaks another request's tags onto this one's records),\npresent only when set; assembled runs attribute each\ncomposed row to its anchor document; `document_id` and `filename` are\nnullable — null when a row's document identity cannot be resolved —\nalongside the legacy `structured_data`,\nstill emitted but considered legacy in favor of `records`),\n`run.failed` (a `POST /v1/run` pipeline failed — every document errored\nduring ingest or extraction; the `error` object's shape varies by failure\nstage and may include `document_ids`, a best-effort array of the input\ndocument ids),\n`run.dataspace.completed`, `run.dataspace.failed`, `result.dataspace.completed`,\n`result.dataspace.failed`, `run.structuring.completed`, `run.structuring.failed`,\n`run.resolution.completed`, `run.resolution.failed`, `run.extraction.completed`,\n`run.extraction.failed`, `result.flagged`, `result.approved`, `result.rejected`,\n`delivery.item.completed`, `delivery.item.failed`.\n\n**Typed structured values:** `run.completed` and `document.structured`\nemit typed field values natively — a field backed by a structured\nsubschema arrives as an array of objects (e.g.\n`[{\"label\":\"BoL\",\"value\":\"123\"}]`), not a stringified scalar, and each\nobject's subfields are typed per their declared subfield `data_type`. A\nconsumer that assumes every field value is a scalar breaks silently on\nsuch a field; that is the consumer's contract violation, not a payload\nchange. `document.extracted` is unaffected — its arrays are pre-flattened\nat the capture layer.\n\n\nThe same subfield typing applies on `json`/`ndjson` delivery and on the\n`/v1` poll — `GET /v1/run/{id}/results` and `GET /v1/pipelines/{id}/results`,\nboth the `fields` map and the `?include=cells` `cells[].value` — so the\npoll and the webhook agree. Per-subfield miss behavior follows the wire\nform of the declared type: a `number` or `boolean` subfield value that\nfails to parse emits `null` (these types have no string wire form, so the\nwire stays strictly number-or-null / boolean-or-null); an `enum` or `date`\nsubfield value that is out-of-vocabulary or unparseable passes through as\nits raw string (these types ARE string-typed on the wire, so a present\nvalue is never dropped). A nested array or object subfield value passes\nthrough raw. The `audit[].value` view is the deliberate raw history view\nand is never type-projected. Every extraction WIRE leaf remains\nstring-typed — subfield typing is derived at this outbound edge, not\ncarried on the extraction wire.\n\n**Signature verification (HMAC-SHA256):**\n\nHeader: `X-Talonic-Signature: t=1714060200000,v1=abc123...`\n\n```javascript\nconst crypto = require('crypto');\nconst [tPart, vPart] = signature.split(',');\nconst timestamp = tPart.split('=')[1];\nconst received  = vPart.split('=')[1];\nconst expected  = crypto.createHmac('sha256', signingSecret)\n  .update(timestamp + '.' + rawBody).digest('hex');\nconst valid = crypto.timingSafeEqual(\n  Buffer.from(received), Buffer.from(expected));\n```\n\n**Retry policy:** Up to 7 attempts — 0s, 30s, 2m, 8m, 30m, 2h, 8h (~10.5h total).\nHTTP 429/5xx are retryable. HTTP 4xx (except 408) goes to DLQ immediately.\n\n**Dead-letter queue recovery:** When all retries are exhausted, the delivery\nlands in the DLQ. List failed deliveries with `GET /v1/delivery/dlq`\n(filterable by `binding_id` and `error_code`). Inspect a single entry with\n`GET /v1/delivery/dlq/{id}`. Replay with `POST /v1/delivery/dlq/{id}/replay`\n— this deletes the DLQ entry, re-signs the payload with the current\nsigning secret, resets the retry counter to attempt 1, and re-enqueues\nthe delivery through the full backoff ladder.\n"},{"name":"Filter","description":"Structured filter queries over materialised document values plus omnisearch across documents, fields, and schemas."},{"name":"Review","description":"Queue of validation records requiring human review; supports single- and batch-action approvals/rejections."},{"name":"Benchmarks","description":"Ground-truth datasets and benchmark runs measuring extraction accuracy."},{"name":"Batches","description":"Batch inference runs. Extraction deferred to the provider's Message Batches API at 50% cost, 48h SLA."},{"name":"Cases","description":"Document clusters linked through shared entity values. Cases are discovered automatically from the linking graph."},{"name":"Document Types","description":"Canonical document type ontology and the customer's resolved types."},{"name":"Fields","description":"Field registry — canonical field definitions discovered across the customer's documents plus cross-schema harmonization."},{"name":"Matching","description":"Reference-data matching configurations and runs. Matches extracted document fields against reference datasets with weighted field mappings."},{"name":"Reference Data","description":"Uploaded reference datasets (CSV/XLSX) used by matching configurations for lookups and joins."},{"name":"Usage","description":"Aggregate, per-document, per-pipeline, and per-run API usage accounting (tokens, costs, operation types). Model and cost fields on the aggregate and per-document routes are redacted for organizations without the \"Cost control endpoints\" approval; the pipeline and run routes are hidden entirely (404) for such organizations and additionally require an API key carrying the `usage` scope."},{"name":"Resolutions","description":"Resolution runs — apply field normalization, transforms, and lookup cascades to extracted data."},{"name":"Linking","description":"Document linking graph — link keys, document links, entity graph, classification, and backfill operations."},{"name":"N-Shot","description":"N-Shot comparison endpoints for job runs — summary, field comparisons, overrides, and judge decisions."},{"name":"Schema Graph","description":"Schema class ontology — versioned classes, diffs with approval workflow, edges, aliases, and visualization."},{"name":"Structuring","description":"Structuring pipeline — validation checks, approval gates with rules, result checks, pending approvals, and delivery triggers."},{"name":"Telemetry","description":"Aggregate structuring metrics — capture hit rate, synthesize rate, strategy distribution, and tier funnel breakdowns per schema or run."},{"name":"Credits","description":"Credit balance, usage history, daily breakdown, and per-request usage log."},{"name":"Agent","description":"Workspace context and tool registry for the embedded AI agent. Read-only."},{"name":"Account","description":"Self-serve account introspection (tier, status, credits, daily limits, today's usage) and programmatic API-key management."},{"name":"Billing","description":"Agent-aware billing — auto top-up and an upgrade link the agent can hand to a human."},{"name":"Process","description":"Submit documents for processing through configured pipelines. Results delivered via webhooks."},{"name":"Reconciliation","description":"Reconcile extracted values against an uploaded reference dataset (config + analyze + run)."},{"name":"Field Reviews","description":"The pipeline field-review queue — list held cells, resolve them, and export the decision log."},{"name":"Matching Packages","description":"Multi-document-type matching packages — configs and synchronous runs over grouped inputs."},{"name":"Customer Ontologies","description":"The customer ontology overlay — versioned custom doctypes and field concepts that augment the Talonic ontology."},{"name":"Pipelines","description":"Run a configured Spec end to end (the One Engine) over a set of documents, poll progress, and produce a data product."},{"name":"Run","description":"One-call ingest + Spec-pipeline run. `POST /v1/run` accepts files and/or file URLs directly (no separate ingest step), starts the named Spec's compiled pipeline, and returns a poll target — unlike `POST /v1/pipelines`, which requires documents to already exist. Poll `GET /v1/run/{id}` or register a webhook (`POST /v1/webhooks`, events `run.completed` / `run.failed`) to be notified on completion.\n"},{"name":"Webhooks","description":"Outbound HMAC-signed event webhooks — configure endpoints and read the event catalog, delivery format, signature scheme, and retry policy."},{"name":"Events","description":"The tenant event feed — the timeline of everything that happened (extractions, run completions, review verdicts, delivery outcomes). The same rows webhooks fan out from, so missed webhook deliveries can be reconciled against this feed."},{"name":"Provenance","description":"Document-level provenance — deterministic (subject, predicate, object) claims synthesized from captured fields and spans, each carrying its evidence quote and grounded flag."},{"name":"AI Policy","description":"Tenant AI policy and model routing. Read the effective policy, replace or patch it, list every model and model class with reachability, inspect the operation catalog, dry-run a routing decision, and read the policy's own version history. The mandatory constraints (region pin, provider allowlist, model denylist) are enforced at routing time for every call; a policy that leaves an operation without a compliant route makes that operation fail closed rather than reach a provider the policy forbids. All routes require a workspace-scoped API key.\n"}],"paths":{"/v1/extract":{"post":{"operationId":"extract","summary":"Extract structured data from a document","description":"Upload a file, provide a URL, or reference an existing document to extract\nstructured data. The response is synchronous for small documents (<=5 pages)\nand asynchronous for larger ones, unless overridden via the `options` field.\n\nProvide exactly one document source: `file`, `file_url`, or `document_id`.\n\nOptionally supply a schema (inline JSON or `schema_id`) and/or free-text\n`instructions` to guide extraction.\n","tags":["Extract"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The document file to extract from. Max 500 MB. Accepted types: PDF, PNG, JPG, TIFF, WEBP, DOCX, TXT, CSV."},"file_url":{"type":"string","format":"uri","description":"Public URL of the document to download and extract from."},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543","description":"ID of an already-uploaded document to re-extract."},"schema":{"type":"string","description":"Inline JSON Schema definition describing the fields to extract."},"schema_id":{"type":"string","format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901","description":"ID of a saved schema to use for extraction."},"instructions":{"type":"string","description":"Free-text extraction instructions (e.g. \"Extract all line items with amounts\")."},"include_markdown":{"type":"string","enum":["true","false"],"default":"false","description":"When \"true\", includes the OCR-converted markdown of the document in the\nresponse under the `markdown` field. Useful for PDF-to-markdown conversion\nwithout requiring a schema.\n"},"options":{"type":"string","description":"JSON string of extraction options.\n- `async` (boolean) — force async (`true`) or sync (`false`) processing.\n"},"batch_id":{"type":"string","maxLength":200,"description":"Optional caller grouping key stamped on the document (documents.client_batch_id)."},"metadata":{"type":"string","description":"Optional JSON string of a FLAT object `{ [key]: string | number | boolean | null }` (nested objects/arrays rejected 400; ≤50 keys, key ≤128, string value ≤1024), stamped on the document as documents.client_metadata.\n"}}},"encoding":{"file":{"contentType":"application/pdf, image/png, image/jpeg, image/tiff, image/webp, application/vnd.openxmlformats-officedocument.wordprocessingml.document, text/plain, text/csv"}}}}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"description":"Synchronous extraction completed.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractSyncResponse"},"example":{"extraction_id":"d1a2b3c4-5678-9abc-def0-1234567890ab","request_id":"req_x7y8z9a0b1c2d3e4","status":"complete","document":{"id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"invoice-042.pdf","pages":3,"size_bytes":245760,"type_detected":"Invoice","language_detected":"en"},"data":{"invoice_number":"INV-2024-0042","invoice_date":"2024-03-15","vendor_name":"Acme Corp","total_amount":1250,"currency":"EUR","line_items":[{"description":"Consulting services","quantity":10,"unit_price":100,"amount":1000},{"description":"Expenses","quantity":1,"unit_price":250,"amount":250}]},"schema":{"source":"inferred","id":null,"definition":{"type":"object","properties":{"invoice_number":{"type":"string"},"total_amount":{"type":"number"}}},"save_url":"https://app.talonic.com/schemas/save?from=d1a2b3c4-5678-9abc-def0-1234567890ab"},"confidence":{"overall":0.94,"fields":{"invoice_number":0.99,"invoice_date":0.97,"vendor_name":0.88,"total_amount":0.98,"currency":0.95,"line_items":0.85}},"processing":{"duration_ms":3420,"pages_processed":3,"region":"eu-west"},"links":{"self":"/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab","document":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543","dashboard":"https://app.talonic.com/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab"}}}}},"202":{"description":"Async extraction accepted. Poll the returned job URL for progress.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractAsyncResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST https://api.talonic.com/v1/extract \\\n  -H \"Authorization: Bearer tlnc_live_abc123\" \\\n  -F \"file=@invoice.pdf\" \\\n  -F 'schema={\"properties\":{\"invoice_number\":{\"type\":\"string\"},\"total_amount\":{\"type\":\"number\"}}}'\n"},{"lang":"python","label":"Python","source":"from talonic import Talonic\nclient = Talonic(api_key=\"tlnc_live_abc123\")\nresult = client.extract(\n    file=open(\"invoice.pdf\", \"rb\"),\n    schema={\n        \"properties\": {\n            \"invoice_number\": {\"type\": \"string\"},\n            \"total_amount\": {\"type\": \"number\"},\n        }\n    },\n)\nprint(result.data)\n"},{"lang":"typescript","label":"TypeScript","source":"import Talonic from \"@talonic/sdk\";\nconst client = new Talonic({ apiKey: \"tlnc_live_abc123\" });\nconst result = await client.extract({\n  file: fs.createReadStream(\"invoice.pdf\"),\n  schema: {\n    properties: {\n      invoice_number: { type: \"string\" },\n      total_amount: { type: \"number\" },\n    },\n  },\n});\nconsole.log(result.data);\n"}]}},"/v1/documents":{"get":{"operationId":"listDocuments","summary":"List documents","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"source_id","in":"query","schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Filter by source connection ID."},{"name":"source_type","in":"query","schema":{"type":"string"},"description":"Filter by source type (e.g. `api`, `manual`)."},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","processing","completed","error"]},"description":"Filter by document status."},{"name":"after","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return documents created after this timestamp (ISO 8601)."},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return documents created before this timestamp (ISO 8601)."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive filename search."}],"responses":{"200":{"description":"Paginated list of documents.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentResponse"}}}}]},"example":{"data":[{"id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"contract-2024.pdf","pages":12,"size_bytes":1048576,"mime_type":"application/pdf","type_detected":"Service Contract","language_detected":"en","status":"completed","source":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","type":"api"},"triage":{"sensitivity":"confidential","department":"Legal","jurisdiction":"EU","pii_detected":true,"pii_categories":["name","address"],"regulated_data":false,"confidentiality_marking":"internal"},"extraction_count":1,"latest_extraction_id":"d1a2b3c4-5678-9abc-def0-1234567890ab","created_at":"2026-04-25T14:30:00.000Z","links":{"self":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543","extractions":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543/extractions","dashboard":"https://app.talonic.com/documents/f0e1d2c3-b4a5-9687-8765-432109876543"}}],"pagination":{"total":142,"limit":20,"has_more":true,"next_cursor":"ZDFhMmIzYzR8MjAyNi0wNC0yNVQxNDozMDowMC4wMDBa"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://api.talonic.com/v1/documents?limit=10&status=completed \\\n  -H \"Authorization: Bearer tlnc_live_abc123\"\n"},{"lang":"python","label":"Python","source":"docs = client.documents.list(limit=10, status=\"completed\")\nfor doc in docs.data:\n    print(doc.filename, doc.status)\n"},{"lang":"typescript","label":"TypeScript","source":"const docs = await client.documents.list({ limit: 10, status: \"completed\" });\ndocs.data.forEach((doc) => console.log(doc.filename, doc.status));\n"}]}},"/v1/documents/{id}":{"get":{"operationId":"getDocument","summary":"Get a document","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteDocument","summary":"Delete a document","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/{id}/extractions":{"get":{"operationId":"listDocumentExtractions","summary":"List extractions for a document","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Extractions for the document.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExtractionResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/{id}/fields":{"get":{"operationId":"listDocumentFields","summary":"List a document's captured fields","description":"Returns the document's captured fields bound into the field registry — one row per occurrence with its canonical concept, tier, value and confidence. A linked duplicate transparently returns the canonical document's fields.\n","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Captured fields for the document.","content":{"application/json":{"schema":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid"},"data":{"type":"array","items":{"type":"object","properties":{"field_id":{"type":"string","format":"uuid"},"canonical_name":{"type":"string"},"display_name":{"type":"string","nullable":true},"cluster_name":{"type":"string","nullable":true},"data_type":{"type":"string","nullable":true},"tier":{"type":"integer"},"value":{"nullable":true},"confidence":{"type":"number","nullable":true}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/{id}/lineage":{"get":{"operationId":"getDocumentLineage","summary":"Get a document's lineage","description":"The document's downstream footprint (\"used in\"): the pipelines that consumed it, the data products built from them, the field-registry concepts it contributed, and the cases and business cases it belongs to. Each entry carries a deep link to its public surface.\n","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document lineage.","content":{"application/json":{"schema":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid"},"pipelines":{"type":"array","items":{"type":"object"}},"data_products":{"type":"array","items":{"type":"object"}},"field_registry":{"type":"object","properties":{"total":{"type":"integer"},"by_tier":{"type":"array","items":{"type":"object"}},"sample":{"type":"array","items":{"type":"object"}}}},"cases":{"type":"array","items":{"type":"object"}},"business_cases":{"type":"array","items":{"type":"object"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/{id}/re-extract":{"post":{"operationId":"reExtractDocument","summary":"Re-run extraction on an existing document","description":"Resets the document's extraction state (clearing `raw_extraction`,\n`resolved_data`, and `processing_log`) and re-runs the full\nextraction pipeline on the same document row. Does not create a\nduplicate record.\n\nReturns immediately with `status: \"processing\"`; poll\n`GET /v1/documents/{id}` until status transitions to `completed`\nor `error`.\n","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Re-extraction started.","content":{"application/json":{"schema":{"type":"object","required":["id","status","message","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["processing"]},"message":{"type":"string","example":"Re-extraction started."},"links":{"type":"object","properties":{"self":{"type":"string"},"document":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/{id}/markdown":{"get":{"operationId":"getDocumentMarkdown","summary":"Get the OCR-converted markdown of a document","description":"Returns the full markdown representation produced by OCR for the document.\nEquivalent to passing `include_markdown=true` on `/v1/extract`, but callable\nat any time after OCR has completed. Useful for PDF-to-markdown conversion\nwithout requiring a schema or re-running extraction.\n\nReturns 404 if the document does not exist, is still being processed, or is\nan image that did not produce OCR output.\n","tags":["Documents"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document markdown.","content":{"application/json":{"schema":{"type":"object","required":["document_id","markdown"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543","description":"ID of the document the markdown was produced from."},"markdown":{"type":"string","example":"# Invoice INV-2024-0042\nVendor: Acme Corp...","description":"Full OCR-converted markdown body."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/upload-session":{"post":{"operationId":"createUploadSession","summary":"Create a browser-handoff upload session","description":"Creates a pending document row plus a short-lived upload token and\nreturns a browser `upload_url` for it. This is the first half of the\nbrowser-handoff upload pair used by the hosted MCP connector: an\nagent creates the session, the user opens `upload_url` in a browser\nand picks the file, and the browser posts it to\n`POST /v1/upload/{token}`.\n\n**Auth is asymmetric across the pair.** This route requires an\nOAuth 2.1 bearer token (the connector OAuth session) and REJECTS\n`tlnc_` API keys with `401`. The upload route is unauthenticated\nbecause the short-lived token IS the credential. The token expires\nafter 15 minutes by default and is single-use.\n\nThe created document is targeted at extraction only\n(`ingestion_target: extract`): once uploaded, call `POST /v1/extract`\nwith the returned `document_id`.\n","tags":["Documents"],"security":[{"OAuthBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename"],"properties":{"filename":{"type":"string","maxLength":512,"description":"Filename of the file the user will upload.","example":"invoice-2026-04.pdf"}}}}}},"responses":{"201":{"description":"Upload session created.","content":{"application/json":{"schema":{"type":"object","required":["document_id","upload_url","expires_at"],"properties":{"document_id":{"type":"string","format":"uuid","description":"Pending document row awaiting the upload.","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"upload_url":{"type":"string","description":"Browser URL the user opens to pick and upload the file.","example":"https://app.talonic.com/u/1f2e3d4c-5b6a-7980-abcd-ef0123456789"},"expires_at":{"type":"string","format":"date-time","description":"Token expiry (15 minutes from creation by default)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing or invalid OAuth bearer token, or a `tlnc_` API key was used (not accepted on this route).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/upload/{token}":{"post":{"operationId":"uploadWithToken","summary":"Upload a file against an upload-session token","description":"Accepts the file for an upload session. This route is public: no\n`Authorization` header is required or read, because the single-use,\nshort-lived session token in the path IS the credential. The token is\nclaimed atomically, so a second request with the same token gets\n`404` even if it races the first.\n\nSend the file as `multipart/form-data` in the `file` field. The\ndefault size cap is 500 MB. On success the document is stored and\nextraction is enqueued; the returned `status` is normally `queued`\n(`uploaded` when the queue is temporarily unavailable, in which case\n`POST /v1/extract` still processes the document inline).\n","tags":["Documents"],"security":[],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Single-use upload token minted by `POST /v1/documents/upload-session`."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The file to upload (500 MB default cap)."}}}}}},"responses":{"201":{"description":"File accepted and extraction enqueued.","content":{"application/json":{"schema":{"type":"object","required":["document_id","status","filename"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"status":{"type":"string","description":"Document status after upload, normally `queued`.","example":"queued"},"filename":{"type":"string","example":"invoice-2026-04.pdf"}}}}}},"400":{"description":"No file was included in the multipart body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Upload token not found, expired, or already used.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/inject-customer-metadata":{"post":{"operationId":"injectCustomerMetadata","summary":"Inject customer metadata for documents","description":"Upload a CSV file containing customer-provided metadata fields and attach\nthose values to matching documents.\n\nBy default, the endpoint expects a comma-delimited UTF-8 CSV with a\n`document_id` column. Every non-empty column other than `document_id`\nis written as injected metadata. Pass `reference_column`, `delimiter`,\n`encoding`, or `field_columns` to use another CSV layout.\n","tags":["Documents"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"CSV file containing document references and metadata values. Max 200 MB."},"reference_column":{"type":"string","default":"document_id","description":"CSV column used to identify the document. Use `document_id` for exact document UUID matching."},"field_columns":{"type":"string","description":"Comma-separated list of CSV columns to inject. Defaults to all non-reference columns.","example":"ku_vertrag_id,contract_status"},"delimiter":{"type":"string","default":",","description":"CSV delimiter. Use `\\t` for tab-delimited files."},"encoding":{"type":"string","default":"utf8","description":"Node.js buffer encoding used to read the uploaded file."}}}}}},"responses":{"200":{"description":"Metadata injection completed.","content":{"application/json":{"schema":{"type":"object","required":["batch_id","rows_processed","documents_matched","documents_pending","fields_written"],"properties":{"batch_id":{"type":"string","format":"uuid"},"rows_processed":{"type":"integer"},"documents_matched":{"type":"integer"},"documents_pending":{"type":"integer"},"fields_written":{"type":"integer"}}},"example":{"batch_id":"b0c1d2e3-f4a5-6789-abcd-ef0123456789","rows_processed":30,"documents_matched":30,"documents_pending":0,"fields_written":30}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST https://api.talonic.com/v1/inject-customer-metadata \\\n  -H \"Authorization: Bearer tlnc_live_abc123\" \\\n  -F \"file=@ku_vertrag_id.csv\"\n"}]}},"/v1/extractions":{"get":{"operationId":"listExtractions","summary":"List extractions","tags":["Extractions"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"document_id","in":"query","schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Filter by document ID."},{"name":"status","in":"query","schema":{"type":"string","enum":["complete","failed","processing"]},"description":"Filter by extraction status."},{"name":"after","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return extractions created after this timestamp."},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return extractions created before this timestamp."}],"responses":{"200":{"description":"Paginated list of extractions.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExtractionListItem"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/extractions/{id}":{"get":{"operationId":"getExtraction","summary":"Get an extraction","tags":["Extractions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Full extraction with data and confidence scores.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/extractions/{id}/data":{"get":{"operationId":"getExtractionData","summary":"Get extraction data","description":"Returns just the extracted key-value data. Supports JSON (default) and CSV formats.\n","tags":["Extractions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"},"description":"Response format. `csv` returns a downloadable CSV file."}],"responses":{"200":{"description":"Extracted data.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Key-value pairs of extracted field names and values.","example":{"invoice_number":"INV-2024-0042","invoice_date":"2024-03-15","vendor_name":"Acme Corp","vendor_address":"123 Main St, Berlin, DE","total_amount":1250,"currency":"EUR","tax_rate":19,"tax_amount":199.58,"payment_terms":"Net 30","due_date":"2024-04-14"}}},"text/csv":{"schema":{"type":"string","description":"CSV with field names as header row and values as data row."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://api.talonic.com/v1/extractions/abc-123/data \\\n  -H \"Authorization: Bearer tlnc_live_abc123\"\n"},{"lang":"python","label":"Python","source":"data = client.extractions.get_data(\"abc-123\")\nprint(data)  # {\"invoice_number\": \"INV-2024-0042\", \"total_amount\": 1250.00}\n"},{"lang":"typescript","label":"TypeScript","source":"const data = await client.extractions.getData(\"abc-123\");\nconsole.log(data); // { invoice_number: \"INV-2024-0042\", total_amount: 1250.00 }\n"}]},"patch":{"operationId":"updateExtractionData","summary":"Correct extraction data","description":"Submit field-level corrections. Each key in the body is a field name; the value\nis the corrected value. Corrected fields are locked at confidence 1.0.\n","tags":["Extractions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Object mapping field names to corrected values.","example":{"vendor_name":"Acme Corporation Ltd.","total_amount":1275.5}}}}},"responses":{"200":{"description":"Updated extraction with corrections applied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionResponse"},"example":{"id":"d1a2b3c4-5678-9abc-def0-1234567890ab","status":"complete","document":{"id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"invoice-042.pdf","pages":3,"type_detected":"Invoice"},"data":{"vendor_name":"Acme Corporation Ltd.","total_amount":1275.5,"invoice_number":"INV-2024-0042"},"confidence":{"overall":0.96,"fields":{"vendor_name":1,"total_amount":1,"invoice_number":0.99}},"locked_fields":["vendor_name","total_amount"],"processing":{"duration_ms":3420,"pages_processed":3,"region":"eu-west"},"created_at":"2026-04-25T14:30:00.000Z","links":{"self":"/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab","data":"/v1/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab/data","document":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543","dashboard":"https://app.talonic.com/extractions/d1a2b3c4-5678-9abc-def0-1234567890ab"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schemas":{"get":{"operationId":"listSchemas","summary":"List schemas","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive name search."}],"responses":{"200":{"description":"Paginated list of schemas.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SchemaResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createSchema","summary":"Create a schema","description":"Create a reusable extraction schema. Provide a `name` and optionally a\nJSON Schema `definition` with `properties` describing the fields to extract.\n","tags":["Schemas"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaCreateRequest"},"example":{"name":"Invoice Schema","description":"Standard invoice fields for AP processing.","definition":{"properties":{"invoice_number":{"type":"string","title":"Invoice Number","description":"Unique identifier on the invoice."},"vendor_name":{"type":"string","title":"Vendor Name"},"total_amount":{"type":"number","title":"Total Amount","description":"Total invoice amount including tax."},"invoice_date":{"type":"string","title":"Invoice Date"}},"required":["invoice_number","total_amount"]}}}}},"responses":{"201":{"description":"Schema created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaResponse"},"example":{"id":"b2c3d4e5-f6a7-8901-bcde-f12345678901","name":"Invoice Schema","description":"Standard invoice fields for AP processing.","definition":{"type":"object","properties":{"invoice_number":{"type":"string","title":"Invoice Number","description":"Unique identifier on the invoice."},"vendor_name":{"type":"string","title":"Vendor Name"},"total_amount":{"type":"number","title":"Total Amount","description":"Total invoice amount including tax."},"invoice_date":{"type":"string","title":"Invoice Date"}},"required":["invoice_number","total_amount"]},"field_count":4,"version":1,"created_at":"2026-04-25T14:30:00.000Z","updated_at":"2026-04-25T14:30:00.000Z","links":{"self":"/v1/schemas/b2c3d4e5-f6a7-8901-bcde-f12345678901","extractions":"/v1/extractions?schema_id=b2c3d4e5-f6a7-8901-bcde-f12345678901","dashboard":"https://app.talonic.com/schemas/b2c3d4e5-f6a7-8901-bcde-f12345678901"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST https://api.talonic.com/v1/schemas \\\n  -H \"Authorization: Bearer tlnc_live_abc123\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"Invoice Schema\",\n    \"definition\": {\n      \"properties\": {\n        \"invoice_number\": {\"type\": \"string\", \"title\": \"Invoice Number\"},\n        \"total_amount\": {\"type\": \"number\", \"title\": \"Total Amount\"},\n        \"vendor_name\": {\"type\": \"string\", \"title\": \"Vendor Name\"}\n      },\n      \"required\": [\"invoice_number\"]\n    }\n  }'\n"},{"lang":"python","label":"Python","source":"schema = client.schemas.create(\n    name=\"Invoice Schema\",\n    definition={\n        \"properties\": {\n            \"invoice_number\": {\"type\": \"string\", \"title\": \"Invoice Number\"},\n            \"total_amount\": {\"type\": \"number\", \"title\": \"Total Amount\"},\n            \"vendor_name\": {\"type\": \"string\", \"title\": \"Vendor Name\"},\n        },\n        \"required\": [\"invoice_number\"],\n    },\n)\nprint(schema.id)\n"},{"lang":"typescript","label":"TypeScript","source":"const schema = await client.schemas.create({\n  name: \"Invoice Schema\",\n  definition: {\n    properties: {\n      invoice_number: { type: \"string\", title: \"Invoice Number\" },\n      total_amount: { type: \"number\", title: \"Total Amount\" },\n      vendor_name: { type: \"string\", title: \"Vendor Name\" },\n    },\n    required: [\"invoice_number\"],\n  },\n});\nconsole.log(schema.id);\n"}]}},"/v1/schemas/{id}":{"get":{"operationId":"getSchema","summary":"Get a schema","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Schema details with field definitions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateSchema","summary":"Replace a schema","description":"Replace a schema's name, description, and/or field definition.\nIf `definition.properties` is provided, all existing fields are replaced.\n","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaUpdateRequest"}}}},"responses":{"200":{"description":"Schema updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"patchSchema","x-required-scopes":["write"],"summary":"Update a schema","description":"Partially update a schema. `name` and `description` are patched\nindependently; omitted keys are left unchanged. If `definition.properties`\nor a non-empty `fields` array is provided, all existing fields are\nreplaced with the new set. `PUT` on this path delegates to the same\nhandler, so both methods accept the same body and behave identically.\nSchemas managed by a Spec document are read-only through the public API\nand return `409 Conflict`.\n","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaUpdateRequest"}}}},"responses":{"200":{"description":"Schema updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteSchema","summary":"Delete a schema","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Schema deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs":{"post":{"operationId":"createJob","summary":"Create and queue a new job","description":"Start a new grid-based job that fills a user schema from a set of\ndocuments. Provide a `schema_id` and, optionally, the specific\n`document_ids` to run against. If `document_ids` is omitted or empty,\nall `completed` documents for the customer are used.\n","tags":["Jobs & Batches"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreateRequest"}}}},"responses":{"200":{"description":"Job created and queued for processing (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreateResponse"}}}},"201":{"description":"Job created and queued for processing.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"get":{"operationId":"listJobs","summary":"List jobs","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","queued","processing","complete","failed"]},"description":"Filter by job status."},{"name":"after","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return jobs created after this timestamp."},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Return jobs created before this timestamp."}],"responses":{"200":{"description":"Paginated list of jobs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/JobResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get a job","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Job details with progress and grid statistics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"},"example":{"id":"c3d4e5f6-a7b8-9012-cdef-123456789012","name":"Q1 Invoice Processing","status":"processing","progress":45,"estimated_seconds_remaining":null,"schema":{"id":"b2c3d4e5-f6a7-8901-bcde-f12345678901","name":"Invoice Schema"},"document_count":150,"completed_documents":67,"grid_stats":{"total_cells":8850,"filled":6200,"empty":2650,"fill_rate":0.7},"current_phase":"phase_2_execute","created_at":"2026-04-25T14:30:00.000Z","started_at":"2026-04-25T14:30:05.000Z","completed_at":null,"links":{"self":"/v1/jobs/c3d4e5f6-a7b8-9012-cdef-123456789012","cancel":"/v1/jobs/c3d4e5f6-a7b8-9012-cdef-123456789012/cancel","dashboard":"https://app.talonic.com/jobs/c3d4e5f6-a7b8-9012-cdef-123456789012"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/{id}/cancel":{"post":{"operationId":"cancelJob","summary":"Cancel a job","description":"Cancel a pending or processing job. Jobs that are already `complete` or\n`failed` cannot be cancelled and will return a 409 Conflict.\n","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Job cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/{id}/results":{"get":{"operationId":"getJobResults","summary":"Get job result rows","description":"Return the extracted values for every document processed by this job,\none row per document. Includes per-row confidence and any validation\nflags raised during Phase 4.\n","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Rows extracted for the job.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResultsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/sources":{"get":{"operationId":"listSources","summary":"List sources","tags":["Sources"],"responses":{"200":{"description":"All sources for the authenticated customer.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SourceResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createSource","summary":"Create a source","description":"Create a new document ingest source. Returns the source details plus a\ndedicated `api_key` for uploading documents into this source.\n","tags":["Sources"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceCreateRequest"},"example":{"name":"Invoice Pipeline","default_schema_id":"b2c3d4e5-f6a7-8901-bcde-f12345678901"}}}},"responses":{"201":{"description":"Source created with a dedicated API key.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SourceResponse"},{"type":"object","properties":{"api_key":{"type":"string","description":"Dedicated API key for this source. Only returned at creation time.","example":"tlnc_live_src_a1b2c3d4..."}}}]},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Invoice Pipeline","type":"api","status":"active","document_count":0,"default_schema":{"id":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"endpoint":"/v1/sources/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents","api_key":"tlnc_live_src_k8m2n4p6q9r1s3t5","created_at":"2026-04-25T14:30:00.000Z","links":{"self":"/v1/sources/a1b2c3d4-e5f6-7890-abcd-ef1234567890","documents":"/v1/sources/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents","dashboard":"https://app.talonic.com/sources/a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/sources/{id}":{"get":{"operationId":"getSource","summary":"Get a source","tags":["Sources"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Source details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"updateSource","summary":"Update a source","tags":["Sources"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceUpdateRequest"}}}},"responses":{"200":{"description":"Source updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteSource","summary":"Delete a source","tags":["Sources"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Source deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/sources/{id}/documents":{"post":{"operationId":"ingestDocument","summary":"Upload a document into a source","description":"Upload a file directly into a source. The document is queued for extraction\nautomatically. Duplicate files (by content hash) return a `duplicate` status\nwith the existing document ID.\n","tags":["Sources"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The document file. Max 500 MB."},"processing_mode":{"type":"string","enum":["realtime","batch"],"default":"realtime","description":"\"realtime\" (default) — processed immediately.\n\"batch\" — 50% cost discount, results within 48 hours.\n"},"batch_id":{"type":"string","maxLength":200,"description":"Optional caller grouping key stamped on the document (documents.client_batch_id)."},"metadata":{"type":"string","description":"Optional JSON string of a FLAT object `{ [key]: string | number | boolean | null }` (nested objects/arrays rejected 400; ≤50 keys, key ≤128, string value ≤1024), stamped on the document as documents.client_metadata.\n"}}}}}},"responses":{"200":{"description":"Document ingested (or duplicate detected).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestDocumentResponse"},"example":{"document_id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"receipt-march.pdf","size_bytes":148213,"status":"queued","processing_mode":"realtime","source_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","links":{"document":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543","source":"/v1/sources/a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"get":{"operationId":"listSourceDocuments","summary":"List documents in a source","tags":["Sources"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of documents belonging to this source.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SourceDocumentItem"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/dialects":{"get":{"operationId":"listDialects","summary":"List dialects","description":"Return every shared dialect defined for the authenticated customer.","tags":["Schemas"],"responses":{"200":{"description":"All dialects for the customer.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DialectResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createDialect","summary":"Create a dialect","description":"Create a new shared dialect.","tags":["Schemas"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectCreateRequest"}}}},"responses":{"200":{"description":"Dialect created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectResponse"}}}},"201":{"description":"Dialect created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/dialects/{id}":{"get":{"operationId":"getDialect","summary":"Get a dialect","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Dialect details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateDialect","summary":"Update a dialect","description":"Partial update. Only the keys present on the body are patched. Bumps the stored `version`.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectUpdateRequest"}}}},"responses":{"200":{"description":"Dialect updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DialectResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteDialect","summary":"Delete a dialect","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Dialect deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/configs":{"get":{"operationId":"listMatchingConfigs","summary":"List matching configurations","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of matching configurations.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MatchingConfigResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createMatchingConfig","summary":"Create a matching configuration","description":"Link a reference dataset to a target scope via weighted field mappings.\nThe reference dataset must belong to the authenticated customer.\n","tags":["Matching"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigCreateRequest"}}}},"responses":{"200":{"description":"Matching configuration created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigResponse"}}}},"201":{"description":"Matching configuration created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/configs/{id}":{"get":{"operationId":"getMatchingConfig","summary":"Get a matching configuration","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching configuration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateMatchingConfig","summary":"Update a matching configuration","description":"Partial update — only provided keys are applied.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigUpdateRequest"}}}},"responses":{"200":{"description":"Matching configuration updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingConfigResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteMatchingConfig","summary":"Delete a matching configuration","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching configuration deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/configs/{id}/run":{"post":{"operationId":"triggerMatchingRun","summary":"Trigger a matching run","description":"Queue a new matching run for this configuration. The run is processed\nasynchronously; poll `GET /v1/matching/runs/{id}` for status.\n","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching run queued (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingRunResponse"}}}},"201":{"description":"Matching run queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingRunResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs":{"get":{"operationId":"listMatchingRuns","summary":"List matching runs","description":"Returns up to the 100 most recent matching runs for the authenticated\ncustomer, optionally filtered by `config_id`. This endpoint is not\ncursor-paginated.\n","tags":["Matching"],"parameters":[{"name":"config_id","in":"query","schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Filter to runs that belong to a specific matching configuration."}],"responses":{"200":{"description":"Matching runs (most recent first, capped at 100).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MatchingRunResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{id}":{"get":{"operationId":"getMatchingRun","summary":"Get a matching run","description":"Returns the run summary together with up to the 50 top-confidence match results.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching run with result summary.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingRunDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{id}/cancel":{"post":{"operationId":"cancelMatchingRun","summary":"Cancel a matching run","description":"Cancel a queued or running matching run. Runs already in a terminal\nstate (`completed`, `failed`, `cancelled`) return 400.\n","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching run cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingRunResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/routing-rules":{"get":{"operationId":"listRoutingRules","summary":"List routing rules","description":"Paginated list of document routing rules, ordered by priority ascending (lowest runs first).","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated routing rules.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createRoutingRule","summary":"Create a routing rule","description":"Create a rule that fires on `document_classified` triggers. The\n`actions.type` key (when present) controls the action kind\n(`route_to_schema` by default).\n","tags":["Delivery"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleCreateRequest"}}}},"responses":{"200":{"description":"Routing rule created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}},"201":{"description":"Routing rule created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/routing-rules/{id}":{"get":{"operationId":"getRoutingRule","summary":"Get a routing rule","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Routing rule.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"updateRoutingRule","summary":"Update a routing rule","description":"Partial update; only provided keys are patched.","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleUpdateRequest"}}}},"responses":{"200":{"description":"Routing rule updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingRuleResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteRoutingRule","summary":"Delete a routing rule","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Routing rule deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/destinations":{"get":{"operationId":"listDeliveryDestinations","summary":"List delivery destinations","tags":["Delivery"],"responses":{"200":{"description":"Delivery destinations for the authenticated customer.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Destination"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createDeliveryDestination","summary":"Create a delivery destination","tags":["Delivery"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDestinationRequest"}}}},"responses":{"200":{"description":"Destination created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"201":{"description":"Destination created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/destinations/{id}":{"get":{"operationId":"getDeliveryDestination","summary":"Get a delivery destination","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Destination detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateDeliveryDestination","summary":"Update a delivery destination","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDestinationRequest"}}}},"responses":{"200":{"description":"Destination updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Destination"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteDeliveryDestination","summary":"Delete a delivery destination","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Destination deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/destinations/{id}/test":{"post":{"operationId":"testDeliveryDestination","summary":"Live-ping a destination through the full transport envelope","description":"Exercises the complete delivery envelope (SSRF guard, payload cap, rate\nlimit, retry ladder is disabled — `max_attempts: 1`) with a tiny test\npayload. The returned `success` field reflects whether the connector's\n`deliver()` call returned a non-retryable success; check `httpStatus`\nand `message` for details.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Test outcome. Returned regardless of whether the ping succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestConnectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/bindings":{"get":{"operationId":"listDeliveryBindings","summary":"List delivery bindings","tags":["Delivery"],"responses":{"200":{"description":"Delivery bindings for the authenticated customer.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryBinding"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createDeliveryBinding","summary":"Create a delivery binding","description":"Runs the compatibility-triangle validator: the `signal_filter` must be\nwell-formed, the `deliverable_type` must resolve to a registered\nresolver, the `serializer_format` must resolve to a registered\nserializer, and the serializer must support the resolver's shape.\n","tags":["Delivery"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBindingRequest"}}}},"responses":{"200":{"description":"Binding created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryBinding"}}}},"201":{"description":"Binding created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryBinding"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/bindings/{id}":{"get":{"operationId":"getDeliveryBinding","summary":"Get a delivery binding","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Binding detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryBinding"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateDeliveryBinding","summary":"Update a delivery binding","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBindingRequest"}}}},"responses":{"200":{"description":"Binding updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryBinding"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteDeliveryBinding","summary":"Delete a delivery binding","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Binding deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/bindings/{id}/preview":{"post":{"operationId":"previewDeliveryBinding","summary":"Synthetic-signal dry-run preview","description":"Builds a synthetic {DeliveryEvent} that matches the binding's\n`signal_filter.event_type` (overlaying any `signal_filter.match`\nconstraints), then walks the delivery pipeline up to — but NOT\nincluding — `connector.deliver()`:\n`resolver.resolve(signal) → projectFieldMap → serializer.serialize`.\n\nWhen the resolver can load a real entity, `sample_mode` is `\"real\"`\nand `projected` / `serialized` / `wire_preview` are populated. If the\nresolver throws (typically `EntityMissingError` because the synthetic\nentity id doesn't exist in this tenant), the service falls back to\n`sample_mode: \"structural\"` — it returns the resolver's declared\n`shape` without concrete data. The preview never makes a network\ncall, never inserts a delivery row, and never touches the DLQ.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Preview response — real dry-run or structural fallback.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindingPreviewResponse"},"examples":{"real":{"summary":"Real dry-run — resolver loaded a synthetic entity and every pipeline stage ran.","value":{"available":true,"sample_mode":"real","signal":{"type":"document.extracted","customer_id":"11111111-1111-1111-1111-111111111111","document_id":"<preview-document_id>"},"resolver":{"type":"markdown","shape":{"kind":"blob","mime":"text/markdown"}},"projected":"# Preview document\n\n...","serialized":{"kind":"bytes","mime":"text/markdown","size_bytes":24},"wire_preview":{"body_preview":"# Preview document\n\n...","mime":"text/markdown","size_bytes":24,"headers_preview":{"Content-Type":"text/markdown","X-Talonic-Idempotency-Key":"preview-7a1b2c...","X-Talonic-Attempt":"1","X-Talonic-Event-Id":"11111111-1111-1111-1111-111111111111"}}}},"structural":{"summary":"Structural fallback — the resolver couldn't load the synthetic entity, so only the declared shape is returned.","value":{"available":true,"sample_mode":"structural","signal":{"type":"run.dataspace.completed","customer_id":"11111111-1111-1111-1111-111111111111","run_id":"<preview-run_id>","schema_id":"<preview-schema_id>"},"resolver":{"type":"run.dataspace.outcome","shape":{"kind":"record","is_collection":true,"columns":[{"name":"document_id","type":"string"},{"name":"schema_id","type":"string"},{"name":"status","type":"string"}]}},"projected":null,"serialized":null,"wire_preview":null,"structural_sample":{"deliverable_type":"run.dataspace.outcome","shape":{"kind":"record","is_collection":true,"columns":[{"name":"document_id","type":"string"},{"name":"schema_id","type":"string"},{"name":"status","type":"string"}]}},"fallback_reason":"resolver reported entity_missing: run not found"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/items":{"get":{"operationId":"listDeliveryItems","summary":"List delivery attempt records","description":"One row per delivery attempt. Filter by `binding_id`, `destination_id`,\nand/or `status` (`in_flight` | `succeeded` | `failed`). Paginated via\n`limit` / `offset` (default 50 / 0).\n","tags":["Delivery"],"parameters":[{"in":"query","name":"binding_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"destination_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string","enum":["in_flight","succeeded","failed"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"default":50}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Paged list of delivery items.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryItem"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"clearDeliveryItems","x-required-scopes":["write"],"summary":"Bulk-clear the delivery log","description":"Deletes every delivery attempt record for the tenant matching the\noptional `binding_id` / `destination_id` / `status` filters, the\nsame filters as the list route (no filters clears the whole log).\nThis is a deliberate admin cleanup: dead-letter rows referencing a\ndeleted item are de-linked, not removed. Requires an\norganization-scoped API key.\n","tags":["Delivery"],"parameters":[{"in":"query","name":"binding_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"destination_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string","enum":["in_flight","succeeded","failed"]}}],"responses":{"200":{"description":"Rows removed.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/items/{id}":{"get":{"operationId":"getDeliveryItem","summary":"Get a delivery attempt record","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Delivery item detail including request/response bodies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryItem"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteDeliveryItem","x-required-scopes":["write"],"summary":"Delete a delivery attempt record","description":"Deletes one delivery attempt record. A dead-letter row referencing\nthe deleted item is de-linked rather than removed. Requires an\norganization-scoped API key.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Item deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/items/{id}/replay":{"post":{"operationId":"replayDeliveryItem","summary":"Re-enqueue a delivery attempt","description":"Enqueues a new attempt for the binding/event pair. Generates a new\nidempotency key — replays are new attempts, never mutations.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Replay enqueued.","content":{"application/json":{"schema":{"type":"object","properties":{"enqueued":{"type":"boolean"},"idempotency_key":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/dlq":{"get":{"operationId":"listDeliveryDlq","summary":"List terminal-failure rows","tags":["Delivery"],"parameters":[{"in":"query","name":"binding_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"error_code","schema":{"type":"string"}}],"responses":{"200":{"description":"Dead-letter queue entries.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryDeadLetter"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"clearDeliveryDlq","summary":"Bulk dismiss dead-letter rows","description":"Deletes every dead-letter row for the tenant matching the optional\n`binding_id` / `error_code` filters (no filters clears the whole\nDLQ). The rows are dismissed, not replayed.\n","tags":["Delivery"],"parameters":[{"in":"query","name":"binding_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"error_code","schema":{"type":"string"}}],"responses":{"200":{"description":"Rows removed.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/dlq/replay-all":{"post":{"operationId":"replayAllDeliveryDlq","summary":"Bulk re-enqueue dead-letter rows","description":"Deletes every dead-letter row for the tenant matching the optional\n`binding_id` / `error_code` filters and re-enqueues each as a fresh\nattempt-1 delivery (the retry ladder restarts). Idempotency keys are\nunchanged, so receivers that dedupe on\n`X-Talonic-Idempotency-Key` will dedupe the replays.\n","tags":["Delivery"],"parameters":[{"in":"query","name":"binding_id","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"error_code","schema":{"type":"string"}}],"responses":{"200":{"description":"Replays enqueued.","content":{"application/json":{"schema":{"type":"object","properties":{"replayed":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/dlq/{id}":{"get":{"operationId":"getDeliveryDlq","summary":"Get a dead-letter row","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Dead-letter detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryDeadLetter"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"dismissDeliveryDlq","summary":"Dismiss a dead-letter row","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Row dismissed.","content":{"application/json":{"schema":{"type":"object","properties":{"dismissed":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/dlq/{id}/replay":{"post":{"operationId":"replayDeliveryDlq","summary":"Re-enqueue a dead-letter row","description":"Inserts a fresh BullMQ job for the binding/event pair. The DLQ row is\nleft in place (append-only history) — it stays readable until\nexplicitly dismissed.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Replay enqueued.","content":{"application/json":{"schema":{"type":"object","properties":{"replayed":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/pending":{"get":{"operationId":"listPendingRetries","summary":"List in-flight delivery retries","description":"Scheduled next-attempts (`delayed`), runnable (`waiting`), and\nin-progress (`active`) retry jobs for the current tenant. Jobs are\nscoped to bindings the API key's customer owns. For a delayed job,\n`next_attempt_at` is when the backoff elapses; for waiting/active\njobs it is null (runnable now). Bounded to the most recent jobs per\nstate — best-effort under deep backlogs.\n","tags":["Delivery"],"responses":{"200":{"description":"Pending-retry job list with per-state counts.","content":{"application/json":{"schema":{"type":"object","properties":{"counts":{"type":"object","properties":{"delayed":{"type":"integer"},"waiting":{"type":"integer"},"active":{"type":"integer"}}},"items":{"type":"array","items":{"type":"object","properties":{"job_id":{"type":"string"},"event_id":{"type":"string"},"binding_id":{"type":"string","format":"uuid"},"attempt":{"type":"integer"},"status":{"type":"string","enum":["delayed","waiting","active"]},"next_attempt_at":{"type":"string","format":"date-time","nullable":true}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"cancelAllPendingRetries","summary":"Cancel all in-flight retries for the tenant","description":"Removes every delayed/waiting retry job across all the tenant's\nbindings. In-progress (`active`) jobs are not affected. Bounded to\nthe most recent jobs per state — under a deep backlog one call\nclears up to the cap and can be repeated.\n","tags":["Delivery"],"responses":{"200":{"description":"Retries cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/pending/{jobId}":{"delete":{"operationId":"cancelPendingRetry","summary":"Cancel a single in-flight retry","description":"Removes the scheduled BullMQ job. `jobId` is a BullMQ job id string\n(not a UUID). The job's binding must belong to the current tenant.\nAn in-progress (`active`) job cannot be cancelled — returns 400.\n","tags":["Delivery"],"parameters":[{"in":"path","name":"jobId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Retry cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"boolean"},"job_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/bindings/{id}/cancel-pending":{"post":{"operationId":"cancelPendingForBinding","summary":"Cancel all in-flight retries for a binding","description":"Removes every delayed/waiting retry job whose binding matches `{id}`.\nIn-progress (`active`) jobs are left untouched. Returns the number of\njobs removed.\n","tags":["Delivery"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Retries cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/events":{"get":{"operationId":"listDeliveryEvents","summary":"List outbox events","description":"Raw outbox rows with their processing status. Filter by `event_type` —\npagination via `limit` / `offset`.\n","tags":["Delivery"],"parameters":[{"in":"query","name":"event_type","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"default":50}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Paged list of outbox events.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryEvent"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/events/{id}/replay":{"post":{"operationId":"replayDeliveryEvent","summary":"Re-poll an outbox event","description":"Clears `processed_at` and `processing_status` so the poller re-picks\nthe row on the next tick. The event ID is BIGSERIAL (string) — no\nUUID validation.\n","tags":["Delivery"],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event re-queued.","content":{"application/json":{"schema":{"type":"object","properties":{"replayed":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/catalog/signals":{"get":{"operationId":"getDeliveryCatalogSignals","summary":"All known signal (event) types","tags":["Delivery"],"responses":{"200":{"description":"Exhaustive list of signal type discriminants.","content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"string"},"example":["document.extracted","run.structuring.completed","result.approved"]},"items":{"type":"array","description":"Same signal set as `types`, but each entry carries a\nhuman-readable `label` and `description` for UI\nconsumers. Added alongside slice-1 polish; older\nclients can keep reading `types`.\n","items":{"type":"object","required":["type","label","description"],"properties":{"type":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/catalog/deliverables":{"get":{"operationId":"getDeliveryCatalogDeliverables","summary":"All registered deliverable resolvers","description":"Live resolvers include `notification`, `markdown`, `document.capture`,\n`document.meta`, `run.dataspace.outcome`, `run.structuring.outcome`,\n`run.resolution.outcome`, `run.extraction.outcome`, `record.approved`,\nand `case.snapshot` (routes the `case.resolved` signal into a flat case\nsnapshot record). The `graph.relations` resolver remains a stub with an\nempty `compatible_signals` array and never routes real traffic.\n","tags":["Delivery"],"responses":{"200":{"description":"Array of deliverable catalog entries.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeliverableCatalogEntry"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/catalog/serializers":{"get":{"operationId":"getDeliveryCatalogSerializers","summary":"All registered serializers","description":"`supports_kinds` is computed by probing the serializer with a minimal\nsynthetic shape for each deliverable kind, so it always reflects the\ncurrent `supports()` implementation.\n","tags":["Delivery"],"responses":{"200":{"description":"Array of serializer catalog entries.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SerializerCatalogEntry"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/delivery/catalog/connectors":{"get":{"operationId":"getDeliveryCatalogConnectors","summary":"All registered connectors","description":"The current build ships seven live backend connectors: `webhook` (HTTP\nPOST with HMAC signing), `sftp`, `s3`, `azure_blob`, `google_drive`\n(OAuth, `drive.file` scope), `onedrive` (OAuth, Microsoft Graph\n`Files.ReadWrite.All`), and `google_sheets` (OAuth, `drive.file` +\n`spreadsheets` scopes; record-oriented tabular upsert). Future OAuth-\nbased connectors (SharePoint, Gmail, Outlook, Hubspot) appear in the\nfrontend destinations catalog as placeholders and will be listed here\nonce their backend implementations land.\n","tags":["Delivery"],"responses":{"200":{"description":"Array of connector catalog entries.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["type","capabilities"],"properties":{"type":{"type":"string"},"capabilities":{"$ref":"#/components/schemas/ConnectorCapabilities"}}}},"example":[{"type":"webhook","capabilities":{"supported_serializers":["json","ndjson","csv","csv_file","md","txt","raw"],"supported_deliverable_kinds":["envelope","record","blob"],"auth_types":["none","bearer","basic","api_key"],"delivery_semantics":"record","default_rate_limit":{"ratePerSec":100,"capacity":100}}},{"type":"sftp","capabilities":{"supported_serializers":["json","ndjson","csv_file","xlsx","md","txt","raw"],"supported_deliverable_kinds":["record","blob","envelope"],"auth_types":["password","private_key"],"delivery_semantics":"file"}},{"type":"s3","capabilities":{"supported_serializers":["json","ndjson","csv_file","xlsx","md","txt","raw"],"supported_deliverable_kinds":["record","blob","envelope"],"auth_types":["access_key"],"delivery_semantics":"file"}},{"type":"azure_blob","capabilities":{"supported_serializers":["json","ndjson","csv_file","xlsx","md","txt","raw"],"supported_deliverable_kinds":["record","blob","envelope"],"auth_types":["connection_string","account_key"],"delivery_semantics":"file"}},{"type":"google_drive","capabilities":{"supported_serializers":["json","ndjson","csv_file","xlsx","md","txt","raw"],"supported_deliverable_kinds":["record","blob","envelope"],"auth_types":["oauth_google"],"delivery_semantics":"file"}},{"type":"onedrive","capabilities":{"supported_serializers":["json","ndjson","csv_file","xlsx","md","txt","raw"],"supported_deliverable_kinds":["record","blob","envelope"],"auth_types":["oauth_microsoft"],"delivery_semantics":"file"}},{"type":"google_sheets","capabilities":{"supported_serializers":["rows"],"supported_deliverable_kinds":["record"],"auth_types":["oauth_google"],"delivery_semantics":"record"}}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/documents/filter":{"post":{"operationId":"filterDocuments","summary":"Filter documents with structured conditions","description":"Query documents using an ordered list of filter conditions against\nmaterialised field values. Optional free-text `search` applies\nalongside the structured filter. `limit` is clamped to a server-side\nmaximum of 500.\n","tags":["Delivery"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilterDocumentsRequest"}}}},"responses":{"200":{"description":"Matching documents with a total count.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilterDocumentsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/search":{"get":{"operationId":"omnisearch","summary":"Omnisearch across documents, fields, and schemas","description":"Full-text search that returns multiple result collections in a single\nresponse: matching documents, field matches, sources, schemas, and\nfields.\n","tags":["Delivery"],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"The search query. Whitespace-only queries return empty arrays."},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1},"description":"Maximum number of results per collection. Default 20."}],"responses":{"200":{"description":"Search results across all searchable entity types.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review":{"get":{"operationId":"listReviewRecords","summary":"List review queue records","description":"Paginated list of validation records awaiting or having completed review.","tags":["Review"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"status","in":"query","schema":{"type":"string"},"description":"Optional status filter (e.g. `pending`, `approved`, `rejected`)."}],"responses":{"200":{"description":"Paginated review queue.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewRecordItem"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review/batch":{"post":{"operationId":"batchReviewAction","summary":"Apply a review action to many records","description":"Approve or reject many validation records in one call. Failed ids\n(not found or not owned by the customer) are reported in the\n`results` array rather than aborting the whole batch.\n","tags":["Review"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewBatchActionRequest"}}}},"responses":{"200":{"description":"Per-record outcomes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewBatchActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review/{id}":{"get":{"operationId":"getReviewRecord","summary":"Get a review record","description":"Returns the full record including per-field decisions and low-confidence field list.","tags":["Review"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Review record detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRecordDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review/{id}/action":{"post":{"operationId":"performReviewAction","summary":"Approve or reject a review record","tags":["Review"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewActionRequest"}}}},"responses":{"200":{"description":"Record updated with the new status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRecordItem"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/ground-truth":{"get":{"operationId":"listGroundTruthDatasets","summary":"List ground truth datasets","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of ground truth datasets.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GroundTruthDatasetResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createGroundTruthDataset","summary":"Create a ground truth dataset","tags":["Benchmarks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthDatasetCreateRequest"}}}},"responses":{"200":{"description":"Dataset created (alias of 201).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthDatasetResponse"}}}},"201":{"description":"Dataset created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthDatasetResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/ground-truth/{id}":{"get":{"operationId":"getGroundTruthDataset","summary":"Get a ground truth dataset","description":"Returns the dataset together with its sample entries (curated known-correct values).","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Dataset with sample entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthDatasetDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/benchmarks":{"get":{"operationId":"listBenchmarkRuns","summary":"List benchmark runs","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of benchmark runs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BenchmarkResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"startBenchmarkRun","x-required-scopes":["write"],"summary":"Start a benchmark run","description":"Start an asynchronous benchmark run that evaluates extraction output\nagainst a ground truth dataset. The run is created with status\n`queued`; `documents_total` is set to the dataset's entry count and\naccuracy fields stay null until the run completes. Poll\n`GET /v1/quality/benchmarks/{id}` for progress and read per-document\noutcomes from `GET /v1/quality/benchmarks/{id}/results`.\n","tags":["Benchmarks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dataset_id","user_schema_id"],"properties":{"dataset_id":{"type":"string","format":"uuid","description":"Ground truth dataset to benchmark against.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"user_schema_id":{"type":"string","format":"uuid","description":"User schema that defines the fields to evaluate.","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"name":{"type":"string","description":"Human-readable name for this run. Defaults to \"Benchmark YYYY-MM-DD\".","example":"Post-prompt-tune run"}}}}}},"responses":{"201":{"description":"Benchmark run created with status `queued`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BenchmarkResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/benchmarks/{id}":{"get":{"operationId":"getBenchmarkRun","summary":"Get a benchmark run","description":"Returns the benchmark run together with its per-document results.","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Benchmark run with per-document results.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BenchmarkDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/batches":{"get":{"operationId":"listBatches","summary":"List batch inference runs","description":"Documents uploaded with `processing_mode=batch` accumulate in an\n`ExtractionBatch` and are submitted to the provider (Anthropic or\nBedrock) at 50% of the realtime cost with a 48h SLA. This endpoint\nreturns a paginated list of the customer's batches.\n","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"status","in":"query","schema":{"type":"string","enum":["accumulating","submitted","in_progress","completed","failed","expired"]},"description":"Filter by batch lifecycle status."}],"responses":{"200":{"description":"Paginated list of batches.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BatchResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/batches/{id}":{"get":{"operationId":"getBatch","summary":"Get a batch inference run","description":"Returns the batch metadata plus per-item status for every document in the batch.","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Batch detail with items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases":{"get":{"operationId":"listCases","x-required-scopes":["read"],"summary":"List cases","description":"Cases are document clusters discovered automatically from shared entity values across documents (BFS on the linking graph; inference mode may materialise them as first-class entities).","tags":["Cases"],"parameters":[{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive search on the case label."},{"name":"min_documents","in":"query","schema":{"type":"integer","minimum":1},"description":"Return only cases with at least this many documents."}],"responses":{"200":{"description":"List of cases.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CaseListItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}":{"get":{"operationId":"getCase","x-required-scopes":["read"],"summary":"Get a case by key","description":"The case resource is keyed on its stable UUID (`id`), which never\nchanges across rebuilds. Each case also carries a content-derived\n`case_key` (hex hash of its member document set) for reference, but API\npaths take the UUID. Returns the label, narrative, linked documents,\nand anomaly count.\n","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"responses":{"200":{"description":"Case detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaseDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/document-types":{"get":{"operationId":"listDocumentTypes","summary":"List document types","description":"Document types resolved for the authenticated customer, ordered by document count descending.","tags":["Documents"],"responses":{"200":{"description":"List of document types.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentTypeResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/document-types/ontology":{"get":{"operationId":"getDocumentTypeOntology","summary":"Get the document type ontology","description":"Returns the canonical category summary (categories, subcategories, and types) used by the classifier.","tags":["Documents"],"responses":{"200":{"description":"Ontology category summary.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"Category → subcategory → types hierarchy. Shape is defined by `config/document-ontology.yaml`."}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/fields":{"get":{"operationId":"listFields","summary":"List fields","description":"Paginated list of fields from the field registry, filterable by search, tier, or cluster.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive search on canonical_name or display_name."},{"name":"tier","in":"query","schema":{"type":"integer"},"description":"Filter by tier."},{"name":"cluster_id","in":"query","schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Filter by cluster."}],"responses":{"200":{"description":"Paginated list of fields.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/fields/harmonization":{"get":{"operationId":"getFieldsHarmonization","summary":"Cross-schema field overlap","description":"Fields appearing in two or more schemas, grouped by `canonical_name`.\nUsed to reconcile field definitions across schemas (a field marked\n`is_universal: true` appears in every schema).\n","tags":["Schemas"],"responses":{"200":{"description":"Harmonization rows.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FieldHarmonizationItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/fields/{id}":{"get":{"operationId":"getField","summary":"Get a field","description":"Returns the field registry row plus up to 20 most recent occurrences.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Field detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/fields/{id}/similar":{"get":{"operationId":"getFieldsSimilar","summary":"Get fields similar to this one","description":"Returns up to 10 fields most similar to this one by cosine similarity\non the `name_embedding` vector (all-MiniLM-L6-v2, 384 dims). Returns\nan empty `data` array if the field has no embedding computed yet.\n","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Similar fields by embedding cosine similarity.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["id","canonical_name","similarity","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"canonical_name":{"type":"string","example":"invoice_number"},"similarity":{"type":"number","format":"float","minimum":0,"maximum":1},"links":{"type":"object","properties":{"self":{"type":"string"}}}}}},"message":{"type":"string","example":"Re-extraction started.","description":"Present when the field has no embedding."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/reference-data":{"get":{"operationId":"listReferenceData","summary":"List reference datasets","description":"Uploaded reference datasets (CSV/XLSX) available for matching configurations.","tags":["Reference Data"],"responses":{"200":{"description":"List of reference datasets.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReferenceDataResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createReferenceData","summary":"Create reference data from JSON","description":"Create a new reference dataset by uploading JSON rows directly. Requires write scope.","tags":["Reference Data"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","data"],"properties":{"name":{"type":"string","description":"Dataset name."},"data":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Array of row objects."},"columns":{"type":"array","items":{"type":"string"},"description":"Optional explicit column order."}}}}}},"responses":{"201":{"description":"Reference dataset created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferenceDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/v1/reference-data/{id}":{"get":{"operationId":"getReferenceData","summary":"Get a reference dataset","tags":["Reference Data"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Reference dataset metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferenceDataResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteReferenceData","summary":"Delete a reference dataset","tags":["Reference Data"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Reference dataset deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/reference-data/{id}/rows":{"get":{"operationId":"getReferenceDataRows","summary":"Get reference dataset rows (paginated)","description":"Returns the dataset's rows, paginated with page/limit (limit capped at 500).","tags":["Reference Data"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Dataset rows.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"Row object — keys match the dataset's column schema."}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/reference-data/{id}/csv":{"get":{"operationId":"downloadReferenceDataCsv","summary":"Download a reference dataset as CSV","description":"Returns the full dataset as a CSV file attachment.","tags":["Reference Data"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"CSV file (returned as an attachment via Content-Disposition).","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/usage":{"get":{"operationId":"getUsage","summary":"Aggregate API usage stats","description":"Returns token and call counts aggregated by `operation_type` and\n`model` over the requested date range. Default range is the last 30\ndays.\n\nFor organizations without the \"Cost control endpoints\" approval,\n`breakdown[].model` is redacted (omitted) and the response carries\n`\"cost_fields\": \"redacted\"`. Approved organizations see the field\nunredacted and no `cost_fields` marker. This applies uniformly —\nevery tenant, not just consumers of the per-document route.\n","tags":["Usage"],"parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Default 30 days ago."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Default now."}],"responses":{"200":{"description":"Aggregated usage stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/usage/documents/{id}":{"get":{"operationId":"getDocumentUsage","summary":"Per-document API usage","description":"Returns per-document API usage entries and totals. 404 if no usage\nrecords exist for the document.\n\nFor organizations without the \"Cost control endpoints\" approval,\n`model` and all cost fields (`cost_estimate_usd` on both `totals` and\neach `entries[]` row) are redacted (omitted), and the response\ncarries `\"cost_fields\": \"redacted\"`. Approved organizations see these\nfields unredacted and no `cost_fields` marker.\n","tags":["Usage"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Per-document usage breakdown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentUsageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/usage/pipelines/{id}":{"get":{"operationId":"getPipelineUsage","summary":"Per-pipeline API usage","description":"Returns AI usage for one pipeline: totals, a breakdown by\n`operation_type` × `model`, and a per-document rollup. `scope` is a\nfixed code (`pipeline_calls_only`) and `scope_note` is the\nhuman-readable statement of what this covers — pipeline-stamped\ncalls only. The ingest OCR leg (shared across runs, unstamped by\ndesign) is excluded.\n\nRequires the org's \"Cost control endpoints\" approval (superadmin-set;\norganizations are approved by default, shared individual workspaces\nare not) — unapproved organizations get a plain `404` (the\nroute's existence is not advertised) — AND an API key carrying the\n`usage` scope (`403` otherwise, approved organizations only). The\ntoggle check runs before the scope check, so an unapproved org's\nread-scoped key gets `404`, never a `403` that names the `usage`\nscope.\n\n`cost_estimate_usd` is Talonic's own estimate of the underlying AI\nprovider's charge for the tokens billed (cache-creation tokens price\nat 1.25× fresh input, so the token math reconciles to the estimate).\nIt is a different currency than `GET /v1/usage/credits`, which\nreports the tenant's own credit-ledger spend — the two do not\nreconcile against each other.\n","tags":["Usage"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Default 90 days ago."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Default now."}],"responses":{"200":{"description":"Per-pipeline usage breakdown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineUsageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Either the pipeline is not owned by the caller's organization, or the organization lacks the \"Cost control endpoints\" approval (the route is hidden, not merely forbidden — see description above).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/usage/runs/{id}":{"get":{"operationId":"getRunUsage","summary":"Per-run API usage","description":"Returns AI usage for one `/v1/run` request: totals, a breakdown by\n`operation_type` × `model`, and a per-document rollup. `id` is the\n`/v1/run` request id (the `run_id` from `POST /v1/run` / `GET\n/v1/run/:id`), not a pipeline id.\n\n`scope` is a fixed code (`run_attributed_calls`) and `scope_note` is\nthe human-readable statement of what this covers.\n\nA run that is still ingesting, or that failed before a pipeline was\ncreated (`pipeline_id IS NULL`), returns `200` with zero totals and\n`scope_note` explaining why — never `404` — since pollers hit this\nwindow constantly. A legacy run request that predates per-request\ndocument tracking (no `documents[]` echo) returns the same zero-total\nshape with its own `scope_note`, even when `pipeline_id` is set.\n\nAttribution is the intersection of: calls stamped with the run's\npipeline, limited to the run's own `documents[]` echo, and inside the\nrun's active time window (open-ended while the run is live; bounded\nat `updated_at` + a short margin once terminal, so completion-adjacent\ncalls are still captured without a later rerun or append on the same\nshared pipeline bleeding in). This is documented as approximate under\nshared-pipeline concurrency (append mode, or several runs targeting\nthe same pipeline). A document skipped by dedup or extraction-reuse\nlegitimately shows zeros for that document.\n\nSame gating as the pipeline route: requires the org's \"Cost control\nendpoints\" approval (`404` otherwise) AND an API key carrying the\n`usage` scope (`403` otherwise, approved organizations only).\n\n`cost_estimate_usd` is Talonic's own estimate of the underlying AI\nprovider's charge for the tokens billed. It is a different currency\nthan `GET /v1/usage/credits`, which reports the tenant's own\ncredit-ledger spend — the two do not reconcile against each other.\n","tags":["Usage"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Default 90 days ago."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Default now."}],"responses":{"200":{"description":"Per-run usage breakdown (zero totals if still ingesting or failed pre-pipeline).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunUsageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Either the run request is not owned by the caller's organization, or the organization lacks the \"Cost control endpoints\" approval (the route is hidden, not merely forbidden).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/usage/credits":{"get":{"operationId":"getCreditUsageByFunction","summary":"Per-function credit consumption","description":"Returns credit consumption grouped by platform function\n(`operation_type`) from the customer-pay ledger, plus the total over the\nwindow. Shows where credits went (extraction vs structuring vs\nintelligence operations). Populates once metering is enforcing.\n","tags":["Usage"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Trailing reporting window in days (default 30)."}],"responses":{"200":{"description":"Per-function credit consumption.","content":{"application/json":{"schema":{"type":"object","properties":{"period_days":{"type":"integer"},"total_credits":{"type":"integer"},"by_function":{"type":"array","items":{"type":"object","properties":{"operation_type":{"type":"string"},"operations":{"type":"integer"},"credits":{"type":"integer"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/pricing":{"get":{"operationId":"getPricing","summary":"Credit pricing catalog","description":"Public (unauthenticated) machine-readable credit pricing catalog: fixed\nper-unit credit rates, their EUR equivalents, the credits-per-EUR\nconversion rate, and processing-mode multipliers (e.g. batch at 0.5x).\nLets an agent predict spend before running anything.\n","tags":["Pricing"],"responses":{"200":{"description":"The credit pricing catalog.","content":{"application/json":{"schema":{"type":"object","properties":{"currency":{"type":"string","example":"EUR"},"credits_per_eur":{"type":"number"},"multipliers":{"type":"object","additionalProperties":{"type":"number"}},"units":{"type":"array","items":{"type":"object","properties":{"unit":{"type":"string"},"label":{"type":"string"},"credits":{"type":"number"},"eur":{"type":"number"},"free":{"type":"boolean"}}}}}}}}}}}},"/v1/resolutions":{"get":{"operationId":"listResolutions","summary":"List resolution runs","tags":["Resolutions"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of resolution runs.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ResolutionResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createResolution","summary":"Create a resolution run","description":"Start a new resolution run targeting documents from a specific source run.","tags":["Resolutions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["source_run_id"],"properties":{"source_run_id":{"type":"string","format":"uuid","example":"f2a3b4c5-d6e7-8901-fabc-012345678901","description":"ID of the source run to resolve against."}}}}}},"responses":{"201":{"description":"Resolution run created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolutionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/resolutions/{id}":{"get":{"operationId":"getResolution","summary":"Get a resolution run","tags":["Resolutions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Resolution run detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolutionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteResolution","summary":"Delete a resolution run","tags":["Resolutions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Resolution run deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/resolutions/{id}/results":{"get":{"operationId":"getResolutionResults","summary":"Get resolution run results","description":"Returns the resolved data for all documents in the resolution run.","tags":["Resolutions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Resolution results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/resolutions/{id}/execute":{"post":{"operationId":"executeResolution","summary":"Execute a resolution run","description":"Trigger execution of a pending resolution run.","tags":["Resolutions"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Resolution execution started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolutionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/link-keys":{"get":{"operationId":"listLinkKeys","summary":"List link keys","description":"Returns all configured link keys (field-level entity identifiers used for document linking).","tags":["Linking"],"responses":{"200":{"description":"List of link keys.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LinkKeyResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/documents/{id}/links":{"get":{"operationId":"getDocumentLinks","summary":"Get links for a document","description":"Returns all entity links discovered for a specific document.","tags":["Linking"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document links.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"entity_value":{"type":"string"},"entity_type":{"type":"string"},"link_key":{"type":"string"},"linked_document_ids":{"type":"array","items":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/graph":{"get":{"operationId":"getLinkingGraph","summary":"Get the full linking graph","description":"Returns the bipartite document-entity graph for the customer.","tags":["Linking"],"responses":{"200":{"description":"Full linking graph.","content":{"application/json":{"schema":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","additionalProperties":true}},"edges":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/graph/documents/{id}":{"get":{"operationId":"getDocumentGraph","summary":"Get graph neighbourhood for a document","description":"Returns the subgraph of entities and linked documents for a specific document.","tags":["Linking"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Document-centric subgraph.","content":{"application/json":{"schema":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","additionalProperties":true}},"edges":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/classify":{"post":{"operationId":"classifyLinkKeys","summary":"Classify link keys","description":"Run AI classification on ambiguous fields to determine their link key category (identity, transaction, reference).","tags":["Linking"],"responses":{"200":{"description":"Classification results.","content":{"application/json":{"schema":{"type":"object","properties":{"classified":{"type":"integer"},"results":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/backfill":{"post":{"operationId":"backfillLinking","summary":"Backfill linking data","description":"Trigger a backfill of the linking graph for all documents. Useful after link key configuration changes.","tags":["Linking"],"responses":{"202":{"description":"Backfill started.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"message":{"type":"string","example":"Re-extraction started."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/backfill/progress":{"get":{"operationId":"getBackfillProgress","summary":"Get backfill progress","description":"Returns the current progress of an in-flight backfill operation.","tags":["Linking"],"responses":{"200":{"description":"Backfill progress.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"processed":{"type":"integer"},"total":{"type":"integer"},"started_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/linking/document-case-map":{"get":{"operationId":"getDocumentCaseMap","summary":"Get document-to-case mapping","description":"Returns a mapping of document IDs to their assigned case keys.","tags":["Linking"],"responses":{"200":{"description":"Document-case mapping.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":{"type":"string"},"description":"Map of document_id to case_key."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/runs/{runId}/nshot/summary":{"get":{"operationId":"getNshotSummary","summary":"Get N-Shot summary for a run","description":"Returns an aggregate summary of N-Shot comparisons for a job run.","tags":["N-Shot"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Job run ID."}],"responses":{"200":{"description":"N-Shot summary.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/runs/{runId}/nshot/comparisons":{"get":{"operationId":"listNshotComparisons","summary":"List N-Shot comparisons","description":"Returns all N-Shot comparisons for a job run.","tags":["N-Shot"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Job run ID."}],"responses":{"200":{"description":"List of comparisons.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/runs/{runId}/nshot/comparison":{"get":{"operationId":"getNshotComparison","summary":"Get a specific N-Shot comparison","description":"Returns a single N-Shot comparison filtered by document and field.","tags":["N-Shot"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Job run ID."},{"name":"document_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Document ID to compare."},{"name":"field_name","in":"query","required":true,"schema":{"type":"string"},"description":"Field name to compare."}],"responses":{"200":{"description":"Single comparison result.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/runs/{runId}/nshot/override":{"post":{"operationId":"nshotOverride","summary":"Override an N-Shot value","description":"Override an N-Shot cell for a document-field pair by selecting a specific shot's value.","tags":["N-Shot"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Job run ID."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document_id","field_name","selected_shot"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"field_name":{"type":"string","example":"invoice_number"},"selected_shot":{"type":"integer","description":"Shot number (index) whose value should become the cell value.","example":2},"reason":{"type":"string","description":"Optional human-readable reason for the override, stored in the audit trail."}}}}}},"responses":{"200":{"description":"The full updated comparison object, including the applied `override`.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/jobs/runs/{runId}/nshot/judge-decision":{"post":{"operationId":"nshotJudgeDecision","summary":"Submit a judge decision for N-Shot","description":"Accept or decline the LLM judge's recommendation for an N-Shot cell. Accepting applies the judge's recommended shot as an override.\n","tags":["N-Shot"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Job run ID."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document_id","field_name","accepted"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"field_name":{"type":"string","example":"invoice_number"},"accepted":{"type":"boolean","description":"Whether the judge recommendation is accepted (true) or declined (false)."}}}}}},"responses":{"200":{"description":"The full updated comparison object, including the recorded `judgement` (and `override` when accepted).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/classes":{"get":{"operationId":"listSchemaGraphClasses","summary":"List schema graph classes","description":"Returns all classes in the schema graph ontology.","tags":["Schemas"],"responses":{"200":{"description":"List of schema graph classes.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SchemaGraphClassResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/classes/{id}":{"get":{"operationId":"getSchemaGraphClass","summary":"Get a schema graph class","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Schema graph class detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaGraphClassResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/classes/{id}/versions":{"get":{"operationId":"listSchemaGraphClassVersions","summary":"List versions of a schema graph class","description":"Returns all published versions of a class, ordered by version number descending.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"List of class versions.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"version":{"type":"integer"},"fields":{"type":"array","items":{"type":"object","additionalProperties":true}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/classes/{id}/versions/{version}":{"get":{"operationId":"getSchemaGraphClassVersion","summary":"Get a specific version of a schema graph class","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"version","in":"path","required":true,"schema":{"type":"integer"},"description":"Version number."}],"responses":{"200":{"description":"Class version detail.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer"},"fields":{"type":"array","items":{"type":"object","additionalProperties":true}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/diffs":{"get":{"operationId":"listSchemaGraphDiffs","summary":"List schema graph diffs","description":"Returns pending and processed diffs between class versions.","tags":["Schemas"],"responses":{"200":{"description":"List of diffs.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SchemaGraphDiffResponse"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/diffs/{id}/approve":{"post":{"operationId":"approveSchemaGraphDiff","summary":"Approve a schema graph diff","description":"Approve a pending diff, promoting the changes to the live class version.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Diff approved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaGraphDiffResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/diffs/{id}/reject":{"post":{"operationId":"rejectSchemaGraphDiff","summary":"Reject a schema graph diff","description":"Reject a pending diff, discarding the proposed changes.","tags":["Schemas"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Diff rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaGraphDiffResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/edges":{"get":{"operationId":"listSchemaGraphEdges","summary":"List schema graph edges","description":"Returns all edges (relationships) between schema graph classes.","tags":["Schemas"],"responses":{"200":{"description":"List of edges.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"source_class_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"target_class_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"relationship":{"type":"string"},"weight":{"type":"number","format":"float"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/aliases":{"get":{"operationId":"listSchemaGraphAliases","summary":"List schema graph aliases","description":"Returns all class aliases (alternative names mapping to canonical class IDs).","tags":["Schemas"],"responses":{"200":{"description":"List of aliases.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"alias":{"type":"string"},"class_id":{"type":"string","format":"uuid","example":"a7b8c9d0-e1f2-3456-abcd-567890123456"},"class_name":{"type":"string"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/schema-graph/visualize":{"get":{"operationId":"visualizeSchemaGraph","summary":"Get schema graph visualization data","description":"Returns nodes and edges formatted for graph visualization (D3-compatible).","tags":["Schemas"],"responses":{"200":{"description":"Visualization data.","content":{"application/json":{"schema":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","additionalProperties":true}},"edges":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/checks":{"get":{"operationId":"listStructuringChecks","summary":"List structuring checks","description":"Returns all configured validation checks for the customer.","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of structuring checks.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StructuringCheckResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createStructuringCheck","summary":"Create a structuring check","tags":["Structuring"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringCheckCreateRequest"}}}},"responses":{"201":{"description":"Structuring check created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringCheckResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/checks/{id}":{"put":{"operationId":"updateStructuringCheck","summary":"Update a structuring check","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringCheckCreateRequest"}}}},"responses":{"200":{"description":"Structuring check updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringCheckResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteStructuringCheck","summary":"Delete a structuring check","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Structuring check deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/gates":{"get":{"operationId":"listStructuringGates","summary":"List approval gates","description":"Returns all configured approval gates for the customer.","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of approval gates.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StructuringGateResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createStructuringGate","summary":"Create an approval gate","tags":["Structuring"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateCreateRequest"}}}},"responses":{"201":{"description":"Approval gate created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/gates/{id}":{"get":{"operationId":"getStructuringGate","summary":"Get an approval gate","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Approval gate detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"updateStructuringGate","summary":"Update an approval gate","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateCreateRequest"}}}},"responses":{"200":{"description":"Approval gate updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteStructuringGate","summary":"Delete an approval gate","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Approval gate deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/gates/{id}/rules":{"post":{"operationId":"addStructuringGateRule","summary":"Add a rule to an approval gate","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","threshold"],"properties":{"type":{"type":"string","description":"Rule type (e.g. min_confidence, validation_pass_rate, field_coverage)."},"threshold":{"type":"number","format":"float","description":"Numeric threshold value."}}}}}},"responses":{"201":{"description":"Rule added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuringGateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/gates/{gateId}/rules/{ruleId}":{"delete":{"operationId":"deleteStructuringGateRule","summary":"Remove a rule from an approval gate","description":"Soft-delete a single rule from an approval gate. Both identifiers come from the path; no request body.","tags":["Structuring"],"parameters":[{"name":"gateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Parent approval gate identifier."},{"name":"ruleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Rule identifier to remove."}],"responses":{"200":{"description":"Rule removed.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/results/{id}/checks":{"get":{"operationId":"getStructuringResultChecks","summary":"Get check results for a structuring result","description":"Returns the validation check outcomes for a specific structuring result.","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Check results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"check_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"check_name":{"type":"string"},"passed":{"type":"boolean"},"message":{"type":["string","null"]}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/approvals/pending":{"get":{"operationId":"listPendingApprovals","summary":"List pending approvals","description":"Returns structuring results awaiting manual approval.","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Paginated list of pending approvals.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/approvals/{id}/approve":{"post":{"operationId":"approveStructuringResult","summary":"Approve a structuring result","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Result approved.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/approvals/{id}/reject":{"post":{"operationId":"rejectStructuringResult","summary":"Reject a structuring result","tags":["Structuring"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Result rejected.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/structuring/delivery/{runId}":{"post":{"operationId":"triggerStructuringDelivery","summary":"Trigger delivery for a structuring run","description":"Emit delivery signals for all approved results in the run.","tags":["Structuring"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Structuring run ID."}],"responses":{"200":{"description":"Delivery triggered.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"integer"},"skipped":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/telemetry/schemas/{id}/summary":{"get":{"operationId":"getTelemetrySchemaSummary","summary":"Get telemetry summary for a schema","description":"Aggregate structuring metrics for a schema — capture hit rate, synthesize rate, strategy distribution, tier funnel.","tags":["Telemetry"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Schema telemetry summary.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/telemetry/schemas/{id}/trend":{"get":{"operationId":"getTelemetrySchemaTrend","summary":"Get telemetry trend for a schema","description":"Time-series telemetry data for a schema over recent runs.","tags":["Telemetry"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Schema telemetry trend.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/telemetry/schemas/{id}/fields":{"get":{"operationId":"getTelemetrySchemaFields","summary":"Get per-field telemetry for a schema","description":"Field-level structuring metrics — per-field state distribution, capture rates, and strategy breakdown.","tags":["Telemetry"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Per-field telemetry.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/telemetry/runs/{id}/summary":{"get":{"operationId":"getTelemetryRunSummary","summary":"Get telemetry summary for a run","description":"Aggregate structuring metrics for a specific job run.","tags":["Telemetry"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Run telemetry summary.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/validation/ground-truth":{"get":{"operationId":"listGroundTruths","summary":"List ground-truth datasets","description":"Returns all ground-truth datasets for the customer.","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of ground-truth datasets.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GroundTruthResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/validation/ground-truth/{id}":{"get":{"operationId":"getGroundTruth","summary":"Get a ground-truth dataset","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Ground-truth dataset detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteGroundTruth","summary":"Delete a ground-truth dataset","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Ground-truth dataset deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/validation/runs":{"get":{"operationId":"listValidationRuns","summary":"List validation runs","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of validation runs.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ValidationRunResponse"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createValidationRun","summary":"Create a validation run","description":"Start a new validation run against a ground-truth dataset.","tags":["Benchmarks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["golden_sample_id"],"properties":{"golden_sample_id":{"type":"string","format":"uuid","example":"e5f6a7b8-c9d0-1234-efab-345678901234","description":"Ground-truth dataset to validate against."},"schema_id":{"type":"string","format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901","description":"Optional schema to scope the validation."}}}}}},"responses":{"201":{"description":"Validation run created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationRunResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/validation/runs/{id}":{"get":{"operationId":"getValidationRun","summary":"Get a validation run","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Validation run detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationRunResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteValidationRun","summary":"Delete a validation run","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Validation run deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/validation/runs/{id}/results":{"get":{"operationId":"getValidationRunResults","summary":"Get validation run results","description":"Returns per-document and per-field accuracy results for the validation run.","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Validation run results.","content":{"application/json":{"schema":{"type":"object","properties":{"accuracy_overall":{"type":"number","format":"float"},"accuracy_by_field":{"type":"object","additionalProperties":{"type":"number","format":"float"}},"results":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/account":{"get":{"operationId":"getAccount","summary":"Get account snapshot","description":"Returns a read-only snapshot an agent can use to introspect itself:\ntier, status, email domain, creation date, credit balance, the daily\nrequest limits enforced by the rate limiter, and today's usage (UTC)\nagainst those limits. Sourced from the same tier table the rate limiter\nuses, the credit balance service, and the API request ledger.\n","tags":["Account"],"responses":{"200":{"description":"Account snapshot.","content":{"application/json":{"schema":{"type":"object","required":["tier","status","created_at","credits","daily_limits","usage_today"],"properties":{"tier":{"type":"string","example":"free"},"status":{"type":"string","example":"active"},"email_domain":{"type":["string","null"],"example":"acme.com"},"created_at":{"type":["string","null"],"format":"date-time"},"credits":{"type":"object","required":["balance","currency"],"properties":{"balance":{"type":"number","format":"float"},"currency":{"type":"string","example":"EUR"}}},"daily_limits":{"type":"object","description":"Daily request limits per namespace. -1 means unlimited.","properties":{"extract":{"type":"integer"},"platform":{"type":"integer"},"ingest":{"type":"integer"},"operations":{"type":"integer"}}},"usage_today":{"type":"object","description":"Requests made today (UTC) per namespace.","properties":{"extract":{"type":"integer"},"platform":{"type":"integer"},"ingest":{"type":"integer"},"operations":{"type":"integer"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/account/keys":{"get":{"operationId":"listApiKeys","summary":"List API keys","description":"Lists the API keys for the authenticated customer. The raw secret is\nnever returned — only a masked prefix, scopes, and usage metadata.\n","tags":["Account"],"responses":{"200":{"description":"API keys for the account.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"masked_prefix":{"type":"string","example":"tlnc_a1b2c3..."},"is_active":{"type":"boolean"},"last_used":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createApiKey","summary":"Create an API key","description":"Mints a new scoped key for the caller's own customer. The raw `key`\nvalue is returned ONCE and is never retrievable again — store it\nimmediately. Requires the `write` scope.\n","tags":["Account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":255,"example":"ci-pipeline"},"scopes":{"type":"array","description":"Subset of: extract, read, write, operations, billing, delivery, usage. Defaults to extract/read/write/operations. `usage` (grants access to the cost-visibility routes `GET /v1/usage/pipelines/:id` and `GET /v1/usage/runs/:id`) is scope-attenuated: requesting it is rejected with `403` (`scope_not_grantable`) unless the calling key itself already carries `usage` — a key can only ever narrow its own privilege on a newly minted key, never widen it. De-novo `usage` grants happen only through owner+ key management, never through self-serve key creation.","items":{"type":"string","enum":["extract","read","write","operations","billing","delivery","usage"]}}}}}}},"responses":{"201":{"description":"Newly created key. The `key` field is shown only here.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"key":{"type":"string","description":"The raw secret. Shown once. Never returned again.","example":"tlnc_0123456789abcdef0123456789abcdef"},"masked_prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"warning":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/account/keys/{keyId}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","description":"Revokes (deactivates) a key belonging to the caller's customer.\nCross-tenant revocation is impossible — a key not owned by the caller's\ncustomer returns 404. Requires the `write` scope.\n","tags":["Account"],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Key revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"revoked":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/billing/packs":{"get":{"operationId":"getBillingPacks","summary":"List purchasable credit packs","description":"The self-serve credit-purchase catalog: flat prepaid packs\n(1,000 credits = 1 EUR, no volume bonuses). Buy via the checkout URL\nfrom `GET /v1/billing/upgrade-link`.\n","tags":["Billing"],"responses":{"200":{"description":"Credit pack catalog.","content":{"application/json":{"schema":{"type":"object","required":["currency","packs"],"properties":{"currency":{"type":"string","example":"EUR"},"packs":{"type":"array","items":{"type":"object","required":["key","eur","credits"],"properties":{"key":{"type":"string","example":"50"},"lookupKey":{"type":"string","example":"credits_pack_50"},"eur":{"type":"number","example":50},"credits":{"type":"integer","example":50000}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/billing/upgrade-link":{"get":{"operationId":"getBillingUpgradeLink","summary":"Get a buy-credits link","description":"Returns a URL the agent hands to a human to buy prepaid credits. With\nbilling configured this is a real Stripe hosted-Checkout session\n(`provider: \"stripe\"`) for the selected pack; credits are available\nseconds after the human completes payment. Falls back to a dashboard\nbilling deep link (`provider: \"dashboard\"`) on deployments without\nStripe. A human must complete the payment either way.\n","tags":["Billing"],"parameters":[{"name":"pack","in":"query","required":false,"schema":{"type":"string","enum":["10","50","250","1000"],"default":"50"},"description":"Credit pack to check out (see `GET /v1/billing/packs`)."}],"responses":{"200":{"description":"Buy-credits link.","content":{"application/json":{"schema":{"type":"object","required":["url","provider","requires_human"],"properties":{"url":{"type":"string","format":"uri","example":"https://checkout.stripe.com/c/pay/cs_test_..."},"provider":{"type":"string","description":"'stripe' (hosted Checkout session) or 'dashboard' (deep link fallback).","example":"stripe"},"requires_human":{"type":"boolean"},"pack":{"type":"object","description":"The selected pack (stripe provider only)."},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/credits/balance":{"get":{"operationId":"getCreditsBalance","summary":"Get credit balance","description":"Returns the enriched credit balance for the authenticated customer:\ncredit balance with EUR conversion, 30-day burn rate, projected runway,\nand API tier info.\n","tags":["Credits"],"responses":{"200":{"description":"Enriched credit balance.","content":{"application/json":{"schema":{"type":"object","required":["balance_credits","balance_eur","burn_rate_30d_credits","projected_runway_days","tier","tier_resets_at"],"properties":{"balance_credits":{"type":"integer","description":"Current credit balance.","example":4200},"balance_eur":{"type":"number","format":"float","description":"Balance converted to EUR at the published credits-per-EUR rate.","example":42},"burn_rate_30d_credits":{"type":"integer","description":"Credits consumed over the last 30 days.","example":1500},"projected_runway_days":{"type":"integer","description":"Projected days until the balance is exhausted at the 30-day burn rate. -1 when there is no recent consumption.","example":84},"tier":{"type":"string","description":"API tier of the organization.","example":"free"},"tier_resets_at":{"type":"string","format":"date-time","description":"Start of the next monthly tier period (1st of next month, UTC).","example":"2026-05-01T00:00:00.000Z"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/credits/history":{"get":{"operationId":"getCreditsHistory","summary":"Get credit history","description":"Returns credit transaction history (purchases, consumption, adjustments, bonuses), most recent first, with page/limit pagination.","tags":["Credits"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (1-based)."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Items per page (max 100)."}],"responses":{"200":{"description":"Paginated credit history.","content":{"application/json":{"schema":{"type":"object","required":["items","total","page","limit"],"properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"customer_id":{"type":"string","format":"uuid"},"user_id":{"type":["string","null"],"format":"uuid"},"amount":{"type":"integer","description":"Credit amount. Positive = credit, negative = debit."},"type":{"type":"string","description":"Transaction type: purchase, consumption, adjustment, bonus."},"description":{"type":["string","null"]},"operation_type":{"type":["string","null"],"description":"Pipeline stage that consumed credits, if applicable."},"metadata":{"type":"object","additionalProperties":true},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}},"total":{"type":"integer","description":"Total number of transactions."},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/credits/usage":{"get":{"operationId":"getCreditsUsage","summary":"Get usage statistics","description":"Returns aggregated API usage stats grouped by operation type and model over the given period.","tags":["Credits"],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30},"description":"Reporting window in days."}],"responses":{"200":{"description":"Aggregated usage stats.","content":{"application/json":{"schema":{"type":"object","required":["stats","period_days"],"properties":{"stats":{"type":"array","items":{"type":"object","properties":{"operation_type":{"type":"string"},"model":{"type":"string"},"call_count":{"type":"integer"},"total_input_tokens":{"type":"string","description":"Summed input tokens (serialized as a string)."},"total_output_tokens":{"type":"string","description":"Summed output tokens (serialized as a string)."},"total_cache_read_tokens":{"type":"string","description":"Summed cache-read tokens (serialized as a string)."},"total_cost_usd":{"type":["string","null"],"description":"Estimated total cost in USD (serialized as a string)."}}}},"period_days":{"type":"integer","example":30}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/credits/usage/daily":{"get":{"operationId":"getCreditsUsageDaily","summary":"Get daily usage breakdown","description":"Returns per-day API usage for the specified period (default last 30 days) as a JSON array.","tags":["Credits"],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30},"description":"Reporting window in days."}],"responses":{"200":{"description":"Daily usage breakdown.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"calls":{"type":"integer"},"input_tokens":{"type":"string","description":"Summed input tokens for the day (serialized as a string)."},"output_tokens":{"type":"string","description":"Summed output tokens for the day (serialized as a string)."},"cost_usd":{"type":["string","null"],"description":"Estimated cost in USD for the day (serialized as a string)."}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/credits/usage/log":{"get":{"operationId":"getCreditsUsageLog","summary":"Get credit usage log","description":"Returns a detailed per-request usage log with model, tokens, and cost, most recent first, with page/limit pagination.","tags":["Credits"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (1-based)."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Items per page (max 100)."}],"responses":{"200":{"description":"Paginated usage log.","content":{"application/json":{"schema":{"type":"object","required":["items","total","page","limit"],"properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"model":{"type":"string"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer"},"cost_estimate_usd":{"type":["string","null"],"description":"Estimated cost in USD (serialized as a string)."},"operation_type":{"type":"string"},"document_id":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}},"total":{"type":"integer","description":"Total number of log entries."},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ask":{"post":{"operationId":"ask","summary":"Ask a question over your documents","description":"Ask a natural-language question over the workspace corpus and get back a cited,\nverified answer. This is the \"replace your RAG stack\" endpoint: instead of\nchunk-embed-retrieve, the Talonic agent plans over the structured field plane\n(three-plane retrieval: semantic field match, lexical value match, and document\ntext search), runs read-only SQL over extracted cells, extracts-and-persists\nmissing fields at query time, and grounds every load-bearing claim in an exact\nsource span.\n\nOnly `question` is required. The optional fields narrow, route, shape, or\nthread the turn:\n\n- `scope` restricts the turn to a slice of the workspace. The scope is compiled\n  into a parameterized SQL predicate applied to every retrieval plane and every\n  virtual table the agent can query, so it bounds what the agent CAN read rather\n  than suggesting where it should look. `document_ids` is capped at 1000 entries\n  and `tags` at 100. An explicit `\"document_ids\": []` is an active scope that\n  matches nothing; it never means \"unscoped\".\n- `conversation_id` continues an existing conversation, so the agent answers\n  with the prior turns in view. Absent, every ask starts a fresh conversation\n  whose id comes back on the response.\n- `model` runs the turn on a named model, and `model_class` selects a class when\n  `model` is absent. Resolution order: explicit `model`, then `model_class`,\n  then the workspace AI policy binding, then the platform default. A model the\n  workspace AI policy denies fails loudly; it is never silently substituted.\n- `output_format` shapes the final answer with a response-format instruction, a\n  markdown template, or both. It constrains form only, never grounding.\n- `on_behalf_of` opts this single request into compartment-correct retrieval as\n  a named workspace user. Without it the key reads workspace-wide, across every\n  compartment and classification.\n\nThe turn runs detached and typically takes 10-60 seconds, so the endpoint is\nasynchronous: it returns `202` with an `ask_id` immediately. Poll\n`GET /v1/ask/{id}` (about every 2 seconds) or stream `GET /v1/ask/{id}/stream`\nfor the answer.\n\nEach accepted ask charges one flat `agent_ask` credit unit at submission, keyed\nto the turn, so streaming, polling, and retrying the same turn never bill twice\n(see `GET /v1/pricing`). The turn is pinned to the least-privilege viewer role:\nonly read tools run, every mutation is denied before it executes.\n","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","maxLength":20000,"description":"The natural-language question to answer over the workspace corpus.","example":"What is the payment term in the Globex contract, and where does it say so?"},"scope":{"type":"object","description":"Restrict the turn to a slice of the workspace. Present fields are ANDed, and the whole object is enforced as a bound SQL predicate on every retrieval plane. An empty `document_ids` array matches nothing.","properties":{"document_ids":{"type":"array","maxItems":1000,"items":{"type":"string","format":"uuid"},"description":"Restrict to these documents. An empty array matches nothing."},"schema_id":{"type":"string","format":"uuid","description":"Restrict to documents processed by a pipeline of this Spec."},"pipeline_id":{"type":"string","format":"uuid","description":"Restrict to documents attached to this pipeline run."},"data_product_id":{"type":"string","format":"uuid","description":"Restrict to documents behind this data product's pipeline run."},"document_type":{"type":"string","maxLength":200,"description":"Restrict to documents of this classification (a document type name)."},"source_id":{"type":"string","format":"uuid","description":"Restrict to documents ingested through this source connection."},"tags":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":200},"description":"Restrict to documents carrying ANY of these user tags."},"ingested_after":{"type":"string","format":"date-time","description":"Restrict to documents ingested at or after this ISO timestamp."},"ingested_before":{"type":"string","format":"date-time","description":"Restrict to documents ingested at or before this ISO timestamp."}}},"conversation_id":{"type":"string","format":"uuid","description":"Continue this conversation; the agent sees its prior turns."},"model":{"type":"string","maxLength":120,"description":"Run the turn on a specific model (e.g. `claude-opus`). A model the workspace AI policy denies fails loudly; it is never substituted."},"model_class":{"type":"string","maxLength":120,"description":"Run the turn on a model class (e.g. `complex`); used when `model` is absent."},"output_format":{"type":"object","description":"Shape the final answer. Constrains form only, never grounding or citation.","properties":{"instruction":{"type":"string","maxLength":4000,"description":"Free-text response-format instruction, e.g. \"answer as a two-column table\"."},"template":{"type":"string","maxLength":20000,"description":"A markdown skeleton whose headings and order the answer keeps."}}},"on_behalf_of":{"type":"string","format":"uuid","description":"Answer as this workspace user would see it, applying that user's compartment and classification visibility. Opt-in per request; the user must be an active member of the calling workspace."}}},"example":{"question":"Which invoices in this pipeline are overdue, and by how much?","scope":{"pipeline_id":"9e107d9d-372b-4c81-90c3-9dfe9f2c4b6a"},"model_class":"complex","output_format":{"instruction":"Answer as a markdown table with columns invoice, due date, days overdue."}}}}},"responses":{"202":{"description":"Ask accepted; poll `poll_url` or stream `stream_url` for the answer.","content":{"application/json":{"schema":{"type":"object","properties":{"ask_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processing"]},"poll_url":{"type":"string","example":"/v1/ask/3fa85f64-5717-4562-b3fc-2c963f66afa6"},"stream_url":{"type":"string","example":"/v1/ask/3fa85f64-5717-4562-b3fc-2c963f66afa6/stream"},"conversation_id":{"type":"string","format":"uuid","description":"The conversation this ask threads into (created when none was given)."}}},"example":{"ask_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","status":"processing","poll_url":"/v1/ask/3fa85f64-5717-4562-b3fc-2c963f66afa6","stream_url":"/v1/ask/3fa85f64-5717-4562-b3fc-2c963f66afa6/stream","conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits. The body is the agent-actionable `insufficient_credits` contract with `buy_credits_url` and `pricing_url`."},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ask/{id}":{"get":{"operationId":"getAsk","summary":"Poll an ask for its answer","description":"Poll a previously-started ask. Tenant-isolated: an ask that belongs to a different\nworkspace reads as not found. While the turn runs the response is\n`{ \"status\": \"processing\" }` plus `conversation_id`; once completed it carries:\n\n- `answer`: the full answer in markdown, citations inline as links.\n- `citations[]`: the same citations structured: source `document_id`, the cited\n  `quote`, whether it grounds a captured `field` or a verbatim `quote`, the source\n  `filename` when resolved, and a deep `app_url` that opens the document with the\n  span highlighted.\n- `cards[]` and `artifacts[]`: the generative UI cards and artifacts the turn\n  produced, when any.\n- `tool_calls`: how many tool invocations the turn ran, an audit-trail count.\n- `verification`: the post-answer verification verdict: a fast model re-checks the\n  answer's claims against the turn's own tool evidence (`supported` | `issues` |\n  `unverifiable`, with check counts and an optional correction). Treat `issues` as a\n  review pointer, not ground truth.\n- `usage`: token count and the flat `credits_charged`.\n","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The ask's current state (processing, completed, or error).","content":{"application/json":{"schema":{"type":"object","properties":{"ask_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processing","completed","error"]},"poll_url":{"type":"string"},"conversation_id":{"type":"string","format":"uuid","nullable":true},"answer":{"type":"string","description":"Markdown answer (present when completed)."},"citations":{"type":"array","items":{"type":"object","properties":{"quote":{"type":"string"},"document_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["field","quote"]},"reference":{"type":"string"},"filename":{"type":"string","nullable":true},"app_url":{"type":"string"}}}},"cards":{"type":"array","items":{"type":"object"},"description":"Generative UI cards the turn produced (present when completed)."},"artifacts":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"id":{"type":"string"},"label":{"type":"string"},"link":{"type":"string"}}}},"tool_calls":{"type":"integer","description":"Number of tool invocations the turn ran."},"verification":{"type":"object","nullable":true,"properties":{"verdict":{"type":"string","enum":["supported","issues","unverifiable"]},"checks_total":{"type":"integer"},"checks_unsupported":{"type":"integer"},"correction":{"type":"string"}}},"usage":{"type":"object","properties":{"tokens":{"type":"integer","nullable":true},"credits_charged":{"type":"integer"}}}}},"example":{"ask_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","status":"completed","poll_url":"/v1/ask/3fa85f64-5717-4562-b3fc-2c963f66afa6","conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c","answer":"Two invoices are overdue: [INV-1041](https://app.talonic.com/documents/1b6f2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d?cite=due_date) by 12 days and INV-1055 by 3 days.","citations":[{"quote":"INV-1041","document_id":"1b6f2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d","kind":"field","reference":"due_date","filename":"invoice-1041.pdf","app_url":"https://app.talonic.com/documents/1b6f2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d?cite=due_date"}],"cards":[],"artifacts":[],"tool_calls":4,"verification":{"verdict":"supported","checks_total":3,"checks_unsupported":0},"usage":{"tokens":18432,"credits_charged":100}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ask/{id}/stream":{"get":{"operationId":"streamAsk","summary":"Stream an ask over server-sent events","description":"Stream a turn's events as they happen instead of polling. The response is\n`text/event-stream`: every frame is a `data: {json}` line followed by a blank\nline, and a `: keep-alive` comment line goes out every 25 seconds so proxies\nkeep an idle turn's socket open.\n\nThe stream first replays every event the turn has already persisted, then\nfollows with live events, and closes when the turn's `status` reaches\n`completed`, `failed`, or `awaiting_confirmation`. A reconnect therefore loses\nnothing: reopen the stream and the replay delivers the whole turn again.\n\nEach frame is a JSON object discriminated by `kind`: `status`, `stage`, `text`,\n`text.delta`, `tool.call`, `tool.progress`, `tool.result`,\n`confirmation.required`, `card`, `artifact`, and `done`. The model's raw\nreasoning (`thinking.delta`) is deliberately withheld from the public stream.\n\nStreaming is additive: the turn is started (and charged) by `POST /v1/ask`, so\nopening, dropping, and reopening a stream never bills, and the poll contract is\nunchanged. A missing or cross-tenant turn is a real `404` issued before any SSE\nheader goes out, never a `200` stream carrying an error frame. Connects are\nmetered in the `ask_stream` rate-limit namespace, and a workspace can hold at\nmost 20 concurrent streams; the 21st connect is refused with `429`.\n","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server-sent event stream of the turn's frames, closed on terminal status.","content":{"text/event-stream":{"schema":{"type":"string","description":"SSE frames, one JSON object per `data:` line, discriminated by `kind`."},"example":"data: {\"kind\":\"status\",\"status\":\"running\"}\n\ndata: {\"kind\":\"stage\",\"stage\":\"retrieve\",\"state\":\"started\"}\n\ndata: {\"kind\":\"tool.call\",\"id\":\"t1\",\"name\":\"query_data\",\"impact\":\"read\",\"title\":\"Query overdue invoices\",\"args\":{}}\n\ndata: {\"kind\":\"tool.result\",\"id\":\"t1\",\"name\":\"query_data\",\"ok\":true,\"summary\":\"2 rows\",\"durationMs\":412}\n\n: keep-alive\n\ndata: {\"kind\":\"text.delta\",\"text\":\"Two invoices are overdue\"}\n\ndata: {\"kind\":\"done\",\"headline\":\"2 overdue invoices found\"}\n\ndata: {\"kind\":\"status\",\"status\":\"completed\"}\n"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/query":{"post":{"operationId":"startAgentQuery","summary":"Ask the agent (legacy alias of /v1/ask)","description":"Legacy alias of `POST /v1/ask` with a minimal response shape. Starts a read-only\nagent turn (202) to poll via `GET /v1/agent/query/{id}`, which returns only\n`status` and the plain `answer` text. New integrations should use `/v1/ask`,\nwhich adds structured citations, the verification verdict, and usage. Charges the\nsame flat `agent_ask` unit.\n","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":20000}}}}}},"responses":{"202":{"description":"Turn started.","content":{"application/json":{"schema":{"type":"object","properties":{"turnId":{"type":"string","format":"uuid"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits (`insufficient_credits` contract)."},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/query/{id}":{"get":{"operationId":"getAgentQuery","summary":"Poll an agent query (legacy alias)","description":"Poll a turn started via `POST /v1/agent/query`. Returns `status` and the plain answer text; empty until the turn completes.","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The turn's status and answer.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["processing","completed","error"]},"answer":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/agent/context":{"get":{"operationId":"getAgentContext","summary":"Get agent workspace context","description":"Returns the comprehensive workspace overview the embedded agent uses to ground its\nreasoning: organisation name, document and pipeline counts, document types, schemas\nwith field counts, active extraction runs, recent activity feed, and field-registry\nsummary by tier.\n","tags":["Agent"],"responses":{"200":{"description":"Workspace context summary.","content":{"application/json":{"schema":{"type":"object","properties":{"organizationName":{"type":"string","nullable":true},"documents":{"type":"object","properties":{"total":{"type":"integer"},"completedThisWeek":{"type":"integer"},"completedLast24h":{"type":"integer"},"processing":{"type":"integer"}}},"documentTypes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"documentCount":{"type":"integer"}}}},"schemas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"fieldCount":{"type":"integer"},"version":{"type":"integer"}}}},"activeRuns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"status":{"type":"string"},"documentCount":{"type":"integer"}}}},"fieldRegistry":{"type":"object","properties":{"totalFields":{"type":"integer"},"tier1":{"type":"integer"},"tier2":{"type":"integer"},"tier3":{"type":"integer"}}},"recentActivity":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"actor":{"type":"string","nullable":true}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/tools":{"get":{"operationId":"listAgentTools","summary":"List agent tools","description":"Returns the catalogue of tools available to the embedded agent, read live from\nthe loop's registry. Each tool entry carries a stable name, a short description,\nan impact level (`read`, `draft_mutation`, `live_mutation`, `irreversible`), the\ncapability the tool requires, its JSON Schema argument shape (`input_schema`),\nand `can_invoke`: whether THIS key can run it via\n`POST /v1/agent/tools/{name}/invoke`. An API key runs as the least-privilege\nviewer role, so the invocable set is the read subset; the rest are listed so a\ncaller can see the full surface the in-product agent operates.\n","tags":["Agent"],"responses":{"200":{"description":"Tool registry.","content":{"application/json":{"schema":{"type":"object","properties":{"tools":{"type":"array","items":{"type":"object","required":["name","description","impact"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"impact":{"type":"string","enum":["read","draft_mutation","live_mutation","irreversible"]},"capability":{"type":"string","description":"The permission the tool requires (e.g. `data.read`)."},"can_invoke":{"type":"boolean","description":"Whether this key can run the tool via `POST /v1/agent/tools/{name}/invoke`."},"input_schema":{"type":"object","description":"JSON Schema for the tool's `args`."}}}},"totalCount":{"type":"integer"},"invocable_count":{"type":"integer","description":"How many listed tools this key can invoke."}}},"example":{"tools":[{"name":"query_data","impact":"read","capability":"data.read","description":"Runs a read-only SQL query over the structured cell plane.","can_invoke":true,"input_schema":{"type":"object","properties":{"sql":{"type":"string"}}}},{"name":"promote_field","impact":"draft_mutation","capability":"data.promote","description":"Makes an already-captured field queryable.","can_invoke":false,"input_schema":{"type":"object","properties":{"field_id":{"type":"string"}}}}],"totalCount":61,"invocable_count":32}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/tools/{name}/invoke":{"post":{"operationId":"invokeAgentTool","summary":"Invoke one agent tool directly","description":"Run ONE named tool directly, with no model in the loop: the caller supplies the\narguments the agent would otherwise choose. This is the seam for building your\nown agent on top of Talonic's retrieval and provenance while driving control\nflow yourself.\n\nThe same capability matrix the agent loop applies governs this route, so a key\ncan only run the tools whose `can_invoke` is `true` on `GET /v1/agent/tools`;\na denied tool answers `403` naming the capability it needs. `scope` and\n`on_behalf_of` behave exactly as on `POST /v1/ask`: the scope is a bound SQL\npredicate, and `on_behalf_of` applies that user's compartment visibility.\n\nDirect invocation charges no credits: every tool this key can reach does no\nmodel work, so there is no model call to meter. The route is bounded by the\n`agent_tools` rate-limit namespace instead. A tool that runs but fails answers\n`422` with the tool's own failure summary.\n","tags":["Agent"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"The tool name as listed by `GET /v1/agent/tools`."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"args":{"type":"object","description":"Arguments matching the tool's `input_schema` from `GET /v1/agent/tools`."},"scope":{"type":"object","description":"Restrict the invocation to a slice of the workspace, exactly as on `POST /v1/ask`."},"on_behalf_of":{"type":"string","format":"uuid","description":"Apply this workspace user's compartment visibility to the invocation."}}},"example":{"args":{"query":"termination notice period"},"scope":{"document_type":"Master Services Agreement"}}}}},"responses":{"200":{"description":"The tool ran; its raw output plus any cards, artifacts, and citations.","content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"type":"string"},"ok":{"type":"boolean"},"content":{"type":"string","description":"The tool's raw output, usually JSON serialized as a string."},"cards":{"type":"array","items":{"type":"object"}},"artifacts":{"type":"array","items":{"type":"object"}},"citations":{"type":"array","items":{"type":"object","properties":{"quote":{"type":"string"},"document_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["field","quote"]},"reference":{"type":"string"},"filename":{"type":"string","nullable":true},"app_url":{"type":"string"}}}}}},"example":{"tool":"query_data","ok":true,"content":"[{\"invoice\":\"INV-1041\",\"days_overdue\":12}]","cards":[],"artifacts":[],"citations":[]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The tool requires a capability this key's role does not grant; the message names it."},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"The tool itself failed; the message is the tool's failure summary."},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/conversations":{"get":{"operationId":"listAgentConversations","summary":"List agent conversations","description":"List the conversations asks have threaded into, newest activity first,\nkeyset-paginated: pass the previous page's `next_cursor` as `cursor` to\ncontinue, until `next_cursor` is null.\n\nConversations belong to the workspace's API principal, not to a platform user:\na key sees the asks made through the API and never a colleague's in-product\nagent chat. `on_behalf_of` selects the separate partition of conversations run\nfor that user, so per-user threads never mix.\n","tags":["Agent"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":30},"description":"Page size (1-100)."},{"name":"cursor","in":"query","schema":{"type":"string","format":"date-time"},"description":"The previous page's `next_cursor`."},{"name":"on_behalf_of","in":"query","schema":{"type":"string","format":"uuid"},"description":"List the conversation partition of this workspace user."}],"responses":{"200":{"description":"One page of conversations, newest activity first.","content":{"application/json":{"schema":{"type":"object","properties":{"conversations":{"type":"array","items":{"type":"object","properties":{"conversation_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"turn_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"last_activity_at":{"type":"string","format":"date-time"}}}},"next_cursor":{"type":"string","format":"date-time","nullable":true,"description":"Pass as `cursor` for the next page; null when this is the last page."}}},"example":{"conversations":[{"conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c","title":"Overdue invoices in Q3","turn_count":3,"created_at":"2026-07-30T09:12:00.000Z","last_activity_at":"2026-07-30T09:41:00.000Z"}],"next_cursor":null}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/agent/conversations/{id}":{"get":{"operationId":"getAgentConversation","summary":"Get one conversation with its asks","description":"One conversation with its asks in order, oldest first. Each turn carries the\nquestion, its lifecycle status (`processing` | `completed` | `error`), and the\nanswer text once settled. Tenant-isolated and partition-scoped: a conversation\nof another workspace, or of another `on_behalf_of` partition, reads as not\nfound.\n","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"on_behalf_of","in":"query","schema":{"type":"string","format":"uuid"},"description":"Read from the conversation partition of this workspace user."}],"responses":{"200":{"description":"The conversation and its turns.","content":{"application/json":{"schema":{"type":"object","properties":{"conversation_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"turns":{"type":"array","items":{"type":"object","properties":{"ask_id":{"type":"string","format":"uuid"},"question":{"type":"string"},"status":{"type":"string","enum":["processing","completed","error"]},"answer":{"type":"string","description":"The answer markdown; empty until the turn completes."},"created_at":{"type":"string","format":"date-time"}}}}}},"example":{"conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c","title":"Overdue invoices in Q3","created_at":"2026-07-30T09:12:00.000Z","turns":[{"ask_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","question":"Which invoices in this pipeline are overdue, and by how much?","status":"completed","answer":"Two invoices are overdue: INV-1041 by 12 days and INV-1055 by 3 days.","created_at":"2026-07-30T09:12:00.000Z"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"renameAgentConversation","summary":"Rename a conversation","description":"Rename a conversation. The title is trimmed server-side and capped at 300\ncharacters. Requires the `write` scope.\n","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"on_behalf_of","in":"query","schema":{"type":"string","format":"uuid"},"description":"Rename within the conversation partition of this workspace user."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":300}}},"example":{"title":"Q3 collections review"}}}},"responses":{"200":{"description":"The conversation's new title.","content":{"application/json":{"schema":{"type":"object","properties":{"conversation_id":{"type":"string","format":"uuid"},"title":{"type":"string"}}},"example":{"conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c","title":"Q3 collections review"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"delete":{"operationId":"deleteAgentConversation","summary":"Delete a conversation","description":"Delete a conversation. It disappears from the list and can no longer be\ncontinued; the asks themselves stay readable by id via `GET /v1/ask/{id}`,\nbecause they are the caller's own answer history. Requires the `write` scope.\n","tags":["Agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"on_behalf_of","in":"query","schema":{"type":"string","format":"uuid"},"description":"Delete within the conversation partition of this workspace user."}],"responses":{"200":{"description":"The conversation was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"conversation_id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}}},"example":{"conversation_id":"8c4f2a1e-0b6d-4e2f-9a3c-5d7e1f2a3b4c","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/exports/{path}":{"get":{"operationId":"deprecatedExportsGet","summary":"Deprecated exports endpoint (any verb)","deprecated":true,"description":"The `/v1/exports/*` namespace was retired on 2026-04-21 in favour of the unified\n`/v1/delivery/*` surface. All requests against any verb of this path return\n`410 Gone` with a pointer to the replacement endpoint. This entry exists so SDK\ngenerators see the deprecation flag; do not call.\n","tags":["Delivery"],"parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"},"description":"Any sub-path under `/v1/exports/`."}],"x-sunset":"2026-04-21","responses":{"410":{"description":"Gone — use `/v1/delivery/*` instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/cases/{key}/status":{"patch":{"operationId":"updateCaseStatus","x-required-scopes":["write"],"summary":"Update case status","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","example":"completed","description":"New status (e.g. open, in_review, resolved, archived)."}}}}}},"responses":{"200":{"description":"Case status updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaseDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/edges":{"get":{"operationId":"getCaseEdges","x-required-scopes":["read"],"summary":"Get case edges","description":"Returns the entity edges (evidence chain) connecting documents within the case.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"responses":{"200":{"description":"Case edges.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"source_document_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"target_document_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"entity_value":{"type":"string"},"entity_type":{"type":"string"},"confidence":{"type":"number","format":"float"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/edges/{edgeId}/confirm":{"post":{"operationId":"confirmCaseEdge","x-required-scopes":["write"],"summary":"Confirm a case edge","description":"Confirm a proposed entity edge between documents in this case.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."},{"name":"edgeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Edge identifier from the case edges list."}],"responses":{"200":{"description":"Edge confirmed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/edges/{edgeId}/reject":{"post":{"operationId":"rejectCaseEdge","x-required-scopes":["write"],"summary":"Reject a case edge","description":"Reject a proposed entity edge between documents in this case.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."},{"name":"edgeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Edge identifier from the case edges list."}],"responses":{"200":{"description":"Edge rejected.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/anomalies":{"get":{"operationId":"getCaseAnomalies","x-required-scopes":["read"],"summary":"Get case anomalies","description":"Detector anomalies for the case (the risk surface) — field conflicts, divergent shared keys, suspicious value reuse, missing-document-type signals — plus open dangling-reference findings and the matched workflow template. Computed on-read from the case's field occurrences; no LLM, nothing persisted.\n","tags":["Cases"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"responses":{"200":{"description":"Anomalies, findings, and matched template.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"severity":{"type":"string","enum":["critical","warning","info"]},"title":{"type":"string"},"description":{"type":"string"},"document_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"targets":{"type":"array","items":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid"},"field":{"type":"string"},"value":{"type":"string"}}}}}}},"findings":{"type":"array","items":{"type":"object"}},"template":{"type":"object","nullable":true}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/cases/{key}/evidence":{"get":{"operationId":"getCaseEvidence","x-required-scopes":["read"],"summary":"Get case evidence","description":"The case's connective evidence: the shared-reference `connections` that join its documents (each with the via-field, value, kind, confidence, and any curator verdict), the open `gaps` (dangling references / missing documents), and the member documents. The synth case evidence model — why these documents form one case and what is still missing.\n","tags":["Cases"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"responses":{"200":{"description":"Connections, gaps, and documents.","content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","properties":{"document_a":{"type":"string","format":"uuid"},"document_b":{"type":"string","format":"uuid","nullable":true},"via_field":{"type":"string"},"value":{"type":"string"},"kind":{"type":"string"},"confidence":{"type":"number","nullable":true},"verdict":{"type":"string","nullable":true}}}},"gaps":{"type":"array","items":{"type":"object"}},"documents":{"type":"array","items":{"type":"object"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/cases/{key}/split":{"post":{"operationId":"splitCase","x-required-scopes":["write"],"summary":"Split a case","description":"Split a case into two separate cases by partitioning its documents into two groups.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["partition_b"],"properties":{"partition_b":{"type":"array","items":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Document IDs that move out into the newly-created case (non-empty strict subset). Everything not listed stays on the existing case."},"partition_a":{"type":"array","items":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Informational only — the kept documents are derived as the complement of partition_b."}}}}}},"responses":{"200":{"description":"Case split.","content":{"application/json":{"schema":{"type":"object","required":["source_id","new_case_id","moved"],"properties":{"source_id":{"type":"string","format":"uuid","description":"UUID of the existing case (retains the documents not listed in partition_b)."},"new_case_id":{"type":"string","format":"uuid","description":"UUID of the newly created case holding the partition_b documents."},"moved":{"type":"integer","description":"Count of documents moved into the new case."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/merge":{"post":{"operationId":"mergeCases","x-required-scopes":["write"],"summary":"Merge two cases","description":"Absorb case B into case A by passing both case UUIDs in the request\nbody. A's documents/links/findings are kept and B's are reparented onto\nA; B is tombstoned (excluded from future rebuilds, never deleted).\n","tags":["Cases"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["case_key_a","case_key_b"],"properties":{"case_key_a":{"type":"string","format":"uuid","description":"UUID of the surviving target case — receives the merged documents."},"case_key_b":{"type":"string","format":"uuid","description":"UUID of the absorbed case — its documents are folded into case A."}}}}}},"responses":{"200":{"description":"Cases merged. Returns the surviving (target) case row — an object\ncarrying at least `id`, `case_key`, `status`, `display_name`,\n`assignee`, `resolution_notes`, `title`, `blurb`, `summary`,\n`source`, `stale`, and build timestamps.\n","content":{"application/json":{"schema":{"type":"object","description":"The surviving target case row.","properties":{"id":{"type":"string","format":"uuid"},"case_key":{"type":"string"},"status":{"type":"string","enum":["discovered","confirmed","active","resolved"]},"display_name":{"type":["string","null"]}},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/completeness":{"get":{"operationId":"getCaseCompleteness","x-required-scopes":["read"],"summary":"Get case completeness","description":"Returns a completeness assessment for the case (expected vs. present document types, missing fields).","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."}],"responses":{"200":{"description":"Completeness assessment.","content":{"application/json":{"schema":{"type":"object","properties":{"completeness_score":{"type":"number","format":"float"},"expected_document_types":{"type":"array","items":{"type":"string"}},"present_document_types":{"type":"array","items":{"type":"string"}},"missing_document_types":{"type":"array","items":{"type":"string"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/documents/{docId}/pin":{"post":{"operationId":"pinCaseDocument","x-required-scopes":["write"],"summary":"Pin a document to a case","description":"Manually pin a document to a case so it persists across re-clustering.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."},{"name":"docId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Document identifier to pin."}],"responses":{"200":{"description":"Document pinned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaseDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/cases/{key}/documents/{docId}":{"delete":{"operationId":"removeCaseDocument","x-required-scopes":["write"],"summary":"Remove a document from a case","description":"Remove a manually-pinned document from a case.","tags":["Cases"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Case UUID (the stable resource id)."},{"name":"docId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Document identifier to remove."}],"responses":{"200":{"description":"Document removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaseDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/batches/{id}/sync":{"post":{"operationId":"syncBatch","summary":"Sync batch status with provider","description":"Force a status sync with the batch inference provider (Anthropic or Bedrock).","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Batch synced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/batches/{id}/cancel":{"post":{"operationId":"cancelBatch","summary":"Cancel a batch inference run","description":"Cancel an in-flight batch. Only batches in `accumulating` or `submitted` status can be cancelled.","tags":["Jobs & Batches"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Batch cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/configs/{id}/smart-run":{"post":{"operationId":"triggerSmartMatchingRun","summary":"Trigger a smart matching run for a config","description":"Run a previously-generated AI matching strategy against the documents scoped by the matching config.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["strategy_id"],"properties":{"strategy_id":{"type":"string","format":"uuid","example":"c9d0e1f2-a3b4-5678-cdef-789012345678","description":"Strategy generated via POST /v1/matching/strategies/generate to execute against this config."}}}}}},"responses":{"201":{"description":"Smart matching run queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchingRunResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{id}/ai-resolve":{"post":{"operationId":"aiResolveMatchingRun","summary":"AI-resolve a matching run's review band","description":"Trigger AI-driven resolution on a completed matching run's review-band candidates. Requires the run to have an associated strategy.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"AI resolution started.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"message":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/strategies/generate":{"post":{"operationId":"generateMatchingStrategy","summary":"Generate a matching strategy","description":"Synthesize a draft matching strategy by analysing reference data shape and the supplied target descriptor. Returns the generated strategy entity for review and execution via /v1/matching/configs/{id}/smart-run.","tags":["Matching"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reference_data_id","target_type"],"properties":{"reference_data_id":{"type":"string","format":"uuid","description":"Reference dataset to use as the source of truth."},"target_type":{"type":"string","description":"Target scope type — e.g. \"run\", \"schema\", \"document_filter\"."},"target_value":{"type":"object","additionalProperties":true,"description":"Target descriptor payload — shape depends on target_type."},"user_prompt":{"type":"string","description":"Optional natural-language guidance to steer strategy synthesis."}}}}}},"responses":{"201":{"description":"Strategy generated.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/strategies/{id}":{"get":{"operationId":"getMatchingStrategy","summary":"Get a matching strategy","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching strategy detail.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"updateMatchingStrategy","summary":"Update a matching strategy","description":"Patch an existing strategy. Every property is optional; only the keys present on the body are merged into the strategy.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reasoning_summary":{"type":"string"},"cardinality":{"type":"object","additionalProperties":true},"data_quality_notes":{"type":"array","items":{"type":"string"}},"blocking_keys":{"type":"array","items":{"type":"object","additionalProperties":true}},"blocking_strategy":{"type":"string","enum":["parallel","ordered_fallback"]},"hard_filters":{"type":"array","items":{"type":"object","additionalProperties":true}},"field_rules":{"type":"array","items":{"type":"object","additionalProperties":true}},"thresholds":{"type":"object","additionalProperties":true},"edge_cases":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"responses":{"200":{"description":"Matching strategy updated.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{id}/results":{"get":{"operationId":"getMatchingRunResults","summary":"Get matching run results","description":"Returns per-document match results with top candidates and field-level evidence.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching run results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{id}/progress":{"get":{"operationId":"getMatchingRunProgress","summary":"Get matching run progress","description":"Returns the processing progress for an in-flight matching run.","tags":["Matching"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Matching run progress.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"processed":{"type":"integer"},"total":{"type":"integer"},"percentage":{"type":"number","format":"float"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/matching/runs/{runId}/results/{resultId}/review":{"post":{"operationId":"reviewMatchingResult","summary":"Review a single match result","description":"Apply an approve/reject decision (or record notes) on a single match result within a matching run.","tags":["Matching"],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Matching run identifier."},{"name":"resultId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Match result identifier within the run."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","description":"Reviewer decision — typically \"approved\" or \"rejected\"."},"notes":{"type":"string","description":"Optional reviewer note attached to the decision."}}}}}},"responses":{"200":{"description":"Review decision applied.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review/{id}/assign":{"post":{"operationId":"assignReviewRecord","summary":"Assign a review record to a user","description":"Set the assignee on a single review record. Pass `user_id: null` to unassign.","tags":["Review"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_id"],"properties":{"user_id":{"type":"string","format":"uuid","nullable":true,"example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"User ID of the assignee, or `null` to unassign."}}}}}},"responses":{"200":{"description":"Record assigned.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/review/stats":{"get":{"operationId":"getReviewStats","summary":"Get review queue statistics","description":"Returns aggregate review queue counts grouped by status.","tags":["Review"],"responses":{"200":{"description":"Review statistics.","content":{"application/json":{"schema":{"type":"object","required":["total","by_status"],"properties":{"total":{"type":"integer","description":"Total number of review records.","example":42},"by_status":{"type":"object","description":"Count of review records per status (e.g. pending, approved, rejected).","additionalProperties":{"type":"integer"},"example":{"pending":12,"approved":25,"rejected":5}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/ground-truth/{id}/entries":{"get":{"operationId":"listGroundTruthEntries","summary":"List entries in a ground truth dataset","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Paginated list of ground truth entries.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GroundTruthEntryItem"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"post":{"operationId":"createGroundTruthEntry","summary":"Add an entry to a ground truth dataset","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["expected_data"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"expected_data":{"type":"object","additionalProperties":true},"notes":{"type":"string","example":"Reviewed and confirmed."}}}}}},"responses":{"201":{"description":"Entry created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthEntryItem"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/ground-truth/{id}/entries/{entryId}":{"delete":{"operationId":"deleteGroundTruthEntry","summary":"Delete a ground truth entry","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"},{"name":"entryId","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Entry ID."}],"responses":{"200":{"description":"Entry deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/benchmarks/compare":{"get":{"operationId":"compareBenchmarkRuns","summary":"Compare two benchmark runs","description":"Returns both benchmark runs side by side together with the overall accuracy delta (run_a minus run_b). The delta is null when either run has not yet produced an overall accuracy score.","tags":["Benchmarks"],"parameters":[{"name":"run_a","in":"query","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"ID of the first benchmark run."},{"name":"run_b","in":"query","required":true,"schema":{"type":"string","format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"description":"ID of the second benchmark run to compare against."}],"responses":{"200":{"description":"Both benchmark runs and their accuracy delta.","content":{"application/json":{"schema":{"type":"object","properties":{"run_a":{"$ref":"#/components/schemas/BenchmarkResponse"},"run_b":{"$ref":"#/components/schemas/BenchmarkResponse"},"accuracy_delta":{"type":["number","null"],"format":"float","description":"Overall accuracy of run_a minus run_b, or null if either is unscored."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/quality/benchmarks/{id}/results":{"get":{"operationId":"getBenchmarkResults","summary":"Get benchmark results","description":"Returns per-document accuracy results for a benchmark run.","tags":["Benchmarks"],"parameters":[{"$ref":"#/components/parameters/ResourceId"}],"responses":{"200":{"description":"Benchmark results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BenchmarkResultItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/process":{"post":{"operationId":"submitProcess","summary":"Submit a document for processing","deprecated":true,"description":"Deprecated: prefer `/v1/pipelines` for new integrations; this endpoint remains supported.\n\nUpload a document and trigger a configured processing pipeline.\nAlways returns 202. Results delivered via `process.completed` webhook.\n\nIdempotency is automatic: the same (config_id, batch_id, file) combination\nreturns the existing run without re-processing. If batch_id is absent,\ndedup applies within a 24-hour window.\n","tags":["Process"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["config_id","file"],"properties":{"config_id":{"type":"string","example":"cfg_bridgeway_invoice_v1","description":"Processing configuration ID (from GET /v1/configs)."},"batch_id":{"type":"string","example":"BW-2026-0512-001","description":"Optional batch identifier. Enables permanent dedup for this (config, batch, file) triple."},"file":{"type":"string","format":"binary","description":"Document file to process. Max 500 MB."},"metadata":{"type":"string","description":"Optional JSON string with additional metadata."}}}}}},"responses":{"200":{"description":"Idempotency hit — returning existing run result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunResponse"}}}},"202":{"description":"Processing accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string"},"run_id":{"type":"string","format":"uuid"},"config_id":{"type":"string"},"batch_id":{"type":"string"},"status":{"type":"string","enum":["processing"]},"poll_url":{"type":"string"}}}}}},"400":{"description":"Missing required field (config_id or file)."},"402":{"description":"Insufficient credits."},"404":{"description":"Config ID not found or inactive."}},"security":[{"BearerAuth":[]}]}},"/v1/runs/{id}":{"get":{"operationId":"getRun","summary":"Get processing run status","description":"Poll for run status and result.","tags":["Process"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Run status and result (if completed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunResponse"}}}},"404":{"description":"Run not found."}},"security":[{"BearerAuth":[]}]}},"/v1/configs":{"get":{"operationId":"listConfigs","summary":"List available processing configs","deprecated":true,"description":"Deprecated: prefer `/v1/pipelines` for new integrations; this endpoint remains supported. Returns all processing configurations available to your organization.\n","tags":["Process"],"responses":{"200":{"description":"List of configs.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConfigResponse"}}}}}}}},"security":[{"BearerAuth":[]}]}},"/v1/configs/{id}":{"get":{"operationId":"getConfig","summary":"Get a processing config","description":"Returns details of a specific processing configuration.","tags":["Process"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"cfg_bridgeway_invoice_v1"}}],"responses":{"200":{"description":"Config details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigResponse"}}}},"404":{"description":"Config not found."}},"security":[{"BearerAuth":[]}]}},"/v1/data-products":{"get":{"tags":["Data Products"],"summary":"List data products","description":"Returns a paginated list of data products for the authenticated organization.","operationId":"listDataProducts","security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","ready","published","archived"]},"description":"Filter by status"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of data products","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DataProduct"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"tags":["Data Products"],"summary":"Create a data product","description":"Creates a data product from one or more completed job/resolution runs and mints its share token. Run-backed only; the validation-session and pipeline-backed create paths remain internal. Requires the `write` scope.\n","operationId":"createDataProduct","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","run_ids"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"run_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Completed job/resolution run IDs that feed the product."},"thresholds":{"type":"object","description":"Quality thresholds (min_confidence, require_validation_pass, require_approval)."}}}}}},"responses":{"201":{"description":"Created data product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataProduct"}}}},"400":{"description":"Validation error"}}}},"/v1/data-products/{id}":{"get":{"tags":["Data Products"],"summary":"Get a data product","operationId":"getDataProduct","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Data product details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataProduct"}}}},"404":{"description":"Data product not found"}}},"delete":{"tags":["Data Products"],"summary":"Delete a data product","operationId":"deleteDataProduct","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Successfully deleted"}}}},"/v1/data-products/{id}/results":{"get":{"tags":["Data Products"],"summary":"Get data product results","description":"Returns paginated results for a data product.","operationId":"getDataProductResults","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Paginated results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","description":"Result row with field values"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/v1/data-products/{id}/export/plain":{"get":{"tags":["Data Products"],"summary":"Export data product as plain CSV","description":"Returns the data product's values as a CSV attachment. For a pipeline-backed product, cells still held in the review queue (`pending_approval`) are written empty; the held value never leaves the API.\n","operationId":"exportDataProductPlain","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{"schema":{"type":"string"}}}},"404":{"description":"Data product not found"}}}},"/v1/data-products/{id}/export/audit":{"get":{"tags":["Data Products"],"summary":"Export data product audit CSV","description":"Returns the audit CSV (the handover trail) as an attachment. Held pipeline-backed cells are written as `PENDING_REVIEW` markers.\n","operationId":"exportDataProductAudit","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{"schema":{"type":"string"}}}},"404":{"description":"Data product not found"}}}},"/v1/data-policies":{"get":{"tags":["Data Policies"],"summary":"List data policies","operationId":"listDataPolicies","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of data policies","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DataPolicy"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"tags":["Data Policies"],"summary":"Create a data policy","operationId":"createDataPolicy","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"Invoice Processing Policy"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPolicy"}}}}}}},"/v1/data-policies/{id}":{"get":{"tags":["Data Policies"],"summary":"Get a data policy with fields and rules","operationId":"getDataPolicy","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Policy with inlined fields and rules","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/DataPolicy"},{"type":"object","properties":{"fields":{"type":"array","items":{"$ref":"#/components/schemas/DataPolicyField"}},"rules":{"type":"array","items":{"$ref":"#/components/schemas/DataPolicyRule"}}}}]}}}}}},"patch":{"tags":["Data Policies"],"summary":"Update a data policy","operationId":"updateDataPolicy","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Data Policies"],"summary":"Delete a data policy","operationId":"deleteDataPolicy","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/data-policies/{id}/versions":{"get":{"tags":["Data Policies"],"summary":"List policy versions","operationId":"listDataPolicyVersions","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of versions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version_number":{"type":"integer"},"status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}}}}}}}}},"/v1/data-policies/{id}/fields":{"get":{"tags":["Data Policies"],"summary":"List policy fields","operationId":"listDataPolicyFields","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of fields","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DataPolicyField"}}}}}}}}}},"/v1/data-policies/{id}/rules":{"get":{"tags":["Data Policies"],"summary":"List policy rules","operationId":"listDataPolicyRules","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of rules ordered by ordinal","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DataPolicyRule"}}}}}}}}}},"/v1/record-sets":{"get":{"tags":["Record Sets"],"summary":"List record sets","description":"Returns a paginated list of record sets (value-plane tables).","operationId":"listRecordSets","security":[{"BearerAuth":[]}],"parameters":[{"name":"layer","in":"query","schema":{"type":"string","enum":["capture","structured","resolved","product"]},"description":"Filter by value layer"},{"name":"kind","in":"query","schema":{"type":"string"},"description":"Filter by source kind (e.g. structuring_run, resolution_run, data_product)"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated list of record sets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RecordSet"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/v1/record-sets/{id}":{"get":{"tags":["Record Sets"],"summary":"Get a record set","operationId":"getRecordSet","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Record set details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordSet"}}}}}}},"/v1/record-sets/{id}/fields":{"get":{"tags":["Record Sets"],"summary":"List record set fields","operationId":"listRecordSetFields","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ordered list of fields","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"field_key":{"type":"string"},"display_name":{"type":"string","description":"Human-readable label, always present. A stored display name wins; otherwise derived from `field_key`, e.g. `charge_type` → `Charge Type`."},"data_type":{"type":"string"},"position":{"type":"integer"},"is_required":{"type":"boolean"},"is_hidden":{"type":"boolean"}}}},"links":{"type":"object","properties":{"self":{"type":"string"},"record_set":{"type":"string"}}}}}}}}}}},"/v1/record-sets/{id}/records":{"get":{"tags":["Record Sets"],"summary":"Get record set records (paginated)","description":"Returns records with offset-based pagination.","operationId":"listRecordSetRecords","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"include","in":"query","schema":{"type":"string","enum":["values"]},"description":"Pass `include=values` to attach each record's latest-version cell values keyed by field key. A cell held for review (`pending_approval`) reports its status with a null value.\n"}],"responses":{"200":{"description":"Paginated records","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"document_id":{"type":["string","null"],"format":"uuid"},"ordinal":{"type":"integer"},"record_key":{"type":["string","null"]},"status":{"type":"string"},"confidence":{"type":["number","null"]},"values":{"type":"object","description":"Only present with `include=values`. Map of field key to the record's latest cell value.\n","additionalProperties":{"type":"object","properties":{"value":{"description":"Cell value. Null when the cell is held for review."},"status":{"type":"string"},"confidence":{"type":["number","null"]}}}}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"has_more":{"type":"boolean"}}},"links":{"type":"object","properties":{"self":{"type":"string"},"record_set":{"type":"string"}}}}}}}}}}},"/v1/record-sets/{id}/export":{"get":{"tags":["Record Sets"],"summary":"Export all records","description":"Returns all records in the set as a JSON array. Use for smaller datasets.","operationId":"exportRecordSet","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"All records","content":{"application/json":{"schema":{"type":"object","properties":{"record_set_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"total":{"type":"integer"},"records":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"document_id":{"type":["string","null"],"format":"uuid"},"ordinal":{"type":"integer"},"record_key":{"type":["string","null"]},"status":{"type":"string"},"confidence":{"type":["number","null"]}}}}}}}}}}}},"/v1/nodes/transfer":{"post":{"tags":["Nodes"],"summary":"Run a Transfer node (Field Registry)","description":"Fill a schema's cells from the Field Registry over the given documents (no LLM extraction), creating a new record set. The documents must already have been ingested + registry-extracted. Returns 202 with the node run and its `record_set_id` — chain later nodes (extract/resolve/validate/assemble) by passing that id. Node-jobs are the primitive tier: no review/blocking holds (that stays on POST /v1/pipelines).\n","operationId":"runTransferNode","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["schema_id","document_ids"],"properties":{"schema_id":{"type":"string","format":"uuid"},"document_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"202":{"description":"Node job created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"400":{"description":"Invalid request"},"404":{"description":"Schema or a document not found"}}}},"/v1/nodes/extract":{"post":{"tags":["Nodes"],"summary":"Run an Extraction node (LLM)","description":"LLM-extract a schema's fields. Start a fresh canvas with `document_ids`, or extract into an existing `record_set_id` (e.g. after a transfer node — already filled fields are skipped). Provide exactly one. Optional `field_keys` scopes extraction to a subset of the schema.\n","operationId":"runExtractNode","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["schema_id"],"properties":{"schema_id":{"type":"string","format":"uuid"},"document_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"record_set_id":{"type":"string","format":"uuid"},"field_keys":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"202":{"description":"Node job created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"400":{"description":"Invalid request (provide either document_ids or record_set_id)"},"404":{"description":"Schema","documents":null,"or record set not found":null}}}},"/v1/nodes/resolve":{"post":{"tags":["Nodes"],"summary":"Run a Resolution node (Data Policies)","description":"Apply one or more Data Policies, in order, to an existing record set (the same One Engine ResolutionPhase the pipeline uses). New resolved cell versions are written into the record set.\n","operationId":"runResolveNode","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["record_set_id","policy_ids"],"properties":{"record_set_id":{"type":"string","format":"uuid"},"policy_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"202":{"description":"Node job created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"400":{"description":"Invalid request"},"404":{"description":"Record set or a policy not found"}}}},"/v1/nodes/validate":{"post":{"tags":["Nodes"],"summary":"Run a Validation node (raw verdicts)","description":"Validate a record set and return per-field verdicts. Supply a saved `validation_stage_id` or an inline `gate` config; default is structural evidence checks only (n-shot off, to bound cost). Raw mode — flagged cell status is written, but there are NO review-queue holds or field blocking (that governed flow stays on POST /v1/pipelines). Read verdicts from GET /v1/nodes/{id}/results.\n","operationId":"runValidateNode","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["record_set_id","schema_id"],"properties":{"record_set_id":{"type":"string","format":"uuid"},"schema_id":{"type":"string","format":"uuid"},"validation_stage_id":{"type":"string","format":"uuid"},"gate":{"type":"object","description":"Inline gate config: { evidence?, nshot?, llmJudge?, businessRules?, groundTruth? }"}}}}}},"responses":{"202":{"description":"Node job created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"400":{"description":"Invalid request"},"404":{"description":"Record set","schema":null,"or validation stage not found":null}}}},"/v1/nodes/assemble":{"post":{"tags":["Nodes"],"summary":"Run an Assembly node","description":"Compose a product record set from an existing record set: group documents by `grouping_field`, pick the Anchor (matching `anchor_values` on `anchor_field`), and apply Amendment overrides. Returns a node run whose `product_record_set_id` holds the composed records.\n","operationId":"runAssembleNode","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["record_set_id","assembly_config"],"properties":{"record_set_id":{"type":"string","format":"uuid"},"assembly_config":{"type":"object","required":["grouping_field","anchor_field"],"properties":{"grouping_field":{"type":"string"},"anchor_field":{"type":"string"},"anchor_values":{"type":"array","items":{"type":"string"}},"signed_field":{"type":"string"},"date_field":{"type":"string"},"amendable_fields":{"type":"array","items":{"type":"string"}}}}}}}}},"responses":{"202":{"description":"Node job created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"400":{"description":"Invalid request (assembly_config needs grouping_field + anchor_field)"},"404":{"description":"Record set not found"}}}},"/v1/nodes/{id}":{"get":{"tags":["Nodes"],"summary":"Get a node job (poll status)","operationId":"getNodeRun","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Node run status + progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeRun"}}}},"404":{"description":"Node run not found"}}}},"/v1/nodes/{id}/results":{"get":{"tags":["Nodes"],"summary":"Read a node job's output","description":"For a validation node, per-record/-field verdicts. For cell-producing nodes (transfer/extract/resolve/assemble), a pointer to the record-set read endpoints where the cells live.\n","operationId":"getNodeRunResults","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Node run output"},"404":{"description":"Node run not found"}}}},"/v1/schemas/{id}/rail":{"get":{"tags":["Schemas"],"summary":"Get the Spec's composed pipeline rail","operationId":"getSpecRail","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ rail: stage[] }"},"404":{"description":"Schema not found"}}},"put":{"tags":["Schemas"],"summary":"Set (or clear) the Spec rail","description":"Replaces the rail. An empty `rail` array clears it. Requires the `write` scope.","operationId":"setSpecRail","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rail"],"properties":{"rail":{"type":"array","maxItems":50,"items":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["source","registry","schema","resolve","valid","assembly","deliver","reconcile","sanitize","triage"]},"name":{"type":"string","maxLength":200},"sub":{"type":"string","maxLength":100},"json":{"type":"object","additionalProperties":true}}}}}}}}},"responses":{"200":{"description":"Rail saved"},"400":{"description":"Validation error"}}}},"/v1/schemas/{id}/validation-stages":{"get":{"tags":["Schemas"],"summary":"List validation stages (ordered)","operationId":"listValidationStages","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Stages in rail order"}}},"post":{"tags":["Schemas"],"summary":"Append a validation stage","operationId":"createValidationStage","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":256},"description":{"type":"string"},"severity":{"type":"string","enum":["info","warning","blocking"]},"config":{"type":"object","additionalProperties":true},"blockingConfig":{"type":"object","additionalProperties":true},"fieldScope":{"type":"string","enum":["all","subset"]},"fieldKeys":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Created stage"},"400":{"description":"Validation error"}}}},"/v1/schemas/{id}/validation-stages/reorder":{"post":{"tags":["Schemas"],"summary":"Reorder validation stages","operationId":"reorderValidationStages","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["stageIds"],"properties":{"stageIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"{ reordered: true }"}}}},"/v1/schemas/{id}/validation-stages/{stageId}":{"get":{"tags":["Schemas"],"summary":"Get a validation stage","operationId":"getValidationStage","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"stageId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Stage"},"404":{"description":"Stage not found"}}},"patch":{"tags":["Schemas"],"summary":"Update a validation stage","operationId":"updateValidationStage","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"stageId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"All fields optional. `blockingConfig: null` clears it.","properties":{"name":{"type":"string","maxLength":256},"description":{"type":"string"},"severity":{"type":"string","enum":["info","warning","blocking"]},"config":{"type":"object","additionalProperties":true},"blockingConfig":{"type":"object","nullable":true,"additionalProperties":true},"fieldScope":{"type":"string","enum":["all","subset"]},"fieldKeys":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated stage"}}},"delete":{"tags":["Schemas"],"summary":"Delete a validation stage","operationId":"deleteValidationStage","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"stageId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ deleted: true, id }"}}}},"/v1/schemas/{id}/validation-stages/{stageId}/replay-blocking":{"post":{"tags":["Schemas"],"summary":"Retroactively apply a now-blocking stage","operationId":"replayBlockingStage","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"stageId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Replay result (preview when dryRun)"}}}},"/v1/schemas/{id}/coherence-rules":{"get":{"tags":["Schemas"],"summary":"List coherence rules","operationId":"listCoherenceRules","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Coherence rules"}}},"post":{"tags":["Schemas"],"summary":"Create a coherence rule","operationId":"createCoherenceRule","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rule_type":{"type":"string","maxLength":50},"config":{"type":"object","additionalProperties":true},"description":{"type":"string"},"confidence_penalty":{"type":"number"},"status":{"type":"string","enum":["proposed","active","rejected"]}}}}}},"responses":{"201":{"description":"Created rule"}}}},"/v1/schemas/{id}/coherence-rules/propose":{"post":{"tags":["Schemas"],"summary":"Auto-propose coherence rules (LLM)","description":"Claude proposes candidate rules in `proposed` status. No request body.","operationId":"proposeCoherenceRules","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Proposed rules"}}}},"/v1/schemas/{id}/coherence-rules/{ruleId}":{"patch":{"tags":["Schemas"],"summary":"Update a coherence rule","operationId":"updateCoherenceRule","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"ruleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rule_type":{"type":"string","maxLength":50},"config":{"type":"object","additionalProperties":true},"description":{"type":"string"},"confidence_penalty":{"type":"number"},"status":{"type":"string","enum":["proposed","active","rejected"]}}}}}},"responses":{"200":{"description":"Updated rule"}}},"delete":{"tags":["Schemas"],"summary":"Delete a coherence rule","operationId":"deleteCoherenceRule","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"ruleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/schemas/{id}/assembly-configs":{"get":{"tags":["Schemas"],"summary":"List assembly configs","operationId":"listAssemblyConfigs","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Assembly configs"}}},"post":{"tags":["Schemas"],"summary":"Create an assembly config","operationId":"createAssemblyConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"grouping_field":{"type":"string"},"anchor_field":{"type":"string"},"anchor_values":{"type":"array","items":{"type":"string"}},"signed_field":{"type":"string"},"date_field":{"type":"string"},"amendable_fields":{"type":"array","items":{"type":"string"}},"override_rule_id":{"type":"string","maxLength":100,"default":"newer-signed-overrides"}}}}}},"responses":{"201":{"description":"Created config"}}}},"/v1/schemas/{id}/assembly-configs/{configId}":{"patch":{"tags":["Schemas"],"summary":"Update an assembly config","operationId":"updateAssemblyConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"configId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"grouping_field":{"type":"string"},"anchor_field":{"type":"string"},"anchor_values":{"type":"array","items":{"type":"string"}},"signed_field":{"type":"string"},"date_field":{"type":"string"},"amendable_fields":{"type":"array","items":{"type":"string"}},"override_rule_id":{"type":"string","maxLength":100}}}}}},"responses":{"200":{"description":"{ ok: true }"}}},"delete":{"tags":["Schemas"],"summary":"Delete an assembly config","operationId":"deleteAssemblyConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"configId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ ok: true }"}}}},"/v1/schemas/{id}/versions":{"get":{"tags":["Schemas"],"summary":"List published Spec versions (newest first)","operationId":"listSpecVersions","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Versions"}}}},"/v1/schemas/{id}/versions/diff":{"get":{"tags":["Schemas"],"summary":"Diff two Spec versions","operationId":"diffSpecVersions","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Version diff"}}}},"/v1/schemas/{id}/versions/rollback":{"post":{"tags":["Schemas"],"summary":"Roll back to a prior version (creates a new version)","operationId":"rollbackSpecVersion","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["version_number"],"properties":{"version_number":{"type":"integer","minimum":1}}}}}},"responses":{"200":{"description":"New version created from the target"}}}},"/v1/schemas/{id}/versions/{versionNumber}":{"get":{"tags":["Schemas"],"summary":"Get a specific Spec version","operationId":"getSpecVersion","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionNumber","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Version"},"404":{"description":"Version not found"}}}},"/v1/schemas/{id}/delivery":{"get":{"tags":["Schemas"],"summary":"Get the Spec delivery config","operationId":"getSpecDelivery","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"delivery_config (or empty object)"}}},"post":{"tags":["Schemas"],"summary":"Replace the Spec delivery config","operationId":"saveSpecDelivery","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Saved"}}}},"/v1/schemas/{id}/samples":{"get":{"tags":["Schemas"],"summary":"List pinned sample documents","operationId":"listSpecSamples","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pinned samples"}}},"post":{"tags":["Schemas"],"summary":"Pin a sample document (idempotent, max 5)","operationId":"pinSpecSample","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document_id"],"properties":{"document_id":{"type":"string","format":"uuid"},"label":{"type":"string","maxLength":200}}}}}},"responses":{"201":{"description":"Pinned"}}}},"/v1/schemas/{id}/samples/{documentId}":{"delete":{"tags":["Schemas"],"summary":"Unpin a sample document","operationId":"unpinSpecSample","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Unpinned"}}}},"/v1/schemas/{id}/document":{"get":{"tags":["Schemas"],"summary":"Get the composed customer-facing Spec document","operationId":"getSpecDocument","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Spec document"}}}},"/v1/schemas/{id}/graph":{"get":{"tags":["Schemas"],"summary":"Get the read-only Spec workflow graph (DAG)","operationId":"getSpecGraph","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workflow graph"}}}},"/v1/schemas/{id}/share":{"get":{"tags":["Schemas"],"summary":"Get the Spec share token (null if none)","operationId":"getSpecShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ token }"}}},"post":{"tags":["Schemas"],"summary":"Create or rotate the Spec share token","operationId":"createSpecShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ token }"}}},"delete":{"tags":["Schemas"],"summary":"Revoke the Spec share token","operationId":"revokeSpecShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ revoked: true }"}}}},"/v1/reconciliation/analyze/{referenceDataId}":{"get":{"tags":["Reconciliation"],"summary":"Auto-classify a reference dataset's columns","operationId":"analyzeReconciliation","security":[{"BearerAuth":[]}],"parameters":[{"name":"referenceDataId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Column classification"},"404":{"description":"Reference dataset not found"}}}},"/v1/reconciliation/config/{referenceDataId}":{"get":{"tags":["Reconciliation"],"summary":"Get the stored reconciliation config","operationId":"getReconciliationConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"referenceDataId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Stored config"}}},"put":{"tags":["Reconciliation"],"summary":"Save the reconciliation config (empty body clears it)","operationId":"saveReconciliationConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"referenceDataId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"version":{"type":"integer"},"haiku_validation":{"type":"boolean"},"anchor":{"type":"object","properties":{"key_columns":{"type":"array","items":{"type":"string"}},"narrowing_columns":{"type":"array","items":{"type":"string"}},"key_patterns":{"type":"object","additionalProperties":{"type":"string"}},"markdown_scanning":{"type":"string","enum":["fallback","always","disabled"]}}},"columns":{"type":"object","additionalProperties":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["validate","extract","anchor"]},"type":{"type":"string"},"tolerance":{"type":"number"},"threshold":{"type":"number"},"required":{"type":"boolean"},"doc_type_scope":{"type":"array","items":{"type":"string"}}}}}}}}}},"responses":{"200":{"description":"Saved"}}}},"/v1/reconciliation/auto-configure":{"post":{"tags":["Reconciliation"],"summary":"Auto-configure reconciliation from a sample target","operationId":"autoConfigureReconciliation","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reference_data_id","target_type","target_value"],"properties":{"reference_data_id":{"type":"string","format":"uuid"},"target_type":{"type":"string","enum":["documents","run"]},"target_value":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Proposed config"}}}},"/v1/reconciliation/run":{"post":{"tags":["Reconciliation"],"summary":"Run reconciliation against a reference dataset","operationId":"runReconciliation","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reference_data_id","target_type","target_value","config"],"properties":{"reference_data_id":{"type":"string","format":"uuid"},"target_type":{"type":"string","enum":["documents","run"]},"target_value":{"type":"object","description":"{ document_ids: uuid[] } or { run_id: uuid }","additionalProperties":true},"config":{"type":"object","required":["lookup_fields"],"properties":{"lookup_fields":{"type":"array","minItems":1,"items":{"type":"string"}},"reference_key_columns":{"type":"array","items":{"type":"string"}},"narrowing_columns":{"type":"array","items":{"type":"string"}},"key_patterns":{"type":"object","additionalProperties":{"type":"string"}},"checks":{"type":"array","items":{"type":"object","required":["name","type","extracted_fields","reference_fields"],"properties":{"name":{"type":"string","maxLength":200},"type":{"type":"string","enum":["exact","numeric_tolerance","containment","any_field","fuzzy_name","fuzzy_address","extract_only"]},"extracted_fields":{"type":"array","minItems":1,"items":{"type":"string"}},"reference_fields":{"type":"array","minItems":1,"items":{"type":"string"}},"tolerance":{"type":"number","minimum":0,"maximum":1},"required":{"type":"boolean"},"document_type":{"type":"string","maxLength":100},"fuzzy_threshold":{"type":"number","minimum":0,"maximum":1}}}}}}}}}}},"responses":{"200":{"description":"Reconciliation result"}}}},"/v1/field-reviews":{"get":{"tags":["Field Reviews"],"summary":"List held field-review items","operationId":"listFieldReviews","security":[{"BearerAuth":[]}],"parameters":[{"name":"pipeline_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"trigger","in":"query","schema":{"type":"string","enum":["gate","declarative"]}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"product_scoped","in":"query","description":"Keep only items whose resolution can still change the delivered data product — the count a run-level headline can honestly promise. A non-assembly run is unaffected (its record set is the product); on an assembly run an item survives only while a product cell still traces back to the flagged document. Default false, which returns the complete queue.","schema":{"type":"boolean","default":false}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Paginated review items"}}}},"/v1/field-reviews/summary":{"get":{"tags":["Field Reviews"],"summary":"Review-queue counts (total + per-trigger + per-pipeline)","description":"Every pending tally in the response is product-scoped: it counts only fields whose resolution can still change the delivered data product, so on an assembly run `total` is smaller than the full queue that `GET /v1/field-reviews` lists by default. Pass `product_scoped=true` on the list route to enumerate exactly the items these counts describe. `reviewedByPipeline` is not a pending tally and is not scoped.","operationId":"getFieldReviewSummary","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Queue summary"}}}},"/v1/field-reviews/decisions":{"get":{"tags":["Field Reviews"],"summary":"List field-review decisions (the decision log)","operationId":"listFieldReviewDecisions","security":[{"BearerAuth":[]}],"parameters":[{"name":"pipeline_id","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Decision log"}}}},"/v1/field-reviews/decisions/export":{"get":{"tags":["Field Reviews"],"summary":"Export the decision log as CSV","operationId":"exportFieldReviewDecisions","security":[{"BearerAuth":[]}],"parameters":[{"name":"pipeline_id","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{"schema":{"type":"string"}}}}}}},"/v1/field-reviews/{docId}/{fieldKey}":{"get":{"tags":["Field Reviews"],"summary":"Get a field-review item's reviewer detail","operationId":"getFieldReviewDetail","security":[{"BearerAuth":[]}],"parameters":[{"name":"docId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"fieldKey","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reviewer detail"},"404":{"description":"Item not found"}}}},"/v1/field-reviews/{docId}/{fieldKey}/resolve":{"post":{"tags":["Field Reviews"],"summary":"Resolve a held field-review item","operationId":"resolveFieldReview","security":[{"BearerAuth":[]}],"parameters":[{"name":"docId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"fieldKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["approve","correct","override"]},"corrected_value":{"type":"string","maxLength":10000},"reason":{"type":"string","maxLength":2000}}}}}},"responses":{"200":{"description":"Resolved"}}}},"/v1/field-reviews/bulk-resolve":{"post":{"tags":["Field Reviews"],"summary":"Resolve many field-review items at once","operationId":"bulkResolveFieldReviews","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items","action"],"properties":{"action":{"type":"string","enum":["approve","correct","override"]},"corrected_value":{"type":"string","maxLength":10000},"reason":{"type":"string","maxLength":2000},"items":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["pipeline_document_id","field_key"],"properties":{"pipeline_document_id":{"type":"string","format":"uuid"},"field_key":{"type":"string","maxLength":500}}}}}}}}},"responses":{"200":{"description":"{ resolved, failed, results[] }"}}}},"/v1/registry/query":{"post":{"tags":["Fields"],"summary":"Query the field registry by field values","deprecated":true,"description":"Deprecated: moved under `/v1/fields/registry/*`; use `POST /v1/fields/registry/query`. This path remains supported and serves the same handler. Returns documents whose captured field values match the `where` map (values matched via ILIKE). A read operation that takes a POST body. Requires the `read` scope. An unknown `where` field returns a 200 body `{ error: 'unknown_field' }`.\n","operationId":"queryRegistry","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["where"],"properties":{"where":{"type":"object","minProperties":1,"additionalProperties":true},"select":{"type":"array","items":{"type":"string"}},"limit":{"type":"integer","minimum":1,"default":100,"maximum":500}}}}}},"responses":{"200":{"description":"{ data: row[], total }"}}}},"/v1/fields/registry/query":{"post":{"tags":["Fields"],"summary":"Query the field registry by field values","description":"The canonical home of the registry query going forward (alias of the deprecated `POST /v1/registry/query`; both serve the same handler). Returns documents whose captured field values match the `where` map (values matched via ILIKE). A read operation that takes a POST body. Requires the `read` scope. An unknown `where` field returns a 200 body `{ error: 'unknown_field' }`.\n","operationId":"queryFieldsRegistry","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["where"],"properties":{"where":{"type":"object","minProperties":1,"additionalProperties":true},"select":{"type":"array","items":{"type":"string"}},"limit":{"type":"integer","minimum":1,"default":100,"maximum":500}}}}}},"responses":{"200":{"description":"{ data: row[], total }"}}}},"/v1/matching/packages/configs":{"get":{"tags":["Matching Packages"],"summary":"List matching-package configs","operationId":"listMatchingPackageConfigs","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated configs"}}},"post":{"tags":["Matching Packages"],"summary":"Create a matching-package config","operationId":"createMatchingPackageConfig","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","document_type_configs","pass_criteria"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"document_type_configs":{"type":"array","minItems":1,"items":{"type":"object","required":["document_type","matching_config_id","presence"],"properties":{"document_type":{"type":"string","minLength":1,"maxLength":200},"matching_config_id":{"type":"string","format":"uuid"},"presence":{"type":"string","enum":["required","expected","optional"]}}}},"pass_criteria":{"type":"object","required":["all_required_matched","min_confidence","allow_review_on_expected"],"properties":{"all_required_matched":{"type":"boolean"},"min_confidence":{"type":"number","minimum":0,"maximum":1},"allow_review_on_expected":{"type":"boolean"}}}}}}}},"responses":{"201":{"description":"Created config"}}}},"/v1/matching/packages/configs/{id}":{"get":{"tags":["Matching Packages"],"summary":"Get a matching-package config","operationId":"getMatchingPackageConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Config"},"404":{"description":"Config not found"}}},"delete":{"tags":["Matching Packages"],"summary":"Delete a matching-package config (cascades to runs)","operationId":"deleteMatchingPackageConfig","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/matching/packages/runs":{"get":{"tags":["Matching Packages"],"summary":"List matching-package runs","operationId":"listMatchingPackageRuns","security":[{"BearerAuth":[]}],"parameters":[{"name":"package_config_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated runs"}}},"post":{"tags":["Matching Packages"],"summary":"Trigger a matching-package run (synchronous)","operationId":"triggerMatchingPackageRun","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["package_config_id","input_documents"],"properties":{"package_config_id":{"type":"string","format":"uuid"},"input_documents":{"type":"object","description":"Keyed by document_type; each value is an array of input rows.","additionalProperties":{"type":"array","items":{"type":"object","required":["document_id","extraction_row_id","values"],"properties":{"document_id":{"type":"string","format":"uuid"},"extraction_row_id":{"type":"string"},"values":{"type":"object","additionalProperties":true}}}}}}}}}},"responses":{"201":{"description":"Terminal run result"}}}},"/v1/field-reviews/triage":{"get":{"tags":["Field Reviews"],"summary":"Review-queue breakdown for the header","description":"Classification-backed breakdown — `byReason` plus `byField`, `byDocument`, `byAssignee`, `byTag`, each group carrying a per-group reason `mix`. Honors the list's scope filters and `q`, but not `reason`/`tags`.\n","operationId":"getFieldReviewTriage","security":[{"BearerAuth":[]}],"parameters":[{"name":"pipeline_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"schema_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"document_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"stage_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"trigger","in":"query","schema":{"type":"string","enum":["gate","declarative"]}},{"name":"assignee","in":"query","schema":{"type":"string","enum":["me","unassigned"]}},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"older_than_hours","in":"query","schema":{"type":"integer"}},{"name":"include_held","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"{ byReason, byField, byDocument, byAssignee, byTag }"}}}},"/v1/field-reviews/value-clusters":{"get":{"tags":["Field Reviews"],"summary":"Distinct held values among the filtered set","description":"Distinct current values (typically for one `field_key`) with counts and member items — drives identical-value cluster bulk-approve.\n","operationId":"getFieldReviewValueClusters","security":[{"BearerAuth":[]}],"parameters":[{"name":"field_key","in":"query","schema":{"type":"string"}},{"name":"pipeline_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"schema_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"document_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"stage_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"trigger","in":"query","schema":{"type":"string","enum":["gate","declarative"]}},{"name":"reason","in":"query","schema":{"type":"string"}},{"name":"assignee","in":"query","schema":{"type":"string","enum":["me","unassigned"]}},{"name":"older_than_hours","in":"query","schema":{"type":"integer"}},{"name":"include_held","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Value clusters with member items"}}}},"/v1/registry/health":{"get":{"tags":["Fields"],"summary":"Field-registry health snapshot (read-only)","deprecated":true,"description":"Deprecated: moved under `/v1/fields/registry/*`; use `GET /v1/fields/registry/health`. This path remains supported and serves the same handler. Tier + admission counts, singleton/weak-name rates, occurrence and resolution stats, transfer hit rate, and coherence/atomicity metrics for the tenant's field registry. The same view the in-app registry dashboard reads; no lifecycle or cleanup actions are exposed.\n","operationId":"getRegistryHealth","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Registry health snapshot"}}}},"/v1/fields/registry/health":{"get":{"tags":["Fields"],"summary":"Field-registry health snapshot (read-only)","description":"The canonical home of the registry health snapshot going forward (alias of the deprecated `GET /v1/registry/health`; both serve the same handler). Tier + admission counts, singleton/weak-name rates, occurrence and resolution stats, transfer hit rate, and coherence/atomicity metrics for the tenant's field registry. The same view the in-app registry dashboard reads; no lifecycle or cleanup actions are exposed.\n","operationId":"getFieldsRegistryHealth","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Registry health snapshot"}}}},"/v1/customer-ontologies":{"get":{"tags":["Customer Ontologies"],"summary":"List ontologies","operationId":"listCustomerOntologies","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Ontologies with latest version status"}}},"post":{"tags":["Customer Ontologies"],"summary":"Create an ontology + empty draft v1","operationId":"createCustomerOntology","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"{ id, version }"}}}},"/v1/customer-ontologies/import":{"post":{"tags":["Customer Ontologies"],"summary":"Top-down import (create/replace draft, optionally publish)","description":"Publishing projects authored fields/doctypes into the field registry and classification — it changes how capture and classification behave for the tenant. Requires the `write` scope.\n","operationId":"importCustomerOntology","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OntologyImport"}}}},"responses":{"200":{"description":"Ontology header"}}}},"/v1/customer-ontologies/overlay/doctypes":{"get":{"tags":["Customer Ontologies"],"summary":"Published custom doctypes (classifier preview)","operationId":"getCustomerOntologyOverlayDoctypes","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Published custom doctypes"}}}},"/v1/customer-ontologies/talonic-types":{"get":{"tags":["Customer Ontologies"],"summary":"The full Talonic ontology type list (global catalog)","operationId":"listTalonicOntologyTypes","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Talonic types (id + name + breadcrumb)"}}}},"/v1/customer-ontologies/suggest-mappings":{"post":{"tags":["Customer Ontologies"],"summary":"Embedding-match posted doctypes onto Talonic types","description":"Stateless — runs over the posted doctypes, persists nothing. Read scope.","operationId":"suggestCustomerOntologyMappings","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["doctypes"],"properties":{"doctypes":{"type":"array","items":{"$ref":"#/components/schemas/OntologyDoctype"}}}}}}},"responses":{"200":{"description":"Per doctype: { key, auto, ambiguous, candidates }"}}}},"/v1/customer-ontologies/{id}":{"get":{"tags":["Customer Ontologies"],"summary":"Ontology header + latest version content","operationId":"getCustomerOntology","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ontology"},"404":{"description":"Not found"}}},"patch":{"tags":["Customer Ontologies"],"summary":"Update the draft (auto-forks if published)","operationId":"updateCustomerOntology","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OntologyUpdate"}}}},"responses":{"200":{"description":"Updated version"}}},"delete":{"tags":["Customer Ontologies"],"summary":"Delete the ontology (versions cascade) + reverse projection","operationId":"deleteCustomerOntology","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ deleted: true }"}}}},"/v1/customer-ontologies/{id}/versions":{"get":{"tags":["Customer Ontologies"],"summary":"Version history (newest first)","operationId":"listCustomerOntologyVersions","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Versions"}}}},"/v1/customer-ontologies/{id}/publish":{"post":{"tags":["Customer Ontologies"],"summary":"Publish the latest version + project into registry/classification","operationId":"publishCustomerOntology","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Published ontology header"}}}},"/v1/customer-ontologies/{id}/unpublish":{"post":{"tags":["Customer Ontologies"],"summary":"Retract the published version → draft + reverse projection","operationId":"unpublishCustomerOntology","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ontology header"}}}},"/v1/pipelines":{"get":{"tags":["Pipelines"],"summary":"List pipeline runs","operationId":"listPipelines","security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"schema_id","in":"query","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Order"}],"responses":{"200":{"description":"Paginated pipeline runs (previews excluded)","newest first.":null}}},"post":{"tags":["Pipelines"],"summary":"Run a Spec as a pipeline","description":"Compiles the named Spec's saved rail into a pipeline and starts processing the documents in one call. The Spec must have a composed rail; otherwise a 400 is returned (use POST /v1/jobs for an ad-hoc run with no rail). Requires write scope.\n","operationId":"createPipeline","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["schema_id","document_ids"],"properties":{"schema_id":{"type":"string","format":"uuid","description":"The Spec to run (a user_schema with a composed rail)."},"document_ids":{"type":"array","minItems":1,"maxItems":3000,"items":{"type":"string","format":"uuid"}},"name":{"type":"string","minLength":1,"maxLength":200},"pipeline_mode":{"type":"string","enum":["new","append"],"description":"Explicit override of the Spec's configured pipeline mode. `append` adds the documents to the newest eligible existing pipeline on the Spec (config-matching, under the size cap) instead of creating one; the response's `appended` reports which happened. Omitted → the Spec's own setting (default `new`).\n"}}}}}},"responses":{"201":{"description":"Created pipeline run with links to progress + data-product. `appended: true` marks an append-mode reuse of an existing pipeline (its id is returned). `run_id` is the submission-group identifier stamped on this call's documents — usable as the `run_id` filter on the results/documents reads."},"400":{"description":"The Spec has no composed rail, or the body failed validation."},"413":{"description":"The request exceeds the tested per-run document ceiling."},"429":{"description":"The pipeline queue lacks tested headroom; retry after the advised delay."},"503":{"description":"Pipeline queue headroom or durable fan-out could not be verified."}}}},"/v1/pipelines/{id}":{"get":{"tags":["Pipelines"],"summary":"Get a pipeline run","operationId":"getPipeline","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Run detail: id, name, status, schema, phase_count, links."},"404":{"description":"Pipeline not found"}}},"delete":{"tags":["Pipelines"],"summary":"Delete a pipeline run","description":"Deletes the run and its owned data (value cells, record sets, cascaded documents). Requires write scope.","operationId":"deletePipeline","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/pipelines/{id}/progress":{"get":{"tags":["Pipelines"],"summary":"Get pipeline progress","description":"Phase-by-phase progress for polling. The run is terminal once completedDocuments + errorDocuments reaches totalDocuments.","operationId":"getPipelineProgress","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Phase progress + per-document errors."}}}},"/v1/pipelines/{id}/rerun":{"post":{"tags":["Pipelines"],"summary":"Re-run a finished pipeline from a phase","description":"Re-runs from the given phase onward, reusing every upstream cell. Requires write scope.","operationId":"rerunPipeline","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from_phase"],"properties":{"from_phase":{"type":"string","enum":["transfer","extraction","resolution","validation"]}}}}}},"responses":{"200":{"description":"Rerun result"}}}},"/v1/pipelines/{id}/data-product":{"post":{"tags":["Pipelines"],"summary":"Produce a data product from a pipeline","description":"Creates a data product backed by the pipeline's record set and rebuilds its review queue. Requires write scope.","operationId":"createPipelineDataProduct","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200}}}}}},"responses":{"201":{"description":"Created data product"}}}},"/v1/pipelines/{id}/results":{"get":{"tags":["Pipelines"],"summary":"Get a pipeline's structured results (poll-able)","description":"The pipeline run's structured rows, poll-able as JSON — the same governed read (review holdback, demoted-field projection, `__` diagnostics filtering, assembly awareness) that previously existed only as the `run.completed` webhook or a data-product CSV export. The default record shape mirrors the `pipeline.capture` webhook envelope: `document_id`, `filename`, `run_id`, `pipeline_id`, `record_id`, `status`, `completed_at`, optional `metadata`/`batch_id`, and clean `fields`. Held (`pending_approval`) values never leave this surface — `fields` serializes `null` for them.\n\n`view=composed` (the default when the run has an assembly product set) returns one row per assembled group, the same rows the data product and CSV exports serve; `view=documents` returns one row per pipeline document from the main record set. A non-assembly run only has the documents view — `view=composed` degrades to it rather than erroring. An **anchor-less composed row** (the product record's anchor could not be resolved — a known `per_group_jobs` identity-stamp gap) serializes `document_id`/`filename`/`run_id: null`, `status: \"complete\"`, and `completed_at: null`; such rows are excluded by any `document_id`, `status`, `since`, or `until` filter and appear only in unbounded reads.\n\n`since`/`until` filter on `completed_at`, which tracks DOCUMENT PROCESSING completion, not value change: a later review promotion or assembly recompose never advances it, and a phase rerun NULLS the completion stamps for every affected document until it re-processes. Poll unbounded (or by `document_id`) to pick up review outcomes; `pending_review_count` on the page is the signal that held values are outstanding.\n\nA field backed by a structured subschema is projected to its declared subfield types on this poll — in both the `fields` map and the `?include=cells` `cells[].value` — matching the `run.completed` webhook; a `number`/`boolean` subfield parse-miss serializes `null` and an `enum`/`date` miss passes through raw (see the `ResultsCell`/`ResultsRecord` schemas and the Webhooks event catalog for the full per-type contract). The `include=audit` trail is the raw history view and is NOT type-projected.\n\n`include=cells,provenance,audit` (comma-separated) add shape beyond `fields`. `cells` adds per-field `{ value, status, confidence, source, document_id, filename }` — `source` is an opaque-but-stable vocabulary; new values may appear over time. `provenance` adds a stable projection of the cell's audit trail (`kind` one of `span`, `assembly_override`, `auto_adjudication`, `human`, `derived`, `legacy`, with an open `derived_reason` enum); a held cell's projection is kind-only — no displaced/previous values. `audit` adds the full cell-version trail, bounded to `structure_pipeline.results_api.audit_max_records` (default 20) records per page — a broader page 400s with `audit_include_too_broad`. For any field whose LATEST version is held, every version in its audit trail serializes `value: null` (the hold mechanism copies the value forward, so the prior version is an equal leak).\n\nPagination is house cursor pagination (`pagination.next_cursor`, keyed on `record_id`), never an invented `page` param. Per-record `status` folds ~10 internal states to four public values — `complete`, `partial`, and `error` pass through, everything else (queue/phase states, `awaiting_ocr`, …) folds to `processing`. This deliberately KEEPS `partial`, unlike `GET /v1/run/{id}`'s 3-state `documents[]` fold, because a partial row's held fields are the reason to keep polling. Poll this envelope's `status` until `completed` for a single-request pipeline; an append pipeline never settles at the pipeline level, so append consumers should loop on per-record `status`/`completed_at` or poll `GET /v1/run/{id}/results` instead, whose run-scoped status does settle. Preview pipelines are served. Requires read scope.\n","operationId":"getPipelineResults","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"document_id","in":"query","schema":{"type":"string"},"description":"Comma-separated document UUIDs (1-100). Composed rows match on the anchor document."},{"name":"run_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Scope to one /v1/run request's own documents (implies view=documents). 404 when the run does not belong to this pipeline/organization; a 200 empty page with scope_note for a legacy run that predates per-request document tracking."},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only records whose completed_at is at or after this ISO timestamp. Records with a null completed_at (still processing, or anchor-less composed rows) are excluded once either bound is set."},{"name":"until","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only records whose completed_at is at or before this ISO timestamp."},{"name":"status","in":"query","schema":{"type":"string"},"description":"Comma-separated subset of complete, partial, error, processing."},{"name":"view","in":"query","schema":{"type":"string","enum":["composed","documents"]},"description":"Defaults to composed when the run has an assembly product set, else documents. A non-assembly run ignores view=composed."},{"name":"include","in":"query","schema":{"type":"string"},"description":"Comma-separated subset of cells, provenance, audit."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Maximum records per page (structure_pipeline.results_api — default 25, max 100)."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from a previous response's pagination.next_cursor, keyed on record_id."}],"responses":{"200":{"description":"The pipeline's results page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineResultsResponse"}}}},"400":{"description":"Invalid query parameters. code is one of invalid_view, invalid_document_ids, invalid_run_id, invalid_time_range, invalid_status, invalid_include, audit_include_too_broad.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsBadRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Pipeline not found, or run_id does not belong to this pipeline/organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/run":{"post":{"tags":["Run"],"summary":"Ingest documents and run a Spec's pipeline in one call","description":"Accepts one or more files, one or more `file_urls`, or a mix of both — at least one input is required. Ingests every input (metering each ingest leg), waits for OCR to finish, then compiles the named Spec's saved rail into a pipeline and starts it — the same compile step `POST /v1/pipelines` uses, minus the separate \"upload documents first\" step. Always returns 202; poll `GET /v1/run/{id}` or listen for the `run.completed` / `run.failed` webhook (`POST /v1/webhooks`). Requires write scope. Unlike `POST /v1/process`, this endpoint does not dedup — every call starts a fresh run. Content-based document dedup still applies per input within the call — see the `documents` response field.\n","operationId":"createRun","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["spec_id"],"properties":{"spec_id":{"type":"string","format":"uuid","description":"The Spec whose saved rail runs. Accepts either a Spec (user_schema) id or a V2 Spec id (the id shown in the /specs editor) — a V2 id resolves to its linked schema's last published/materialized rail."},"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"Zero or more document files (max 20 per call, 500 MB each). At least one of files/file_urls is required."},"file_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Zero or more remote document URLs (SSRF-guarded downstream)."},"name":{"type":"string","maxLength":200,"description":"Optional display name for the run."},"batch_id":{"type":"string","maxLength":200,"description":"Optional caller grouping key stamped on every document ingested by this call (documents.client_batch_id) and echoed by GET /v1/run/{id}. Opaque to the platform — an external job/batch id for grouping.\n"},"metadata":{"type":"string","description":"Optional JSON string of a FLAT object `{ [key]: string | number | boolean | null }` (nested objects/arrays are rejected 400; limits: ≤50 keys, key ≤128 chars, string value ≤1024 chars). The validated object is persisted on the run request (echoed by GET /v1/run/{id}) AND stamped on every ingested document as documents.client_metadata.\n"},"file_metadata":{"type":"string","description":"Optional JSON string of a map `{ [inputKey: string]: ClientMetadata }` for tagging individual files in a multi-file call — each value obeys the same constraints as `metadata` (≤50 keys, key ≤128 chars, string value ≤1024 chars). `inputKey` is the input's identity: for `files`, the uploaded filename exactly as echoed back in `documents[]` (filenames are NFC-normalized before matching, so an umlaut/NFD name still keys correctly); for `file_urls`, the exact URL string (no trim, no normalization). A key matching several same-named inputs applies to ALL of them; a key matching NO input is a 400 `invalid_metadata` naming the offending key, so a typo'd filename fails loudly instead of silently tagging nothing. Per input, the file's bag is merged OVER the call-level `metadata` — per-file wins per key, and `null` is a value (it overrides), never a deletion, so a per-file entry cannot unset a call-level key. The MERGED result must still satisfy the caps above (a 30-key call bag plus a disjoint 30-key file bag is rejected, not silently truncated) — 400 `invalid_metadata` otherwise. The map itself is capped at the call's max input count (20) entries and 64 KB of decoded JSON; the size cap binds BEFORE per-entry validation, so 20 individually-legal maximal bags can still exceed it. Container inputs (ZIP/email) key by the archive's filename only — a key can target the archive, never its extracted members, which inherit the archive's merged bag. The resolved per-input bag is echoed back in `documents[].metadata` on this response and on GET /v1/run/{id}.\n"},"pipeline_mode":{"type":"string","enum":["new","append"],"description":"Explicit override of the Spec's configured pipeline mode. `new` (the default when neither this nor the Spec sets a mode) creates a fresh pipeline per call. `append` adds this call's documents to the newest eligible existing pipeline on the Spec — so bulk uploads accumulate into one growing table instead of one pipeline per call. A pipeline is eligible when its config still matches the Spec (schema fields, policies, gates, assembly/review config) and it is under the append size cap; otherwise a fresh pipeline is created and becomes the new append target. Under append, completion is PER REQUEST: the run.completed webhook and GET /v1/run/{id} report this request's own documents (payloads carry run_id and are scoped to them), and the shared pipeline fires no pipeline-level run.* webhook.\n"},"ingestion_target":{"type":"string","enum":["ingest","extract"],"default":"ingest","description":"How far the platform processes the run's documents beyond the Spec pipeline. `ingest` (default): after OCR, Stage-2 field capture runs asynchronously so the corpus becomes queryable by the agent surfaces (POST /v1/ask) and the pipeline's Transfer phase — the pipeline still starts the moment OCR markdown is ready, capture never delays it. `extract`: markdown-only; the documents are not askable.\n"}}}}}},"responses":{"202":{"description":"Ingest + run accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"run_id":{"type":"string","format":"uuid"},"spec_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processing"]},"input_count":{"type":"integer","description":"Total files + file_urls accepted."},"poll_url":{"type":"string","example":"/v1/run/3d44a4dc-e3e4-4bca-b079-a9c85bf75026"},"documents":{"type":"array","description":"One entry per input, in input order — multipart files (in request order) first, then file_urls; documents.length === input_count. Identical files submitted in the same call resolve to the same document_id, so GET /v1/run/{id}'s progress.total_documents can be lower than input_count.\n","items":{"type":"object","required":["document_id","filename","size_bytes","source","deduplicated"],"properties":{"document_id":{"type":"string","format":"uuid","description":"The CANONICAL document — the same id result rows and the run.completed webhook's records[] carry. A byte-identical re-upload resolves to an existing document whose filename/tags may pre-date this run. This deliberately diverges from the sources/ingest dedup shape, where document_id is the link row and existing_document_id is the canonical.\n"},"filename":{"type":"string","nullable":true,"description":"For file inputs, the caller's uploaded filename (even when deduplicated). For file_url inputs, the filename derived at download — for a deduplicated URL input this is the canonical document's stored filename, which may differ from the URL.\n"},"size_bytes":{"type":"integer","nullable":true},"source":{"type":"string","enum":["file","file_url"]},"deduplicated":{"type":"boolean","description":"True when this input resolved to a pre-existing document instead of creating a new one."},"linked_document_id":{"type":"string","format":"uuid","description":"Present only when deduplicated is true — the thin per-upload link row created for this input."},"metadata":{"type":"object","additionalProperties":true,"description":"This input's EFFECTIVE metadata for THIS request — the call-level `metadata` merged with its `file_metadata` entry (per-file wins), captured at submit. Present only when set. Under byte-identical dedup this can legitimately diverge from GET /v1/documents/{id}'s `metadata`, which keeps the CANONICAL document's tags from its FIRST submission — this echo is the authoritative per-request tag source; read it (not the document) to see what THIS call tagged.\n"}},"example":{"document_id":"3d44a4dc-e3e4-4bca-b079-a9c85bf75026","filename":"invoice.pdf","size_bytes":148213,"source":"file","deduplicated":false}}}}}}}},"400":{"description":"Missing spec_id, no input provided (both files and file_urls empty), or metadata is not a valid flat JSON object."},"402":{"description":"Insufficient credits for an ingest leg."},"413":{"description":"A file exceeds the tier's per-file size cap."},"429":{"description":"API rate limit or pipeline-queue admission limit reached; retry after the advised delay."},"503":{"description":"Pipeline queue headroom could not be verified before ingest."}}}},"/v1/run/{id}":{"get":{"tags":["Run"],"summary":"Poll a /v1/run request","description":"Row status, folded with the compiled pipeline's live progress once one exists (`pipeline_id` set). `status` is `processing` (in flight), `completed`, or `failed` — the same vocabulary `POST /v1/run` returns. A non-null `pipeline_id` plus the `progress` object indicate the pipeline has started. `documents` (when present) echoes each input's resolved document plus a per-entry live `status` — omitted entirely for runs submitted before this field shipped. Requires read scope.\n","operationId":"pollRunRequest","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Run request status.","content":{"application/json":{"schema":{"type":"object","properties":{"run_id":{"type":"string","format":"uuid"},"spec_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processing","completed","failed"]},"pipeline_id":{"type":"string","format":"uuid","nullable":true},"pipeline_mode":{"type":"string","enum":["new","append"],"description":"The EFFECTIVE mode this request resolved to (present only when recorded — omitted for legacy requests). Under `append` the pipeline is shared across requests, and `status`/`progress` are scoped to THIS request's own documents (the same all-terminal fold the per-request webhook fires on), not the whole pipeline.\n"},"input_count":{"type":"integer"},"error_message":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true,"additionalProperties":true,"description":"The validated flat metadata object supplied on POST /v1/run, echoed back here."},"batch_id":{"type":"string","nullable":true,"description":"The caller grouping key supplied on POST /v1/run, echoed back here."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"progress":{"type":"object","nullable":true,"description":"Present once the pipeline has started.","properties":{"total_documents":{"type":"integer"},"completed_documents":{"type":"integer"},"error_documents":{"type":"integer"}}},"documents":{"type":"array","nullable":true,"description":"Same items as POST /v1/run's response, each with an added per-entry status folded from the compiled pipeline's live per-document state (falls back to the run's own status when no pipeline is running yet, or the per-document fold could not be read). OPTIONAL — omitted entirely for runs submitted before this field shipped.\n","items":{"type":"object","required":["document_id","filename","size_bytes","source","deduplicated","status"],"properties":{"document_id":{"type":"string","format":"uuid"},"filename":{"type":"string","nullable":true},"size_bytes":{"type":"integer","nullable":true},"source":{"type":"string","enum":["file","file_url"]},"deduplicated":{"type":"boolean"},"linked_document_id":{"type":"string","format":"uuid","description":"Present only when deduplicated is true."},"metadata":{"type":"object","additionalProperties":true,"description":"This input's EFFECTIVE per-request metadata, echoed from submit time (see POST /v1/run's documents[].metadata). Present only when set.\n"},"status":{"type":"string","enum":["processing","completed","failed"]}}}}}}}}},"404":{"description":"Run request not found."}}}},"/v1/run/{id}/results":{"get":{"tags":["Run"],"summary":"Get this run's structured results (poll-able, per-document)","description":"The same governed results read as `GET /v1/pipelines/{id}/results` (review holdback, demoted-field projection, assembly awareness), scoped ALWAYS to this `/v1/run` request's own `documents[]` echo and ALWAYS the per-document view — \"what did MY submitted documents produce,\" uniform across new/append pipeline modes. This is a deliberate DIVERGENCE from the per-run `run.completed` webhook, which for an unscoped non-append assembly run delivers COMPOSED rows: composed output for an assembly run is `GET /v1/pipelines/{id}/results?view=composed`, surfaced here at `links.composed_results` when a pipeline exists.\n\nOnly `document_id` and `include` filter the rows; `run_id`, `view`, `since`, `until`, and `status` are pipeline-route-only and 400 with `unsupported_filter` here, since the run IS the scope and its window is already bounded. `include=cells,provenance,audit` behave identically to the pipeline route — including the structured-subfield type projection on `fields`/`cells` and the raw, non-projected `audit` trail — see `GET /v1/pipelines/{id}/results` for the full shape and held-value redaction rules.\n\nTwo zero-states return `200` with an empty page and a `scope_note`, never `404`: no compiled pipeline exists yet for this run (still ingesting, or it failed before pipeline creation), or the run predates per-request document tracking (an echo-less legacy row, whose membership is unknowable). The envelope's `status` folds the same three-state vocabulary as `GET /v1/run/{id}` (`processing`/`completed`/`failed`) and DOES settle even for an append pipeline that never settles at the pipeline level — poll this route for append consumers instead of the pipeline route. Requires read scope.\n","operationId":"getRunResults","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"document_id","in":"query","schema":{"type":"string"},"description":"Comma-separated document UUIDs (1-100), intersected with the run's own documents echo."},{"name":"include","in":"query","schema":{"type":"string"},"description":"Comma-separated subset of cells, provenance, audit."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Maximum records per page (default 25, max 100)."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from a previous response's pagination.next_cursor, keyed on record_id."}],"responses":{"200":{"description":"This run's results page (always the documents view).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunResultsResponse"}}}},"400":{"description":"Invalid query parameters, or a pipeline-route-only filter (run_id, view, since, until, status) was supplied. code is one of invalid_document_ids, invalid_include, unsupported_filter, audit_include_too_broad.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsBadRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Run request not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook configs","operationId":"listWebhooks","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ data: webhook[] }"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","operationId":"createWebhook","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"secret":{"type":"string","description":"HMAC signing secret (defaults to empty)."},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to (default: extraction.complete, extraction.failed). Includes run.completed / run.failed — fired on POST /v1/run pipeline completion. run.completed's payload carries records (array of { document_id, filename, data }, always present; document_id and filename are nullable — null when a row's document identity cannot be resolved) alongside the legacy structured_data; run.failed's error object may carry document_ids (best effort, present on some failure paths only). See GET /v1/webhooks/events for the full, current catalog."},"source_connection_id":{"type":"string","format":"uuid","nullable":true},"is_active":{"type":"boolean","default":true}}}}}},"responses":{"201":{"description":"Created webhook"},"400":{"description":"Missing url"}}}},"/v1/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook","operationId":"getWebhook","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Webhook config"},"404":{"description":"Not found"}}},"patch":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"updateWebhook","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"secret":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated webhook"}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"deleteWebhook","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ deleted: true, id }"}}}},"/v1/events":{"get":{"tags":["Events"],"summary":"List tenant events","description":"Newest-first feed of platform events (document.extracted, run.*.completed/failed, result.flagged/approved/rejected, delivery.item.*, case.resolved). Alias of /v1/delivery/events at the API root.\n","operationId":"listEvents","security":[{"BearerAuth":[]}],"parameters":[{"name":"event_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by event type, e.g. document.extracted"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"{ data: [{ id, event_type, payload, created_at }], total, limit, offset }"}}}},"/v1/documents/{id}/claims":{"get":{"tags":["Provenance"],"summary":"List a document's provenance claims","description":"Deterministic atomic (subject, predicate, object) claims synthesized from the document's captured fields + provenance spans (no LLM). Each claim carries its evidence quote, grounded flag, and confidence. Field-level span detail lives on GET /v1/field-reviews/{docId}/{fieldKey}.\n","operationId":"listDocumentClaims","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"grounded","in":"query","required":false,"schema":{"type":"boolean"},"description":"true = only span-backed claims"}],"responses":{"200":{"description":"{ data: [{ subject, predicate, object, qualifier, evidence, segment_id, grounded, confidence, origin }], total }"},"404":{"description":"Document not found or not owned by the caller."}}}},"/v1/webhooks/events":{"get":{"tags":["Webhooks"],"summary":"List supported webhook event types","description":"Live catalog served from code (not a static enum) — includes run.completed (\"A /v1/run pipeline finished; structured output is available, review-held fields null\" — payload adds `records`, an array of `{ document_id, filename, data }` always present even for a single document (`document_id` and `filename` are nullable — null when a row's document identity cannot be resolved), alongside the legacy `structured_data`, which is still emitted but considered legacy in favor of `records`) and run.failed (\"A /v1/run pipeline failed — all documents errored during ingest or extraction\" — its `error` object may include `document_ids`, a best-effort array of the input document ids, present only on some failure paths) alongside the document/extraction/job/delivery/process event families.\n","operationId":"listWebhookEvents","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ data: [{ event, description }] }"}}}},"/v1/webhooks/delivery":{"get":{"tags":["Webhooks"],"summary":"Webhook delivery payload format","operationId":"getWebhookDeliveryFormat","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Content type","method":null,"headers":null,"body":null,"example.":null}}}},"/v1/webhooks/signatures":{"get":{"tags":["Webhooks"],"summary":"Webhook signature verification reference","operationId":"getWebhookSignatures","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"HMAC-SHA256 scheme","header":null,"verification steps.":null}}}},"/v1/webhooks/retries":{"get":{"tags":["Webhooks"],"summary":"Webhook retry policy","operationId":"getWebhookRetries","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Max attempts","backoff schedule":null,"timeout.":null}}}},"/v1/data-products/{id}/share":{"get":{"tags":["Data Products"],"summary":"Get the data product's share link","description":"Returns the current public share link, or `share: null` when never shared or revoked. Does not auto-create one.","operationId":"getDataProductShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ share: { token, url, has_password, created_at } | null }"}}},"post":{"tags":["Data Products"],"summary":"Create or rotate the share link","description":"Creates the share link, or rotates it (fresh token, prior link invalidated, password kept). Requires write scope.","operationId":"createDataProductShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ share: { token, url, has_password, created_at } }"}}},"delete":{"tags":["Data Products"],"summary":"Revoke the share link","description":"Revokes the public link (idempotent). Requires write scope.","operationId":"revokeDataProductShare","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ revoked: boolean, id }"}}}},"/v1/search/autocomplete":{"get":{"tags":["Filter"],"summary":"Autocomplete field names from the registry","operationId":"searchAutocomplete","security":[{"BearerAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"source_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"{ data: field-name suggestions }"}}}},"/v1/search/field-values":{"get":{"tags":["Filter"],"summary":"Distinct values for a field across documents","operationId":"searchFieldValues","security":[{"BearerAuth":[]}],"parameters":[{"name":"field","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"The field-registry UUID to read values for."},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"source_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"Distinct values with counts."},"400":{"description":"Missing or non-UUID field."}}}},"/v1/search/filter":{"post":{"tags":["Filter"],"summary":"Filter documents by field-value conditions","description":"Alias of POST /v1/documents/filter.","operationId":"searchFilter","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source_id":{"type":"string","format":"uuid"},"search":{"type":"string"},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"sort":{"type":"object","properties":{"fieldId":{"type":"string"},"direction":{"type":"string","enum":["asc","desc"]}}},"conditions":{"type":"array","items":{"type":"object","required":["fieldId","operator"],"properties":{"fieldId":{"type":"string"},"operator":{"type":"string"},"value":{},"valueTo":{}}}}}}}}},"responses":{"200":{"description":"{ data, total, links }"}}}},"/v1/search/omnisearch":{"post":{"tags":["Filter"],"summary":"Global omnisearch across documents, fields, sources, and schemas","operationId":"omnisearch","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer","minimum":1}}}}}},"responses":{"200":{"description":"{ documents, fieldMatches, sources, schemas, fields }"}}}},"/v1/search/saved-filters":{"get":{"tags":["Filter"],"summary":"List saved filters","operationId":"listSavedFilters","security":[{"BearerAuth":[]}],"parameters":[{"name":"source_id","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ data: saved filters }"}}}},"/v1/search/materialize":{"post":{"tags":["Filter"],"summary":"Trigger field-value materialization","description":"Rebuilds the materialized field-value index used by autocomplete and field-values. Requires write scope.","operationId":"materializeFieldValues","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Materialization status"}}}},"/v1/dialects/primitives":{"get":{"tags":["Dialects"],"summary":"List reference primitives","operationId":"listDialectPrimitives","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ data: primitives }"}}},"post":{"tags":["Dialects"],"summary":"Create a reference primitive","operationId":"createDialectPrimitive","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","data_schema","entries"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"data_schema":{"type":"array","items":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"type":{"type":"string","minLength":1,"maxLength":50}}}},"entries":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"responses":{"201":{"description":"Created primitive (v1) + entries"}}}},"/v1/dialects/primitives/{id}":{"get":{"tags":["Dialects"],"summary":"Get a reference primitive","operationId":"getDialectPrimitive","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Primitive + current-version entries"},"404":{"description":"Not found"}}},"delete":{"tags":["Dialects"],"summary":"Delete a reference primitive","operationId":"deleteDialectPrimitive","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ deleted: true, id }"}}}},"/v1/linking/entity-graph":{"get":{"tags":["Linking"],"summary":"Get the entity graph","operationId":"getEntityGraph","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ entities, documents, field_names, edges, stats }"}}}},"/v1/linking/entity-graph/recompute":{"post":{"tags":["Linking"],"summary":"Force an entity-graph rebuild","operationId":"recomputeEntityGraph","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ ok: true, stats }"}}}},"/v1/cases/threads":{"get":{"tags":["Cases"],"summary":"Get the cached synthesis threads","description":"The cached synthesis artifact (threads + findings). Never triggers a rebuild.","operationId":"getCaseThreads","x-required-scopes":["read"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Cached threads artifact"}}}},"/v1/cases/synthesis/status":{"get":{"tags":["Cases"],"summary":"Get the case-synthesis build status","operationId":"getCaseSynthesisStatus","x-required-scopes":["read"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ building, dirty, built_at, build_error, n_threads, never_built }"}}}},"/v1/cases/synthesis/recompute":{"post":{"tags":["Cases"],"summary":"Trigger an async case-synthesis recompute","description":"Enqueues the multi-minute synthesis pipeline and returns immediately. Poll the status endpoint. Requires write scope.","operationId":"recomputeCaseSynthesis","x-required-scopes":["write"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ ok, status, build_started_at? }"}}}},"/v1/documents/convert":{"post":{"tags":["Documents"],"summary":"Convert a file to markdown without ingesting it","description":"Stateless conversion — no document row, no extraction, no field registry. Returns the markdown plus conversion metadata. Requires write scope.\n","operationId":"convertDocument","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"vision":{"type":"string","description":"Set to \"false\" to disable vision OCR escalation."}}}}}},"responses":{"200":{"description":"{ filename, markdown, source_format, page_count, table_count, vision_pages, warnings }"},"400":{"description":"No file provided."}}}},"/v1/extractions/{id}/correct":{"post":{"tags":["Extractions"],"summary":"Correct extracted field values","description":"Overrides field values on an extraction (each set to confidence 1.0 and locked). Body is a flat map of field name to corrected value. Requires write scope.\n","operationId":"correctExtraction","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Map of field name → corrected value."}}}},"responses":{"200":{"description":"Updated extraction"},"404":{"description":"Not found"}}}},"/v1/sources/{id}/ingest":{"post":{"tags":["Sources"],"summary":"Ingest a document into a source","description":"Multipart upload of one document (≤500 MB) into the source for extraction. Alias of POST /v1/sources/{id}/documents. Requires the extract scope.\n","operationId":"ingestSourceDocument","security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"processing_mode":{"type":"string","enum":["batch","realtime"]}}}}}},"responses":{"200":{"description":"{ document_id, filename, size_bytes, status: queued, processing_mode, source_id, links } — same shape as POST /v1/sources/{id}/documents (this route is an alias); duplicate branch is { status: duplicate, message, document_id, existing_document_id, filename, size_bytes }"}}}},"/v1/ingest":{"post":{"tags":["Sources"],"summary":"Ingest a document via a standalone source API key","description":"Multipart upload of one document (≤50 MB), authenticated by a source's own `Authorization: Bearer tlnc_...` API key — no source id in the path, the key resolves it. Duplicate files (by content hash) return a `duplicate` status with the existing document's id. A narrower sibling of `POST /v1/sources/{id}/documents`: the queued response has no `processing_mode`/`source_id`, and `links` carries only `document` (no `source` link).\n","operationId":"ingestViaApiKey","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The document file. Max 50 MB."},"batch_id":{"type":"string","maxLength":200,"description":"Optional caller grouping key stamped on the document (documents.client_batch_id)."},"metadata":{"type":"string","description":"Optional JSON string of a FLAT object `{ [key]: string | number | boolean | null }` (nested objects/arrays rejected 400; ≤50 keys, key ≤128, string value ≤1024), stamped on the document as documents.client_metadata.\n"}}}}}},"responses":{"200":{"description":"Document ingested (or duplicate detected).","content":{"application/json":{"schema":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid","description":"When status is `duplicate`, the id of the linked-duplicate row created for this upload (see `existing_document_id` for the canonical)."},"filename":{"type":"string","description":"The uploaded file's own name."},"size_bytes":{"type":["integer","null"],"description":"The uploaded file's own size in bytes."},"status":{"type":"string","enum":["queued","duplicate"]},"existing_document_id":{"type":["string","null"],"format":"uuid","description":"Present when status is duplicate — the canonical document this upload deduplicated to."},"message":{"type":"string","description":"Present when status is duplicate."},"links":{"type":"object","properties":{"document":{"type":"string"}}}}},"example":{"document_id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"receipt-march.pdf","size_bytes":148213,"status":"queued","links":{"document":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"}}}},"/v1/billing/settings":{"get":{"tags":["Billing"],"summary":"Get billing (auto top-up) settings","operationId":"getBillingSettings","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Auto-topup configuration"}}},"patch":{"tags":["Billing"],"summary":"Update billing (auto top-up) settings","operationId":"updateBillingSettings","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"auto_topup_enabled":{"type":"boolean"},"auto_topup_threshold":{"type":"integer","minimum":1000},"auto_topup_amount":{"type":"integer","minimum":1000}}}}}},"responses":{"200":{"description":"Updated settings"}}}},"/v1/billing/topup":{"post":{"tags":["Billing"],"summary":"Trigger an auto top-up now","description":"Charges a top-up if auto top-up is enabled. Requires the billing scope.","operationId":"triggerBillingTopup","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"{ topped_up, ... }"},"403":{"description":"auto_topup_disabled"}}}},"/v1/ai/policy":{"get":{"operationId":"getAiPolicy","summary":"Get the effective AI policy","tags":["AI Policy"],"description":"The caller's own AI policy as it is enforced right now: the mandatory\nconstraints applied at routing time, the per-operation class map, the\nresolved defaults, and whether the policy currently leaves every gating\noperation with a compliant route.\n\n`constraints` is the enforced view: it folds the workspace policy\ntogether with the platform provider floor\n(`constraints.platform_provider_floor`), a deployment-level constraint\nthat intersects with the tenant policy and can only narrow it.\n`inherited: true` means the workspace has stored no policy of its own\nand runs on the platform default.\n\nThe workspace is taken from the authenticated key and from nowhere\nelse. A master-view key spans every workspace, has no single policy to\nread, and is rejected with 400 `workspace_scope_required`.\n","responses":{"200":{"description":"The effective policy, constraints, operation class map, and satisfiability status.","content":{"application/json":{"example":{"policy":{"version":4,"status":"active","region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"model_substitutions":null,"default_models":null,"max_attempts":null,"model_classes":null,"operation_classes":{"extraction":"complex"},"features":null},"inherited":false,"constraints":{"region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"platform_provider_floor":["bedrock"]},"operation_classes":{"extraction":{"class":"complex","source":"org","overridden":true}},"status":{"satisfiable":true,"unroutable_operations":[],"advisory_warnings":["document_ocr"]}}}}},"400":{"description":"The API key is not scoped to a single workspace.","content":{"application/json":{"example":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"put":{"operationId":"replaceAiPolicy","summary":"Replace the AI policy","tags":["AI Policy"],"description":"Replace the policy wholesale. Every field is optional in the body, but\nan omitted field is CLEARED, which makes this the route to use when the\npolicy is generated from the customer's own source of truth. To change\none field while keeping the rest, use PATCH instead.\n\nThe write defaults to `status: active`, so the satisfiability gate\nbinds: a policy that would leave a registered operation with no\ncompliant route is refused with 400 `policy_unsatisfiable` and nothing\nis stored. Only `active` policies are enforced at routing time;\n`draft` and `shadow` versions are stored without taking effect.\n\nNaming asymmetry, deliberate: top-level fields are snake_case, but\nvalues INSIDE `model_classes` (`chain`, `requiredCapabilities`,\n`fallback`) and the keys of `features` (`dataCapture`,\n`markdownExtraction`, `assetVision`, `assetAnnotation`,\n`classificationEscalation`, `richSummary`, `documentClassification`)\nstay camelCase because they pass straight to the shared policy\nvalidator.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"region_pin":{"type":["string","null"],"enum":["us","eu",null],"description":"Hard residency constraint. A deployment in any other region is rejected, including globally-routed ones."},"allowed_providers":{"type":["array","null"],"items":{"type":"string","enum":["anthropic","bedrock","foundry","openai","azure-openai","google","mistral","local"]},"description":"Providers permitted to process this workspace's data. Null or omitted means every provider the platform permits."},"denied_models":{"type":["array","null"],"items":{"type":"string"},"description":"Models this workspace may never be routed to, whatever else permits them. Applies to explicit requests and every fallback chain step alike."},"model_substitutions":{"type":"object","additionalProperties":{"type":"string"},"description":"Remap one model onto another wherever the first would be chosen."},"default_models":{"type":"object","description":"Preferred model per speed tier where no class governs the call. Keys are fast, default, powerful."},"max_attempts":{"type":"integer","minimum":1,"maximum":8,"description":"Ceiling on provider attempts for one logical call."},"model_classes":{"type":"object","description":"Named model lineage overrides. Values are camelCase: { description, chain: [{ model, deployments: [{ provider, region }] }], requiredCapabilities, fallback: chain | primary_only }."},"operation_classes":{"type":"object","additionalProperties":{"type":["string","null"]},"description":"Per-operation class overrides, keyed by operation type."},"features":{"type":"object","additionalProperties":{"type":"boolean"},"description":"Feature toggles, camelCase keys. Absent toggles stay on."},"status":{"type":"string","enum":["draft","shadow","active"],"default":"active","description":"Lifecycle state to save under. Only active is enforced at runtime."},"change_reason":{"type":"string","maxLength":200,"description":"Why this change is being made. Recorded on the stored version."}}},"example":{"region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"operation_classes":{"extraction":"complex"},"change_reason":"Contractual EU residency"}}}},"responses":{"200":{"description":"The saved version plus the resulting effective policy view (the GET response body).","content":{"application/json":{"example":{"saved":{"version":7,"status":"active"},"policy":{"version":7,"status":"active","region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"model_substitutions":null,"default_models":null,"max_attempts":null,"model_classes":null,"operation_classes":{"extraction":"complex"},"features":null},"inherited":false,"constraints":{"region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"platform_provider_floor":["bedrock"]},"operation_classes":{"extraction":{"class":"complex","source":"org","overridden":true}},"status":{"satisfiable":true,"unroutable_operations":[],"advisory_warnings":["document_ocr"]}}}}},"400":{"description":"The policy was refused and nothing was stored.","content":{"application/json":{"examples":{"policy_unsatisfiable":{"summary":"Activation would strand registered operations","value":{"error":"policy_unsatisfiable","message":"This policy leaves 2 operations with no compliant route: extraction, classification. Widen the allowed providers, the region pin, or the denied models, then submit again.","unroutable_operations":["extraction","classification"],"advisory_warnings":["document_ocr"]}},"invalid_policy":{"summary":"The policy shape or a referenced model is invalid","value":{"error":"invalid_policy","message":"denied model 'not-a-real-model' is not in the catalog"}},"workspace_scope_required":{"summary":"The key is not scoped to a single workspace","value":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}},"patch":{"operationId":"patchAiPolicy","summary":"Update part of the AI policy","tags":["AI Policy"],"description":"Partial update. Omitted fields keep their current value, and inside the\noverride maps (`model_substitutions`, `default_models`,\n`model_classes`, `operation_classes`, `features`) omitted keys survive\ntoo. Sending `null` as a map value removes that single override and\nrestores the platform default for it.\n\n`status` defaults to the policy's current status (or `active` when\nnone is stored), so patching an active policy keeps it active and the\nsatisfiability gate binds exactly as it does on PUT. The same camelCase\nrule applies to values inside `model_classes` and to `features` keys.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Same fields as PUT /v1/ai/policy; every field optional, omissions preserved."},"example":{"denied_models":["claude-opus"],"operation_classes":{"extraction":null},"change_reason":"Remove the extraction override, deny one model"}}}},"responses":{"200":{"description":"The saved version plus the resulting effective policy view (the GET response body).","content":{"application/json":{"example":{"saved":{"version":8,"status":"active"},"policy":{"version":8,"status":"active","region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"model_substitutions":null,"default_models":null,"max_attempts":null,"model_classes":null,"operation_classes":null,"features":null},"inherited":false,"constraints":{"region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"platform_provider_floor":["bedrock"]},"operation_classes":{"extraction":{"class":"standard","source":"builtin","overridden":false}},"status":{"satisfiable":true,"unroutable_operations":[],"advisory_warnings":[]}}}}},"400":{"description":"The policy was refused and nothing was stored. Same error contract as PUT.","content":{"application/json":{"example":{"error":"policy_unsatisfiable","message":"This policy leaves 1 operation with no compliant route: extraction. Widen the allowed providers, the region pin, or the denied models, then submit again.","unroutable_operations":["extraction"],"advisory_warnings":[]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ai/models":{"get":{"operationId":"listAiModels","summary":"List models and model classes with reachability","tags":["AI Policy"],"description":"Every model and model class the platform knows, annotated with\nprovider, region, and why each is or is not reachable for this\nworkspace under the live policy. This is the answer to \"which models\ncan touch our data\", derived from the policy rather than from\ndocumentation that can drift away from it.\n\n`reason` is one of `allowed`, `model_denied`, `provider_floor`,\n`provider_not_allowed`, `region_not_permitted`. A class's `source` is\n`builtin`, `platform`, or `org`. A deployment with\n`custom_endpoint: true` is a self-hosted or customer-operated\ninference endpoint declared at deployment level; no host and no\ncredential detail is ever returned.\n","responses":{"200":{"description":"The annotated model catalog, class definitions, enforced constraints, and reachability counts.","content":{"application/json":{"example":{"models":[{"model":"claude-sonnet","tier":"default","capabilities":["generate","tool_use"],"reachable":true,"reason":"allowed","deployments":[{"provider":"bedrock","region":"eu","custom_endpoint":false,"reachable":true,"reason":"allowed"}]},{"model":"claude-opus","tier":"powerful","capabilities":["generate","tool_use"],"reachable":false,"reason":"model_denied","deployments":[{"provider":"bedrock","region":"eu","custom_endpoint":false,"reachable":false,"reason":"model_denied"}]}],"classes":[{"name":"standard","description":"General-purpose extraction lineage","source":"builtin","required_capabilities":[],"fallback":"chain","chain":[{"model":"claude-sonnet","reachable":true,"reason":"allowed"}],"reachable":true}],"constraints":{"region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"platform_provider_floor":["bedrock"]},"counts":{"total":18,"reachable":9}}}}},"400":{"description":"The API key is not scoped to a single workspace.","content":{"application/json":{"example":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ai/operations":{"get":{"operationId":"listAiOperations","summary":"List the operation catalog","tags":["AI Policy"],"description":"Every operation type the platform runs, the model class it resolves to\nfor this workspace, whether the workspace overrode it, how it gates\npolicy activation, and whether it currently has a compliant route.\n\n`gating` separates operations: `registered` operations block a policy\nfrom activating when they lose their route, `advisory` operations only\nwarn, and `none` operations are not swept at all (`routable` is null\nfor them rather than implying a check that never ran). This\ndistinction is why a region pin can leave document OCR unroutable\nwithout blocking the rest of the workspace.\n","responses":{"200":{"description":"The operation catalog with per-operation class, gating, and routability.","content":{"application/json":{"example":{"operations":[{"operation_type":"extraction","class":"standard","source":"builtin","overridden":false,"gating":"registered","routable":true},{"operation_type":"document_ocr","class":"ocr","source":"builtin","overridden":false,"gating":"advisory","routable":false,"reason":"no_compliant_route"}],"counts":{"total":60,"overridden":1,"registered":8,"advisory":1}}}}},"400":{"description":"The API key is not scoped to a single workspace.","content":{"application/json":{"example":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ai/routes:explain":{"post":{"operationId":"explainAiRoute","summary":"Dry-run a routing decision","tags":["AI Policy"],"description":"Answer \"what would this operation route to right now\" without spending\na model call. The question runs through the same resolver that serves\nlive traffic, so the answer is evidence rather than a forecast: the\nordered candidate chain that would serve the operation, and every\ncandidate the policy discarded with the constraint that discarded it.\n\nWhen the policy permits no route, the response is still 201 with\n`routable: false` and a plain-language explanation. A policy that\npermits no route is a valid configuration whose consequence is that\nthe live call fails closed rather than reaching a provider the policy\nforbids.\n\n`model` pins a specific logical model instead of letting the\noperation's class choose; `class` pins a specific model class. Both\nare optional.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["operation_type"],"properties":{"operation_type":{"type":"string","maxLength":120,"description":"The operation to route, for example extraction or classification."},"model":{"type":"string","maxLength":120,"description":"Optional. Pin a specific logical model."},"class":{"type":"string","maxLength":120,"description":"Optional. Pin a specific model class."}}},"example":{"operation_type":"extraction","model":"claude-sonnet","class":"standard"}}}},"responses":{"201":{"description":"The routing plan, or a fail-closed explanation when nothing is routable.","content":{"application/json":{"examples":{"routable":{"summary":"An ordered candidate chain exists","value":{"operation_type":"extraction","routable":true,"class":"standard","fallback_scope":"class_chain","candidates":[{"model":"claude-sonnet","provider":"bedrock","region":"eu","custom_endpoint":false}],"rejected":[{"model":"gpt-balanced","provider":"openai","region":"global","reason":"provider_not_allowed"}]}},"fail_closed":{"summary":"The policy permits no route for this operation","value":{"operation_type":"document_ocr","routable":false,"reason":"no_compliant_route","message":"No route satisfies this workspace policy for this operation, so the call fails closed rather than reaching a provider the policy does not permit.","candidates":[],"rejected":[{"model":"mistral-ocr","provider":"mistral","region":"global","reason":"provider_not_allowed"}]}}}}}},"400":{"description":"The request body is invalid or the key is not workspace-scoped.","content":{"application/json":{"example":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/ai/policy/history":{"get":{"operationId":"getAiPolicyHistory","summary":"Get the policy version history","tags":["AI Policy"],"description":"Version history of the caller's own policy, newest first, each version\ncarrying its lifecycle status, the fields it changed relative to the\nprevious version, its attribution (`changed_by`, `change_reason`,\n`changed_at`, each nullable: null means the store did not record it,\nnot that nothing changed), and the full stored policy.\n\nOnly versions this workspace stored appear. A workspace running on the\ninherited platform default has no versions of its own and reads as an\nempty list, which is the honest answer to \"what have we changed\".\n","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Maximum number of versions to return (1-200)."}],"responses":{"200":{"description":"Stored policy versions, newest first.","content":{"application/json":{"example":{"versions":[{"version":2,"status":"active","changed":["region_pin","denied_models"],"changed_by":"api_key:c1a2b3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d","change_reason":"Contractual EU residency","changed_at":"2026-07-28T14:02:11.000Z","policy":{"version":2,"status":"active","region_pin":"eu","allowed_providers":["bedrock"],"denied_models":["claude-opus"],"model_substitutions":null,"default_models":null,"max_attempts":null,"model_classes":null,"operation_classes":null,"features":null}},{"version":1,"status":"active","changed":["allowed_providers"],"changed_by":null,"change_reason":null,"changed_at":null,"policy":{"version":1,"status":"active","region_pin":null,"allowed_providers":["bedrock"],"denied_models":null,"model_substitutions":null,"default_models":null,"max_attempts":null,"model_classes":null,"operation_classes":null,"features":null}}],"total":2,"limit":50}}}},"400":{"description":"The API key is not scoped to a single workspace.","content":{"application/json":{"example":{"error":"workspace_scope_required","message":"A workspace-scoped API key is required to read or change AI policy."}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}}},"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"tlnc_*","description":"API key with `tlnc_` prefix. Pass as `Authorization: Bearer tlnc_live_...`.\n"},"OAuthBearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth 2.1 access token (JWT) from the connector OAuth flow. Routes\nthat declare this scheme reject `tlnc_` API keys with `401`.\n"}},"parameters":{"ResourceId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"description":"Resource UUID."},"Limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Maximum number of items to return (1–100)."},"Cursor":{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from a previous response's `pagination.next_cursor`."},"Order":{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort order by creation date."},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"description":"Unique key for idempotent requests. If a request with the same key was\nalready processed, the cached result is returned.\n"}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Daily request limit for this namespace."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Remaining requests until the window resets."},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"},"description":"ISO 8601 timestamp when the rate-limit window resets (midnight UTC)."}},"responses":{"BadRequest":{"description":"The request is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"code":"VALIDATION_ERROR","error":"Bad Request","message":"name is required.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/schemas"}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"code":"AUTH_REQUIRED","error":"Unauthorized","message":"Invalid or missing API key.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/extract"}}}},"Forbidden":{"description":"The API key does not have the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"code":"INSUFFICIENT_PERMISSIONS","error":"Forbidden","message":"This key does not have the 'write' scope.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/schemas"}}}},"NotFound":{"description":"The requested resource was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"code":"RESOURCE_NOT_FOUND","error":"Not Found","message":"Document 'f0e1d2c3-b4a5-9687-8765-432109876543' not found.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/documents/f0e1d2c3-b4a5-9687-8765-432109876543"}}}},"Conflict":{"description":"The request conflicts with the current resource state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":409,"code":"VALIDATION_ERROR","error":"Conflict","message":"Job is already completed. Cannot cancel.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/jobs/c3d4e5f6-a7b8-9012-cdef-123456789012/cancel"}}}},"PayloadTooLarge":{"description":"The uploaded file exceeds the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":413,"code":"FILE_TOO_LARGE","error":"Payload Too Large","message":"File exceeds the 500 MB limit.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/extract"}}}},"UnprocessableEntity":{"description":"The document could not be processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":422,"code":"EXTRACTION_FAILED","error":"Unprocessable Entity","message":"Unable to extract fields from the provided document.","retryable":false,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/extract","links":{"dashboard":"https://app.talonic.com/documents/abc-123"}}}}},"RateLimitExceeded":{"description":"Daily rate limit exceeded.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":429,"code":"QUOTA_EXCEEDED","error":"Too Many Requests","message":"Daily extract request ceiling reached. Resets at midnight UTC. Spend is governed by credits, not this abuse ceiling.","retryable":true,"timestamp":"2026-04-25T23:45:00.000Z","path":"/v1/extract"}}}},"InsufficientCredits":{"description":"Insufficient credits (402). The body is the agent-actionable contract:\n`buy_credits_url` is where a human completes a purchase (see also\n`GET /v1/billing/upgrade-link` for a direct Stripe Checkout link), and\n`pricing_url` is the machine-readable rate catalog. Free workspaces\nreceive 5,000 credits monthly; purchased credits top up the same\nbalance.\n","content":{"application/json":{"schema":{"type":"object","required":["error","message","required_credits","balance_credits"],"properties":{"error":{"type":"string","example":"insufficient_credits"},"message":{"type":"string"},"required_credits":{"type":"integer","example":100},"balance_credits":{"type":"integer","example":0},"buy_credits_url":{"type":"string","format":"uri","example":"https://app.talonic.com/settings/billing?buy=1"},"pricing_url":{"type":"string","example":"/v1/pricing"}}}}}},"InternalServerError":{"description":"An unexpected error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"code":"INTERNAL_ERROR","error":"Internal Server Error","message":"An unexpected error occurred. Please try again or contact support.","retryable":true,"timestamp":"2026-04-25T14:30:00.000Z","path":"/v1/extract"}}}}},"schemas":{"OntologyDoctype":{"type":"object","required":["key","name"],"properties":{"key":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"},"maps_to":{"type":"string","description":"A Talonic ontology_type_id the doctype anchors to."},"description":{"type":"string"},"signals":{"type":"array","items":{"type":"string"}}}},"OntologyField":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"canonical_name":{"type":"string"},"display_name":{"type":"string"},"data_type":{"type":"string"},"description":{"type":"string"},"synonyms":{"type":"array","items":{"type":"string"}},"doctype_scope":{"type":"string","description":"Custom doctype key, or null/empty/* for global."},"required":{"type":"boolean"},"format":{"type":"string"},"enum_values":{"type":"array","items":{"type":"string"}},"examples":{"type":"array","items":{"type":"string"}}}},"OntologyUpdate":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"doctypes":{"type":"array","items":{"$ref":"#/components/schemas/OntologyDoctype"}},"fields":{"type":"array","items":{"$ref":"#/components/schemas/OntologyField"}}}},"OntologyImport":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"doctypes":{"type":"array","items":{"$ref":"#/components/schemas/OntologyDoctype"}},"fields":{"type":"array","items":{"$ref":"#/components/schemas/OntologyField"}},"publish":{"type":"boolean","description":"Publish immediately after import."}}},"RunResponse":{"type":"object","properties":{"run_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","running","step_extract","step_structure","step_reconcile","completed","failed"]},"config_id":{"type":"string"},"batch_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"started_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time"},"duration_ms":{"type":"integer"},"current_step":{"type":"string"},"markdown":{"type":"string","description":"OCR-converted markdown (on completion)."},"structured_data":{"type":"object","description":"Structured extraction results (on completion)."},"reconciliation":{"type":"object","description":"Reconciliation results (on completion)."},"error":{"type":"object","description":"Error detail (on failure).","properties":{"step":{"type":"string"},"error_code":{"type":"string"},"message":{"type":"string"}}}}},"ConfigResponse":{"type":"object","properties":{"config_id":{"type":"string","example":"cfg_bridgeway_invoice_v1"},"name":{"type":"string"},"description":{"type":"string"},"credit_cost":{"type":"integer"},"steps":{"type":"array","items":{"type":"string"},"example":["extract","structure","reconcile"]}}},"ErrorResponse":{"type":"object","required":["statusCode","code","error","message","retryable","timestamp","path"],"properties":{"statusCode":{"type":"integer","description":"HTTP status code.","example":400},"code":{"type":"string","description":"Machine-readable error discriminant. One of: VALIDATION_ERROR,\nAUTH_REQUIRED, TOKEN_EXPIRED, INSUFFICIENT_PERMISSIONS,\nRESOURCE_NOT_FOUND, QUOTA_EXCEEDED, INSUFFICIENT_CREDITS,\nLLM_RATE_LIMITED, LLM_TIMEOUT, LLM_UNAVAILABLE, OCR_FAILED,\nEXTRACTION_FAILED, EXTRACTION_TIMEOUT, FILE_TOO_LARGE,\nDUPLICATE_RESOURCE, DATASPACE_RUN_FAILED, INTERNAL_ERROR.\n","example":"VALIDATION_ERROR"},"error":{"type":"string","description":"HTTP status name.","example":"Bad Request"},"message":{"type":"string","description":"Human-readable error description.","example":"name is required."},"retryable":{"type":"boolean","description":"Whether the client should retry the request.","example":false},"timestamp":{"type":"string","format":"date-time","description":"ISO 8601 timestamp when the error occurred.","example":"2026-04-25T14:30:00.000Z"},"path":{"type":"string","description":"Request path that failed.","example":"/v1/schemas"}}},"WebhookEvent":{"type":"object","description":"Webhook delivery payload sent to configured destinations.","required":["event"],"properties":{"event":{"type":"object","required":["event_type","event_id","binding_id","idempotency_key","attempt","delivered_at"],"properties":{"event_type":{"type":"string","description":"The event that triggered this delivery. One of:\ndocument.extracted, document.extraction_failed,\nrun.dataspace.completed, run.dataspace.failed,\nresult.dataspace.completed, result.dataspace.failed,\nrun.structuring.completed, run.structuring.failed,\nrun.resolution.completed, run.resolution.failed,\nrun.extraction.completed, run.extraction.failed,\nresult.flagged, result.approved, result.rejected,\ndelivery.item.completed, delivery.item.failed.\n","example":"document.extracted"},"event_id":{"type":"string","description":"Monotonically increasing event sequence ID.","example":"42"},"binding_id":{"type":"string","format":"uuid","description":"The delivery binding that matched this event.","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"idempotency_key":{"type":"string","description":"32-character hex key derived from binding_id + event_id. Stable across retries.","example":"c9f3a7e1b2d4f6a8e0c2d4f6a8e0c2d4"},"attempt":{"type":"integer","description":"Delivery attempt number (1–7).","example":1},"delivered_at":{"type":"string","format":"date-time","description":"Timestamp of this delivery attempt.","example":"2026-04-25T14:30:00.000Z"}}},"payload":{"type":"object","description":"Serialized deliverable data. Shape depends on the deliverable type and serializer format configured on the binding.","additionalProperties":true,"example":{"document_id":"f0e1d2c3-b4a5-9687-8765-432109876543","filename":"invoice-042.pdf","status":"completed","data":{"invoice_number":"INV-2024-0042","total_amount":1250}}},"content":{"type":["object","null"],"description":"Binary content envelope (for file-type serializers like CSV/XLSX). Null when payload is used instead.","properties":{"mime":{"type":"string","example":"text/csv"},"encoding":{"type":"string","enum":["utf-8","base64"],"example":"utf-8"},"data":{"type":"string","description":"UTF-8 text or base64-encoded binary."}}}}},"PaginatedResponse":{"type":"object","properties":{"data":{"type":"array","items":{}},"pagination":{"type":"object","required":["total","limit","has_more","next_cursor"],"properties":{"total":{"type":"integer","description":"Total number of matching records.","example":142},"limit":{"type":"integer","description":"Requested page size.","example":20},"has_more":{"type":"boolean","description":"Whether more pages exist.","example":true},"next_cursor":{"type":["string","null"],"description":"Cursor to pass for the next page. Null if no more pages.","example":"ZDFhMmIzYzR8MjAyNi0wNC0wM1QxMjowMDowMC4wMDBa"}}}}},"DeletedResponse":{"type":"object","required":["deleted","id"],"properties":{"deleted":{"type":"boolean","example":true},"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}},"ExtractSyncResponse":{"type":"object","required":["extraction_id","request_id","status","document","data"],"properties":{"extraction_id":{"type":"string","format":"uuid","example":"d1a2b3c4-5678-9abc-def0-1234567890ab"},"request_id":{"type":"string","example":"req_x7y8z9a0b1c2d3e4"},"status":{"type":"string","enum":["complete"],"example":"complete"},"document":{"$ref":"#/components/schemas/ExtractDocumentSummary"},"data":{"type":"object","additionalProperties":true,"description":"Extracted key-value pairs.","example":{"invoice_number":"INV-2024-0042","total_amount":1250,"vendor_name":"Acme Corp"}},"schema":{"type":"object","properties":{"source":{"type":"string","description":"Where the schema came from (e.g. `inline`, `saved`, `auto`)."},"id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"definition":{"type":"object","additionalProperties":true},"save_url":{"type":"string","format":"uri","description":"URL to save the auto-generated schema in the dashboard."}}},"confidence":{"type":"object","properties":{"overall":{"type":"number","format":"float","minimum":0,"maximum":1,"description":"Average confidence across all fields.","example":0.92},"fields":{"type":"object","additionalProperties":{"type":"number","format":"float"},"description":"Per-field confidence scores.","example":{"invoice_number":0.99,"total_amount":0.95,"vendor_name":0.82}}}},"processing":{"type":"object","properties":{"duration_ms":{"type":"integer","description":"Total processing time in milliseconds.","example":3420},"pages_processed":{"type":"integer","example":3},"region":{"type":"string","example":"eu-west"}}},"links":{"type":"object","properties":{"self":{"type":"string"},"document":{"type":"string"},"dashboard":{"type":"string","format":"uri"}}}}},"ExtractAsyncResponse":{"type":"object","required":["request_id","status","job","document"],"properties":{"request_id":{"type":"string","format":"uuid","example":"req_x7y8z9a0b1c2d3e4"},"status":{"type":"string","example":"completed","enum":["processing"]},"job":{"type":"object","required":["id","status","poll_url"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["queued"]},"poll_url":{"type":"string","description":"URL to poll for job progress.","example":"/v1/jobs/abc-123"},"estimated_seconds":{"type":"integer","description":"Estimated processing time in seconds.","example":15}}},"document":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"invoice-042.pdf"},"pages":{"type":"integer"},"size_bytes":{"type":["integer","null"],"example":148213}}},"links":{"type":"object","properties":{"dashboard":{"type":"string","format":"uri"}}}}},"ExtractDocumentSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"invoice-042.pdf"},"pages":{"type":"integer","example":3},"size_bytes":{"type":"integer","example":245760},"type_detected":{"type":["string","null"],"description":"AI-inferred document type.","example":"Invoice"},"language_detected":{"type":["string","null"],"example":"en"}}},"DocumentResponse":{"type":"object","required":["id","filename","status","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"contract-2024.pdf"},"pages":{"type":"integer","example":12},"size_bytes":{"type":"integer","example":1048576},"mime_type":{"type":"string","example":"application/pdf"},"type_detected":{"type":["string","null"],"example":"Service Contract"},"language_detected":{"type":["string","null"],"example":"en"},"status":{"type":"string","example":"completed","enum":["pending","processing","completed","error"]},"error":{"type":"string","description":"Human-readable failure message. Present ONLY when status is `error`; omitted otherwise.\n","example":"Extraction failed"},"source":{"type":"object","properties":{"id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"type":{"type":"string","example":"manual"}}},"field_count":{"type":"integer","description":"Number of fields captured from the document. 0 until extraction completes.","example":42},"triage":{"type":["object","null"],"description":"Compliance triage signals for the document. `null` until triage has run.\n","properties":{"sensitivity":{"type":["string","null"],"enum":["public","internal","restricted",null],"description":"Sensitivity tier.","example":"internal"},"department":{"type":["string","null"],"example":"finance"},"jurisdiction":{"type":["string","null"],"description":"Two-letter country code.","example":"DE"},"pii_detected":{"type":"boolean","description":"True when at least one PII category was detected.","example":true},"pii_categories":{"type":["array","null"],"items":{"type":"string"},"description":"Detected PII categories. `null` until the compliance pass has run.","example":["name","email"]},"regulated_data":{"type":"boolean","description":"Whether the document likely contains regulated data.","example":false},"confidentiality_marking":{"type":["string","null"],"description":"Confidentiality marking found in the document, if any.","example":"Vertraulich"}}},"original_path":{"type":["string","null"],"description":"Folder path of the file at its source, when ingested from a connector.","example":"/invoices/2026/04"},"batch_id":{"type":"string","description":"Caller grouping key supplied at ingest (batch_id). Present ONLY when the document was tagged; omitted otherwise (backwards-compatible).\n","example":"2026-07-14-run-042"},"metadata":{"type":"object","additionalProperties":{"type":["string","number","boolean","null"]},"description":"Caller flat metadata supplied at ingest. Present ONLY when the document was tagged; omitted otherwise (backwards-compatible).\n","example":{"customer":"bridgeway","source":"sftp"}},"extraction_count":{"type":"integer","example":1},"latest_extraction_id":{"type":["string","null"],"format":"uuid","example":"d1a2b3c4-5678-9abc-def0-1234567890ab"},"processing_log":{"type":"array","description":"Per-stage pipeline timing log (OCR, classify, extract). Present ONLY when at least one stage has been recorded; omitted otherwise.\n","items":{"type":"object","required":["step","status","started_at"],"properties":{"step":{"type":"string","example":"ocr"},"status":{"type":"string","example":"completed"},"started_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time"},"duration_ms":{"type":"integer","example":3120},"detail":{"type":"string"}}}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"extractions":{"type":"string"},"fields":{"type":"string"},"lineage":{"type":"string"},"dashboard":{"type":"string","format":"uri"}}}}},"ExtractionListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["complete","failed","processing"]},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"document_filename":{"type":"string","example":"invoice-042.pdf"},"confidence_overall":{"type":"number","format":"float"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"document":{"type":"string"}}}}},"ExtractionResponse":{"type":"object","required":["id","status","document","data","confidence"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["complete","failed","processing"]},"document":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"invoice-042.pdf"},"pages":{"type":"integer"},"type_detected":{"type":["string","null"]}}},"data":{"type":"object","additionalProperties":true,"description":"Extracted key-value pairs."},"confidence":{"type":"object","properties":{"overall":{"type":"number","format":"float","minimum":0,"maximum":1},"fields":{"type":"object","additionalProperties":{"type":"number","format":"float"}}}},"locked_fields":{"type":"array","items":{"type":"string"},"description":"Fields that have been manually corrected (locked at confidence 1.0)."},"batch_id":{"type":"string","description":"The caller grouping key stamped on this document at ingestion (documents.client_batch_id) — e.g. from POST /v1/run or POST /v1/sources/:id/documents. Present only when set.\n"},"metadata":{"type":"object","additionalProperties":true,"description":"The caller's flat metadata bag stamped on this document at ingestion (documents.client_metadata) — for a /v1/run input, its per-request EFFECTIVE merged bag (call-level metadata merged with any file_metadata entry). Present only when set.\n"},"processing":{"type":"object","properties":{"duration_ms":{"type":"integer"},"pages_processed":{"type":"integer"},"region":{"type":"string","example":"eu-west"}}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"data":{"type":"string"},"document":{"type":"string"},"dashboard":{"type":"string","format":"uri"}}}}},"SchemaResponse":{"type":"object","required":["id","name","definition"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Invoice Schema"},"description":{"type":["string","null"],"example":"Standard invoice fields for AP processing."},"definition":{"type":"object","description":"JSON Schema definition of the extraction target.","properties":{"type":{"type":"string","example":"object"},"properties":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"}}}},"required":{"type":"array","items":{"type":"string"}}},"example":{"type":"object","properties":{"invoice_number":{"type":"string","title":"Invoice Number"},"total_amount":{"type":"number","title":"Total Amount","description":"Total invoice amount including tax"}},"required":["invoice_number"]}},"field_count":{"type":"integer","example":8},"version":{"type":"integer","example":1},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"extractions":{"type":"string"},"dashboard":{"type":"string","format":"uri"}}}}},"SchemaCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100,"description":"Schema name.","example":"Invoice Schema"},"description":{"type":["string","null"],"description":"Optional description."},"definition":{"type":"object","description":"JSON Schema definition. If provided, `properties` describes the fields.\nEach property key is the field name; the value is an object with `type`,\noptional `title`, and optional `description`.\n","properties":{"properties":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"}}}},"required":{"type":"array","items":{"type":"string"}}}},"fields":{"type":"array","description":"Flat fields array (alternative to `definition.properties`). Each element has\nat minimum a `field_name`; other attributes are optional.\n","items":{"type":"object","required":["field_name"],"properties":{"field_name":{"type":"string","example":"invoice_number"},"display_name":{"type":"string","example":"Invoice Number"},"data_type":{"type":"string","description":"Field type hint. Accepted values: string, number, integer, boolean, date, array, object. Defaults to string. Extracted values are returned as the specified type when possible.","example":"number"},"description":{"type":"string"},"is_required":{"type":"boolean"}}}}}},"SchemaUpdateRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":["string","null"]},"definition":{"type":"object","properties":{"properties":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"}}}},"required":{"type":"array","items":{"type":"string"}}}},"fields":{"type":"array","description":"Flat fields array (alternative to `definition.properties`). Each element has\nat minimum a `field_name`; other attributes are optional.\n","items":{"type":"object","required":["field_name"],"properties":{"field_name":{"type":"string","example":"invoice_number"},"display_name":{"type":"string","example":"Invoice Number"},"data_type":{"type":"string","example":"string"},"description":{"type":"string"},"is_required":{"type":"boolean"}}}}}},"JobResponse":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":["string","null"],"example":"Q1 Invoice Processing"},"status":{"type":"string","example":"completed","enum":["pending","queued","processing","complete","failed"]},"progress":{"type":["integer","null"],"description":"Percentage complete (0–100). Only present while `processing`.","example":45},"estimated_seconds_remaining":{"type":["integer","null"]},"schema":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"}}},"document_count":{"type":"integer","description":"Total documents in the job.","example":150},"completed_documents":{"type":"integer","description":"Documents that have finished processing.","example":67},"grid_stats":{"type":["object","null"],"description":"Grid fill statistics.","properties":{"total_cells":{"type":"integer","example":8850},"filled":{"type":"integer","example":6200},"empty":{"type":"integer","example":2650},"fill_rate":{"type":"number","format":"float","example":0.7}}},"current_phase":{"type":["string","null"],"description":"Current pipeline phase.","enum":["phase_1_resolve","phase_2_strategy","phase_2_execute","phase_2_outliers","phase_3_validation","phase_4_reread","completed","error"]},"error":{"type":["object","null"],"description":"Present only when status is `failed`.","properties":{"code":{"type":"string"},"message":{"type":"string","example":"Re-extraction started."}}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"started_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"cancel":{"type":"string","description":"Cancel URL. Only present for pending/processing jobs."},"dashboard":{"type":"string","format":"uri"}}}}},"SourceResponse":{"type":"object","required":["id","name","type","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Invoices Ingest"},"type":{"type":"string","example":"api"},"status":{"type":"string","example":"completed","enum":["active","syncing","error"]},"document_count":{"type":"integer","example":42},"default_schema":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}},"endpoint":{"type":"string","description":"URL path for uploading documents to this source.","example":"/v1/sources/abc-123/documents"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"documents":{"type":"string"},"dashboard":{"type":"string","format":"uri"}}}}},"SourceCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Source name.","example":"Invoices Ingest"},"default_schema_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"Optional schema ID to apply by default to documents in this source."}}},"SourceUpdateRequest":{"type":"object","properties":{"name":{"type":"string"},"default_schema_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"Set to null to remove the default schema."}}},"IngestDocumentResponse":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543","description":"ID of the created document. When status is `duplicate`, this is the id of the linked-duplicate row created for this upload (see `existing_document_id` for the canonical document)."},"filename":{"type":"string","example":"invoice-042.pdf","description":"The uploaded file's own name — present on both the `queued` and `duplicate` branches."},"size_bytes":{"type":["integer","null"],"example":148213,"description":"The uploaded file's own size in bytes — present on both the `queued` and `duplicate` branches."},"status":{"type":"string","example":"completed","enum":["queued","duplicate"],"description":"`queued` if the document was accepted, `duplicate` if a matching file already exists."},"source_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"message":{"type":"string","example":"Re-extraction started.","description":"Present when status is `duplicate`."},"existing_document_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"Present when status is `duplicate` — the canonical document this upload deduplicated to (the linked duplicate reads its extracted data from it). The `document_id` field carries the id of the linked-duplicate row created for this upload."},"links":{"type":"object","properties":{"document":{"type":"string"},"source":{"type":"string"}}}}},"SourceDocumentItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"invoice-042.pdf"},"status":{"type":"string","example":"completed","enum":["pending","processing","completed","error"]},"size_bytes":{"type":"integer"},"type_detected":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"JobCreateRequest":{"type":"object","required":["schema_id"],"properties":{"schema_id":{"type":"string","format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901","description":"User schema UUID to run this job against."},"document_ids":{"type":"array","description":"Optional list of document UUIDs to process. If omitted or empty, all\ncompleted documents for the authenticated customer are used.\n","items":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}},"name":{"type":["string","null"],"maxLength":200,"description":"Optional human-readable job name.","example":"Q1 Invoice Processing"}}},"JobCreateResponse":{"type":"object","required":["id","status","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"The newly created job's UUID."},"status":{"type":"string","example":"completed","enum":["pending"],"description":"The job always starts in `pending` state."},"message":{"type":"string","example":"Job created and queued for processing."},"links":{"type":"object","properties":{"self":{"type":"string","example":"/v1/jobs/abc-123"},"results":{"type":"string","example":"/v1/jobs/abc-123/results"}}}}},"JobResultsResponse":{"type":"object","required":["job_id","job_status","total_rows","data"],"properties":{"job_id":{"type":"string","format":"uuid","example":"c3d4e5f6-a7b8-9012-cdef-123456789012"},"job_status":{"type":"string","enum":["pending","queued","processing","complete","failed"],"description":"Current job status (with `completed` mapped to `complete`)."},"schema":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"}}},"total_rows":{"type":"integer","description":"Number of result rows returned.","example":150},"data":{"type":"array","description":"One entry per processed document.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"The result row's UUID."},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"filename":{"type":"string","example":"invoice-042.pdf"},"status":{"type":"string","example":"completed","description":"Per-row status (e.g. `complete`, `partial`, `failed`)."},"values":{"type":"object","additionalProperties":true,"description":"Extracted field values keyed by field name."},"confidence":{"type":["number","null"],"format":"float","description":"Row-level average confidence score."},"validation_flags":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Validation flags raised during Phase 4."}}}},"links":{"type":"object","properties":{"self":{"type":"string"},"job":{"type":"string"}}}}},"DialectResponse":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"European CSV"},"version":{"type":"integer","description":"Monotonically increasing version counter. Bumped on every update.","example":1},"config":{"$ref":"#/components/schemas/DialectConfig"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"DialectConfig":{"type":"object","description":"Dialect configuration payload; all keys optional.","properties":{"date_format":{"type":"string","description":"Date format pattern (e.g. `YYYY-MM-DD`, `DD/MM/YYYY`).","example":"YYYY-MM-DD"},"number_locale":{"type":"string","description":"BCP-47 locale tag used for number formatting.","example":"en-US"},"delimiter":{"type":"string","description":"CSV column delimiter character.","example":","},"null_representation":{"type":"string","description":"How null values are rendered in serialised output.","example":""},"encoding":{"type":"string","description":"Character encoding label (e.g. `UTF-8`, `ISO-8859-1`).","example":"UTF-8"},"boolean_format":{"type":"array","description":"Exactly 2 strings — `[true_value, false_value]`.","minItems":2,"maxItems":2,"items":{"type":"string"},"example":["true","false"]}}},"DialectCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Dialect name. Required, non-empty.","example":"European CSV"},"date_format":{"type":"string","description":"Date format string (e.g. `YYYY-MM-DD`, `DD/MM/YYYY`)."},"number_locale":{"type":"string","description":"BCP-47 locale for number formatting."},"delimiter":{"type":"string","description":"CSV delimiter character."},"null_representation":{"type":"string","description":"Representation of null values."},"encoding":{"type":"string","description":"Character encoding."},"boolean_format":{"type":"array","description":"Exactly 2 strings — `[true_value, false_value]`.","minItems":2,"maxItems":2,"items":{"type":"string"},"example":["Yes","No"]}}},"DialectUpdateRequest":{"type":"object","description":"Partial update — only supplied keys are patched.","properties":{"name":{"type":"string"},"date_format":{"type":"string"},"number_locale":{"type":"string"},"delimiter":{"type":"string"},"null_representation":{"type":"string"},"encoding":{"type":"string"},"boolean_format":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string"}}}},"MatchingFieldMapping":{"type":"object","description":"Field-mapping entry linking an extracted field to a reference-data column.\nThe shape below is illustrative — the platform accepts any object shape and\napplies matching using the documented keys when present.\n","additionalProperties":true,"properties":{"extracted_field":{"type":"string","description":"Name or id of the extracted field.","example":"vendor_name"},"reference_column":{"type":"string","description":"Reference dataset column to match against.","example":"supplier_legal_name"},"match_type":{"type":"string","example":"exact","enum":["exact","fuzzy","date_range","numeric_range"],"description":"Matching strategy applied to this pair."},"weight":{"type":"number","format":"float","minimum":0,"description":"Relative weight used to aggregate the final confidence.","example":0.6}}},"MatchingConfigResponse":{"type":"object","required":["id","name","reference_data_id","field_mappings","threshold"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Supplier lookup"},"reference_data_id":{"type":"string","format":"uuid","example":"b8c9d0e1-f2a3-4567-bcde-678901234567"},"target_type":{"type":"string","enum":["run","schema","document_filter"],"example":"run"},"target_value":{"type":"object","additionalProperties":true,"description":"Target identifier payload (e.g. run_id, schema_id)."},"field_mappings":{"type":"array","items":{"$ref":"#/components/schemas/MatchingFieldMapping"}},"threshold":{"type":"number","format":"float","minimum":0,"maximum":1,"description":"Auto-accept confidence threshold.","example":0.85},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"runs":{"type":"string"}}}}},"MatchingConfigCreateRequest":{"type":"object","required":["name","reference_data_id","field_mappings"],"properties":{"name":{"type":"string","description":"Human-readable configuration name."},"reference_data_id":{"type":"string","format":"uuid","example":"b8c9d0e1-f2a3-4567-bcde-678901234567","description":"UUID of the reference dataset to match against."},"field_mappings":{"type":"array","minItems":1,"description":"Weighted field-mapping entries. Must be non-empty.","items":{"$ref":"#/components/schemas/MatchingFieldMapping"}},"threshold":{"type":"number","format":"float","minimum":0,"maximum":1,"description":"Auto-accept confidence threshold (defaults to 0.85 server-side)."},"target_type":{"type":"string","enum":["run","schema","document_filter"],"description":"Target scope type (defaults to `run`)."},"target_value":{"type":"object","additionalProperties":true,"description":"Free-form target identifier payload (e.g. `{ run_id }`)."}}},"MatchingConfigUpdateRequest":{"type":"object","description":"Partial update — only provided keys are applied.","properties":{"name":{"type":"string"},"field_mappings":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/MatchingFieldMapping"}},"threshold":{"type":"number","format":"float","minimum":0,"maximum":1},"target_type":{"type":"string","enum":["run","schema","document_filter"]},"target_value":{"type":"object","additionalProperties":true}}},"MatchingRunResponse":{"type":"object","required":["id","matching_config_id","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"matching_config_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["queued","running","completed","failed","cancelled"]},"triggered_by":{"type":"string","example":"manual"},"rows_processed":{"type":["integer","null"]},"rows_matched":{"type":["integer","null"]},"avg_confidence":{"type":["number","null"],"format":"float"},"started_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"error":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"config":{"type":"string"}}}}},"MatchingRunDetailResponse":{"allOf":[{"$ref":"#/components/schemas/MatchingRunResponse"},{"type":"object","properties":{"results":{"type":"array","description":"Up to the 50 highest-confidence match results.","items":{"$ref":"#/components/schemas/MatchResultItem"}}}}]},"MatchResultItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"document_filename":{"type":["string","null"]},"matched_reference_row_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"confidence":{"type":"number","format":"float","minimum":0,"maximum":1},"status":{"type":"string","example":"completed","description":"Per-result status (e.g. `auto_accepted`, `needs_review`, `no_match`)."},"evidence":{"type":"object","additionalProperties":true,"description":"Per-result evidence payload (top candidates, per-field scores)."}}},"RoutingRuleResponse":{"type":"object","required":["id","name","trigger_type","action_type","priority","is_active"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"trigger_type":{"type":"string","example":"document_classified","description":"Trigger kind. Always `document_classified` for rules created via this API."},"conditions":{"type":"object","additionalProperties":true,"description":"Mirror of the internal `trigger_config`."},"action_type":{"type":"string","example":"route_to_schema","description":"Resolved action kind. Defaults to `route_to_schema` when not specified on the request body."},"actions":{"type":"object","additionalProperties":true,"description":"Action payload. May include a `type` key that drives `action_type`."},"priority":{"type":"integer","description":"Lower runs first. Default 100.","example":100},"is_active":{"type":"boolean"},"review_required":{"type":["boolean","null"]},"source_connection_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"RoutingRuleCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Rule name. Required, non-empty."},"conditions":{"type":"object","additionalProperties":true,"description":"Trigger condition payload; stored as `trigger_config` internally."},"actions":{"type":"object","additionalProperties":true,"description":"Action payload. If an `actions.type` key is provided it becomes the\nrule's `action_type` (default: `route_to_schema`).\n","properties":{"type":{"type":"string","description":"Action kind identifier.","example":"route_to_schema"}}},"priority":{"type":"integer","description":"Lower priority runs first. Defaults to 100 server-side."}}},"RoutingRuleUpdateRequest":{"type":"object","description":"Partial update — only supplied keys are patched.","properties":{"name":{"type":"string"},"conditions":{"type":"object","additionalProperties":true},"actions":{"type":"object","additionalProperties":true,"properties":{"type":{"type":"string"}}},"priority":{"type":"integer"},"is_active":{"type":"boolean"}}},"Destination":{"type":"object","required":["id","customer_id","name","type","is_active","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"customer_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","example":"Analytics webhook"},"type":{"type":"string","description":"Connector type discriminant — resolves to a registered connector. Live types are `webhook`, `sftp`, `s3`, `azure_blob`, `google_drive`, `onedrive`, `google_sheets`.","example":"webhook"},"config":{"type":"object","additionalProperties":true,"description":"Connector-specific configuration (e.g. `{ url, headers }` for webhook)."},"has_auth_config":{"type":"boolean","description":"True when connector credentials are stored for this destination. The credential values themselves are never returned."},"has_signing_secret":{"type":"boolean","description":"True when an HMAC signing secret is stored. The secret itself is never returned."},"payload_cap_bytes":{"type":["integer","null"],"description":"Per-destination override of the TransportWrapper payload cap (bytes)."},"is_active":{"type":"boolean"},"last_delivery_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"last_delivery_status":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"CreateDestinationRequest":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","description":"Connector type. Must match a registered connector. Live types are `webhook`, `sftp`, `s3`, `azure_blob`, `google_drive`, `onedrive`, `google_sheets`."},"config":{"type":"object","additionalProperties":true},"auth_config":{"type":["object","null"],"additionalProperties":true},"signing_secret":{"type":["string","null"]},"payload_cap_bytes":{"type":["integer","null"]},"is_active":{"type":"boolean"}}},"UpdateDestinationRequest":{"type":"object","description":"Partial update — every field optional. Only supplied fields are written.","properties":{"name":{"type":"string"},"config":{"type":"object","additionalProperties":true},"auth_config":{"type":["object","null"],"additionalProperties":true},"signing_secret":{"type":["string","null"]},"payload_cap_bytes":{"type":["integer","null"]},"is_active":{"type":"boolean"}}},"TestConnectionResponse":{"type":"object","required":["success","durationMs"],"properties":{"success":{"type":"boolean"},"httpStatus":{"type":["integer","null"]},"durationMs":{"type":"integer"},"message":{"type":["string","null"]}}},"SignalFilter":{"type":"object","required":["event_type"],"description":"Shallow predicate stored on each binding. Slice-1 matching is exact\nevent_type + equality on optional `match` keys; richer predicates are\nintentionally out of scope.\n","properties":{"event_type":{"type":"string","example":"document.extracted"},"match":{"type":["object","null"],"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]},"description":"Optional equality filter on payload keys."}}},"FieldMap":{"type":"object","description":"Declarative projection applied between resolver output and serializer\ninput. Operations run in fixed order: drop → rename → static.\n","properties":{"rules":{"type":"array","items":{"type":"object","required":["source","target"],"properties":{"source":{"type":"string"},"target":{"type":"string"}}}},"static":{"type":"object","additionalProperties":true,"description":"Literal key/value pairs added last — always wins collisions."},"drop":{"type":"array","items":{"type":"string"}}}},"DeliveryPolicy":{"type":"object","description":"Retry / timeout overrides consumed by the TransportWrapper. Slice 1\ndefaults to a 6-attempt ladder with backoff `[5s, 30s, 2min, 10min, 1h]`.\n","properties":{"max_attempts":{"type":"integer","minimum":1},"backoff_schedule":{"type":"array","items":{"type":"integer","description":"Delay in milliseconds"}},"timeout_ms":{"type":"integer"},"rate_limit":{"type":"object","properties":{"ratePerSec":{"type":"number"},"capacity":{"type":"integer"}}}}},"DeliveryBinding":{"type":"object","required":["id","customer_id","name","signal_filter","deliverable_type","destination_id","serializer_format","is_active","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"customer_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"signal_filter":{"$ref":"#/components/schemas/SignalFilter"},"deliverable_type":{"type":"string","description":"Must resolve to a registered deliverable resolver."},"destination_id":{"type":"string","format":"uuid","example":"e1f2a3b4-c5d6-7890-efab-901234567890"},"field_map":{"$ref":"#/components/schemas/FieldMap"},"serializer_format":{"type":"string","description":"Must resolve to a registered serializer (json, ndjson, csv, csv_file, xlsx, rows, graph, raw, md, txt)."},"serializer_config":{"type":"object","additionalProperties":true},"resolver_config":{"type":["object","null"],"additionalProperties":true,"description":"Per-binding resolver options threaded into the deliverable resolver. First consumer: `null_handling` on the `pipeline.capture` deliverable — `always_null` (default: every declared schema field present, missing values as null), `omit_absent` (valued fields only), or `distinguish` (null = deliberately cleared by resolution; never-captured keys omitted). The sparse modes require a json or ndjson serializer (compatibility validated on create/update).\n"},"delivery_policy":{"$ref":"#/components/schemas/DeliveryPolicy"},"is_active":{"type":"boolean"},"last_status":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"CreateBindingRequest":{"type":"object","required":["name","signal_filter","deliverable_type","destination_id","serializer_format"],"properties":{"name":{"type":"string"},"signal_filter":{"$ref":"#/components/schemas/SignalFilter"},"deliverable_type":{"type":"string"},"destination_id":{"type":"string","format":"uuid","example":"e1f2a3b4-c5d6-7890-efab-901234567890"},"field_map":{"$ref":"#/components/schemas/FieldMap"},"serializer_format":{"type":"string"},"serializer_config":{"type":"object","additionalProperties":true},"resolver_config":{"type":"object","additionalProperties":true,"description":"Per-binding resolver options — e.g. `{\"null_handling\": \"distinguish\"}` on a `pipeline.capture` binding. Sparse modes (`omit_absent`, `distinguish`) require a json/ndjson serializer (400 otherwise).\n"},"delivery_policy":{"$ref":"#/components/schemas/DeliveryPolicy"},"is_active":{"type":"boolean"}}},"UpdateBindingRequest":{"type":"object","description":"Partial update — every field optional.","properties":{"name":{"type":"string"},"signal_filter":{"$ref":"#/components/schemas/SignalFilter"},"deliverable_type":{"type":"string"},"destination_id":{"type":"string","format":"uuid","example":"e1f2a3b4-c5d6-7890-efab-901234567890"},"field_map":{"$ref":"#/components/schemas/FieldMap"},"serializer_format":{"type":"string"},"serializer_config":{"type":"object","additionalProperties":true},"resolver_config":{"type":"object","additionalProperties":true,"description":"Per-binding resolver options — e.g. `{\"null_handling\": \"distinguish\"}` on a `pipeline.capture` binding. Sparse modes (`omit_absent`, `distinguish`) require a json/ndjson serializer (400 otherwise).\n"},"delivery_policy":{"$ref":"#/components/schemas/DeliveryPolicy"},"is_active":{"type":"boolean"}}},"DeliveryItem":{"type":"object","required":["id","customer_id","binding_id","event_id","idempotency_key","status","attempt","created_at"],"description":"One row per delivery attempt.","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"customer_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"binding_id":{"type":"string","format":"uuid","example":"d0e1f2a3-b4c5-6789-defa-890123456789"},"event_id":{"type":"string","description":"BIGSERIAL id of the originating outbox row (string-encoded)."},"idempotency_key":{"type":"string","description":"SHA-256-derived key passed on the wire. Stable within an attempt."},"status":{"type":"string","example":"completed","enum":["in_flight","succeeded","failed"]},"attempt":{"type":"integer","minimum":1},"http_status":{"type":["integer","null"]},"error_code":{"type":["string","null"]},"error_message":{"type":["string","null"]},"request_body":{"type":["string","null"]},"response_body":{"type":["string","null"]},"duration_ms":{"type":["integer","null"]},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"DeliveryDeadLetter":{"type":"object","required":["id","customer_id","binding_id","event_id","error_code","attempts","created_at"],"description":"Terminal failure row written after retry exhaustion.","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"customer_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"binding_id":{"type":"string","format":"uuid","example":"d0e1f2a3-b4c5-6789-defa-890123456789"},"event_id":{"type":"string","description":"BIGSERIAL outbox id (string)."},"last_item_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"FK to the last DeliveryItem attempt (nullable — `ON DELETE SET NULL`)."},"error_code":{"type":"string","example":"delivery_timeout"},"error_message":{"type":["string","null"]},"attempts":{"type":"integer"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"DeliveryEvent":{"type":"object","required":["id","customer_id","event_type","payload","created_at","processing_attempts"],"description":"Outbox record (not the typed producer DTO). Represents a single row in\nthe `delivery_events` table. `event_type` is a string discriminant —\nsee `/v1/delivery/catalog/signals` for the exhaustive list.\n","properties":{"id":{"type":"string","description":"BIGSERIAL (string-encoded to avoid JS number precision loss)."},"customer_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"event_type":{"type":"string"},"payload":{"type":"object","additionalProperties":true,"description":"Entity IDs only — deliverable resolvers load content at delivery time."},"dedup_key":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"processed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"processing_attempts":{"type":"integer"},"processing_status":{"type":["string","null"],"enum":["enqueued","no-subscribers","failed"]},"error":{"type":["string","null"]}}},"DeliverableCatalogEntry":{"type":"object","required":["type","compatible_signals","shape"],"properties":{"type":{"type":"string"},"label":{"type":"string","example":"Customer Onboarding","description":"Short human-readable label, e.g. \"Document markdown content\". Falls back to `type` if unknown."},"description":{"type":"string","description":"One-line explanation of what the resolver emits."},"compatible_signals":{"type":"array","items":{"type":"string"},"description":"Empty for slice-2 stub resolvers — they appear in the list but never route."},"shape":{"oneOf":[{"type":"object","required":["kind","is_collection","columns"],"properties":{"kind":{"type":"string","enum":["record"]},"is_collection":{"type":"boolean"},"columns":{"type":"array","items":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","enum":["string","number","boolean","date","datetime","json"]},"nullable":{"type":"boolean"}}}}}},{"type":"object","required":["kind","mime"],"properties":{"kind":{"type":"string","enum":["blob"]},"mime":{"type":"string"}}},{"type":"object","required":["kind","node_types","edge_types"],"properties":{"kind":{"type":"string","enum":["graph"]},"node_types":{"type":"array","items":{"type":"string"}},"edge_types":{"type":"array","items":{"type":"string"}}}},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["envelope"]}}}]}}},"SerializerCatalogEntry":{"type":"object","required":["format","supports_kinds"],"properties":{"format":{"type":"string","enum":["json","ndjson","csv","csv_file","xlsx","rows","graph","raw","md","txt"],"description":"Registered serializer format. `csv_file` always emits a complete\nfile with header + text/csv mime + .csv filename hint. `md`\nrenders record collections as markdown tables, blobs as\npassthrough, envelopes as key/value lists. `txt` is the universal\nfallback and accepts every deliverable shape.\n"},"supports_kinds":{"type":"array","description":"Deliverable shape kinds this serializer accepts. Probed against a\nminimal synthetic shape per kind — always reflects the current\nimplementation.\n","items":{"type":"string","enum":["record","blob","graph","envelope"]}}}},"ConnectorCapabilities":{"type":"object","required":["supported_serializers","supported_deliverable_kinds","auth_types","delivery_semantics"],"properties":{"supported_serializers":{"type":"array","items":{"type":"string"}},"supported_deliverable_kinds":{"type":"array","items":{"type":"string","enum":["record","blob","graph","envelope"]}},"max_payload_bytes":{"type":"integer","description":"Connector's own cap. TransportWrapper enforces the smaller of this and the per-destination override."},"auth_types":{"type":"array","items":{"type":"string"}},"delivery_semantics":{"type":"string","enum":["record","batch","file"]},"default_rate_limit":{"type":"object","properties":{"ratePerSec":{"type":"number"},"capacity":{"type":"integer"}}}}},"BindingPreviewResponse":{"type":"object","required":["available","sample_mode","signal","resolver","projected","serialized","wire_preview"],"description":"Output of `POST /v1/delivery/bindings/{id}/preview`. When the resolver\nsuccessfully loads a synthetic entity the full pipeline (`resolve →\nprojectFieldMap → serialize`) runs and `sample_mode=\"real\"`. When the\nresolver throws (commonly `EntityMissingError` on a synthetic id) the\nservice falls back to `sample_mode=\"structural\"` and returns only the\nresolver's declared shape — `projected`, `serialized`, and\n`wire_preview` are `null` in that case.\n","properties":{"available":{"type":"boolean","enum":[true],"description":"Always `true`. Present so future gated-preview responses can set `available=false` without breaking consumers."},"sample_mode":{"type":"string","enum":["real","structural"],"description":"`real` — the resolver loaded a synthetic entity and every pipeline\nstage ran. `structural` — the resolver threw (typically\n`entity_missing`) so only the declared shape is returned.\n"},"signal":{"type":"object","description":"Synthetic {DeliveryEvent} built from `signal_filter.event_type`\nwith placeholder entity ids (`<preview-{field}>`) and\n`signal_filter.match` overlaid so the synthetic signal passes its\nown filter. `customer_id` always matches the authenticated tenant.\n","additionalProperties":true},"resolver":{"type":"object","required":["type","shape"],"properties":{"type":{"type":"string","description":"Registered deliverable-resolver type (e.g. `markdown`, `run.dataspace.outcome`)."},"shape":{"description":"The resolver's declared `DeliverableShape`.","oneOf":[{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["record"]},"is_collection":{"type":"boolean"},"columns":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"nullable":{"type":"boolean"}}}}}},{"type":"object","required":["kind","mime"],"properties":{"kind":{"type":"string","enum":["blob"]},"mime":{"type":"string"}}},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["graph"]},"node_types":{"type":"array","items":{"type":"string"}},"edge_types":{"type":"array","items":{"type":"string"}}}},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["envelope"]}}}]}}},"projected":{"type":["object","null"],"description":"Resolver output after `projectFieldMap(binding.field_map)`. `null` when `sample_mode='structural'`."},"serialized":{"type":["object","null"],"description":"Serializer output (`kind: 'bytes' | 'rows' | 'graph' | 'object'` + per-kind fields). `null` when `sample_mode='structural'`."},"wire_preview":{"description":"Static projection of how the wire-level payload would look at delivery time. Never sent to the connector. `null` when `sample_mode=\"structural\"`.","type":["object","null"],"required":["body_preview","size_bytes","headers_preview"],"properties":{"body_preview":{"type":"string","description":"UTF-8 body stringification, truncated to the first 8 KiB with an ellipsis if longer."},"mime":{"type":"string","description":"Inferred content type of the body."},"size_bytes":{"type":"integer","description":"Full body size in bytes (the serializer's real output, not the truncated preview)."},"headers_preview":{"type":"object","additionalProperties":{"type":"string"},"description":"The `X-Talonic-*` headers that would ship on the wire. The\n`X-Talonic-Signature` header, when present, is rendered as\n`t=<preview>,v1=<preview>` — the preview never computes a real\nHMAC so the signing secret is not exercised.\n"}}},"structural_sample":{"type":"object","description":"Only present when `sample_mode=\"structural\"`. Mirrors `resolver.shape` for convenience.","properties":{"deliverable_type":{"type":"string"},"shape":{"description":"Same `DeliverableShape` union as `resolver.shape`."}}},"fallback_reason":{"type":"string","description":"Only present when `sample_mode=\"structural\"`. Human-readable reason the resolver could not produce a real sample."}}},"FilenameTemplateDescription":{"type":"string","description":"Tokens replaced inside filename / object-key templates:\n`{binding_id}`, `{event_id}`, `{customer_id}`, `{idempotency_key}`,\n`{attempt}`, `{timestamp_iso}`, `{date}` (UTC YYYY-MM-DD), and\n`{deliverable_type}`. Unknown tokens pass through verbatim so typos\nsurface on first delivery. Path-traversal segments (`..`) are stripped.\nSee `packages/api/src/delivery/connectors/common/filename-template.ts`.\n"},"SftpDestinationConfig":{"type":"object","required":["host","username","remote_path"],"description":"Destination `config` shape when `type=\"sftp\"`. Pairs with an\n`auth_config` of type `password` or `private_key`.\n","properties":{"host":{"type":"string","description":"SFTP server hostname."},"port":{"type":"integer","default":22,"description":"SSH port. Default 22."},"username":{"type":"string"},"remote_path":{"type":"string","description":"Absolute remote directory that uploads land in."},"filename_template":{"type":"string","description":"Optional filename template. Default `delivery_{event_id}`. See\n`FilenameTemplateDescription`. If the rendered filename already\nends with an extension the operator value wins; otherwise the\npayload's derived extension is appended.\n","default":"delivery_{event_id}"},"timeout_ms":{"type":"integer","default":30000,"description":"Connect / operation timeout in milliseconds."}}},"S3DestinationConfig":{"type":"object","required":["bucket","region"],"description":"Destination `config` shape when `type=\"s3\"`. Pairs with an\n`auth_config` of type `access_key`.\n","properties":{"bucket":{"type":"string"},"region":{"type":"string","description":"AWS region, e.g. `us-east-1`."},"key_template":{"type":"string","default":"delivery/{date}/{event_id}","description":"Optional S3 key template. Default `delivery/{date}/{event_id}`.\nSee `FilenameTemplateDescription`. Leading slashes are trimmed;\nan extension is appended if the template does not already end in\none.\n"},"public_read":{"type":"boolean","description":"When true, sets `ACL=public-read` on the upload."}}},"AzureBlobDestinationConfig":{"type":"object","required":["account_name","container"],"description":"Destination `config` shape when `type=\"azure_blob\"`. Pairs with an\n`auth_config` of type `connection_string` or `account_key`. With\n`account_key` the public `https://{account_name}.blob.core.windows.net`\nURL is built from `account_name`.\n","properties":{"account_name":{"type":"string"},"container":{"type":"string"},"blob_key_template":{"type":"string","default":"delivery/{date}/{event_id}","description":"Optional blob-key template. Default `delivery/{date}/{event_id}`.\nSee `FilenameTemplateDescription`. Leading slashes are trimmed;\nan extension is appended if the template does not already end in\none.\n"}}},"DestinationAuthConfig":{"description":"Destination credential payload. Write-only — server responses expose\nonly `has_auth_config: boolean`, never the credential values\nthemselves. The `type` field discriminates the concrete shape; valid\nvalues depend on the parent destination's connector `type` (see\n`/v1/delivery/catalog/connectors` for each connector's `auth_types`).\n","oneOf":[{"$ref":"#/components/schemas/AuthConfigPassword"},{"$ref":"#/components/schemas/AuthConfigPrivateKey"},{"$ref":"#/components/schemas/AuthConfigAccessKey"},{"$ref":"#/components/schemas/AuthConfigConnectionString"},{"$ref":"#/components/schemas/AuthConfigAccountKey"},{"$ref":"#/components/schemas/AuthConfigBearer"},{"$ref":"#/components/schemas/AuthConfigBasic"},{"$ref":"#/components/schemas/AuthConfigApiKey"},{"$ref":"#/components/schemas/AuthConfigNone"}],"discriminator":{"propertyName":"type","mapping":{"password":"#/components/schemas/AuthConfigPassword","private_key":"#/components/schemas/AuthConfigPrivateKey","access_key":"#/components/schemas/AuthConfigAccessKey","connection_string":"#/components/schemas/AuthConfigConnectionString","account_key":"#/components/schemas/AuthConfigAccountKey","bearer":"#/components/schemas/AuthConfigBearer","basic":"#/components/schemas/AuthConfigBasic","api_key":"#/components/schemas/AuthConfigApiKey","none":"#/components/schemas/AuthConfigNone"}}},"AuthConfigPassword":{"type":"object","required":["type","password"],"description":"SFTP password auth.","properties":{"type":{"type":"string","enum":["password"]},"password":{"type":"string"}}},"AuthConfigPrivateKey":{"type":"object","required":["type","private_key"],"description":"SFTP key-based auth. `passphrase` is optional.","properties":{"type":{"type":"string","enum":["private_key"]},"private_key":{"type":"string"},"passphrase":{"type":["string","null"]}}},"AuthConfigAccessKey":{"type":"object","required":["type","access_key_id","secret_access_key"],"description":"S3 IAM access-key pair. `session_token` is optional (STS).","properties":{"type":{"type":"string","enum":["access_key"]},"access_key_id":{"type":"string"},"secret_access_key":{"type":"string"},"session_token":{"type":["string","null"]}}},"AuthConfigConnectionString":{"type":"object","required":["type","connection_string"],"description":"Azure Blob Storage connection string auth.","properties":{"type":{"type":"string","enum":["connection_string"]},"connection_string":{"type":"string"}}},"AuthConfigAccountKey":{"type":"object","required":["type","account_key"],"description":"Azure Blob Storage shared-key auth (`account_name` lives in the destination `config`).","properties":{"type":{"type":"string","enum":["account_key"]},"account_key":{"type":"string"}}},"AuthConfigBearer":{"type":"object","required":["type","token"],"description":"Webhook Bearer-token auth. Emits `Authorization: Bearer {token}`.","properties":{"type":{"type":"string","enum":["bearer"]},"token":{"type":"string"}}},"AuthConfigBasic":{"type":"object","required":["type"],"description":"Webhook HTTP Basic auth. Emits `Authorization: Basic base64(username:password)`.","properties":{"type":{"type":"string","enum":["basic"]},"username":{"type":"string"},"password":{"type":"string"}}},"AuthConfigApiKey":{"type":"object","required":["type","api_key"],"description":"Webhook API-key auth. Header name defaults to `X-API-Key`.","properties":{"type":{"type":"string","enum":["api_key"]},"api_key":{"type":"string"},"header_name":{"type":"string","default":"X-API-Key"}}},"AuthConfigNone":{"type":"object","required":["type"],"description":"Explicit \"no authentication\" marker.","properties":{"type":{"type":"string","enum":["none"]}}},"FilterCondition":{"type":"object","required":["fieldId","operator"],"properties":{"fieldId":{"type":"string","description":"User-schema field id or materialised column identifier.","example":"amount"},"operator":{"type":"string","description":"Operator identifier (free-form — e.g. `eq`, `contains`, `between`).","example":"between"},"value":{"description":"Primary value. Shape depends on the operator."},"valueTo":{"description":"Upper bound for range operators such as `between`."}}},"FilterSort":{"type":"object","required":["fieldId","direction"],"properties":{"fieldId":{"type":"string","description":"Field id to sort by."},"direction":{"type":"string","enum":["asc","desc"],"description":"Sort direction."}}},"FilterDocumentsRequest":{"type":"object","properties":{"source_id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","description":"Optional source connection UUID to narrow the result set."},"conditions":{"type":"array","description":"Ordered list of filter conditions, ANDed together.","items":{"$ref":"#/components/schemas/FilterCondition"}},"search":{"type":"string","description":"Optional free-text search applied alongside the structured conditions."},"sort":{"$ref":"#/components/schemas/FilterSort"},"page":{"type":"integer","minimum":1,"description":"1-based page number. Default 1."},"limit":{"type":"integer","minimum":1,"description":"Page size. Server clamps to a maximum of 500. Default 50."}}},"FilterDocumentsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","description":"Matching document rows.","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer","description":"Total number of matching documents.","example":142},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"SearchResponse":{"type":"object","description":"Multi-collection search result. Empty arrays are returned for any\ncollection with no matches; empty queries return all empty arrays.\n","properties":{"documents":{"type":"array","items":{"type":"object","additionalProperties":true}},"fieldMatches":{"type":"array","items":{"type":"object","additionalProperties":true}},"sources":{"type":"array","items":{"type":"object","additionalProperties":true}},"schemas":{"type":"array","items":{"type":"object","additionalProperties":true}},"fields":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"ReviewRecordItem":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"run_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":["string","null"],"format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"schema_id":{"type":["string","null"],"format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"status":{"type":"string","example":"completed","description":"Review status (e.g. `pending`, `approved`, `rejected`)."},"overall_confidence":{"type":["number","null"],"format":"float","minimum":0,"maximum":1},"assigned_to":{"type":["string","null"]},"reviewed_by":{"type":["string","null"]},"reviewed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"action":{"type":"string"}}}}},"ReviewRecordDetail":{"allOf":[{"$ref":"#/components/schemas/ReviewRecordItem"},{"type":"object","properties":{"field_decisions":{"type":"object","additionalProperties":true,"description":"Per-field decisions persisted on the record."},"low_confidence_fields":{"type":"array","items":{"type":"string"},"description":"Names of fields that fell below the review confidence threshold."},"review_comment":{"type":["string","null"]}}}]},"ReviewActionRequest":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["approve","reject"],"description":"Decision applied to the record."},"reason":{"type":"string","description":"Optional reviewer note stored on the record."}}},"ReviewBatchActionRequest":{"type":"object","required":["ids","action"],"properties":{"ids":{"type":"array","minItems":1,"description":"Non-empty list of validation-record UUIDs.","items":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}},"action":{"type":"string","enum":["approve","reject"],"description":"Decision applied to every record in `ids`."}}},"ReviewBatchActionResponse":{"type":"object","required":["processed","failed","results"],"properties":{"processed":{"type":"integer","description":"Number of records successfully updated."},"failed":{"type":"integer","description":"Number of records that could not be updated (not found, not owned)."},"results":{"type":"array","items":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","description":"Per-record outcome (`approved`, `rejected`, or `error`)."},"error":{"type":"string","description":"Present on `status: error` rows (e.g. `not_found`)."}}}}}},"GroundTruthDatasetResponse":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"description":{"type":["string","null"]},"user_schema_id":{"type":["string","null"],"format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"document_count":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"GroundTruthDatasetDetailResponse":{"allOf":[{"$ref":"#/components/schemas/GroundTruthDatasetResponse"},{"type":"object","properties":{"samples":{"type":"array","items":{"$ref":"#/components/schemas/GroundTruthEntryItem"}}}}]},"GroundTruthDatasetCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Dataset name. Required, non-empty."},"description":{"type":"string","description":"Optional free-text description."}}},"GroundTruthEntryItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":["string","null"],"format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"expected_data":{"type":"object","additionalProperties":true,"description":"The known-correct field values for this document."},"notes":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"BenchmarkResponse":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":["string","null"]},"dataset_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"user_schema_id":{"type":["string","null"],"format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"status":{"type":"string","example":"completed","description":"Benchmark run status."},"accuracy_overall":{"type":["number","null"],"format":"float","minimum":0,"maximum":1},"accuracy_by_field":{"type":["object","null"],"additionalProperties":{"type":"number","format":"float"}},"documents_processed":{"type":["integer","null"]},"documents_total":{"type":["integer","null"]},"duration_ms":{"type":["integer","null"]},"accuracy_delta":{"type":["number","null"],"format":"float","description":"Change in overall accuracy vs the compared run."},"compared_to_run_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"results":{"type":"string"}}}}},"BenchmarkDetailResponse":{"allOf":[{"$ref":"#/components/schemas/BenchmarkResponse"},{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/BenchmarkResultItem"}}}}]},"BenchmarkResultItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":["string","null"],"format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"ground_truth_entry_id":{"type":["string","null"],"format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"accuracy":{"type":["number","null"],"format":"float","minimum":0,"maximum":1},"field_results":{"type":"object","additionalProperties":true,"description":"Per-field pass/fail results for this document."},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"BatchResponse":{"type":"object","required":["id","status","provider","item_count","succeeded_count","errored_count","expired_count","created_at","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","example":"completed","enum":["accumulating","submitted","in_progress","completed","failed","expired"]},"provider":{"type":"string","example":"anthropic","enum":["anthropic","bedrock"]},"item_count":{"type":"integer"},"succeeded_count":{"type":"integer"},"errored_count":{"type":"integer"},"expired_count":{"type":"integer"},"submitted_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"error_message":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"BatchDetailResponse":{"allOf":[{"$ref":"#/components/schemas/BatchResponse"},{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","document_id","status","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"document_filename":{"type":["string","null"]},"custom_id":{"type":["string","null"]},"status":{"type":"string","example":"completed"},"error_message":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"processed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}}}}]},"CaseListItem":{"type":"object","required":["id","case_key","label","document_count","links"],"properties":{"id":{"type":"string","format":"uuid","description":"Case UUID — the stable resource id used in API paths."},"case_key":{"type":"string","example":"8c1ca050535e3ea3","pattern":"^[a-fA-F0-9]{8,64}$","description":"Content-derived key (hex hash of the member document set); distinct from `id`."},"label":{"type":["string","null"]},"document_count":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"CaseDetailResponse":{"type":"object","required":["id","case_key","documents","anomaly_count","links"],"properties":{"id":{"type":"string","format":"uuid","description":"Case UUID — the stable resource id used in API paths."},"case_key":{"type":"string","example":"8c1ca050535e3ea3","description":"Content-derived key (hex hash of the member document set); distinct from `id`."},"label":{"type":["string","null"]},"narrative":{"type":["string","null"]},"documents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"filename":{"type":"string","example":"invoice-042.pdf"},"document_type":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}},"anomaly_count":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"documents":{"type":"string"}}}}},"DocumentTypeResponse":{"type":"object","required":["id","name","document_count","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"ontology_type_id":{"type":["string","null"]},"category_id":{"type":["string","null"]},"document_count":{"type":"integer"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"FieldResponse":{"type":"object","required":["id","canonical_name","display_name","data_type","tier","occurrence_count","created_at","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"canonical_name":{"type":"string","example":"invoice_number"},"display_name":{"type":"string","description":"Human-readable label, always present. A stored display name wins; otherwise it is derived from `canonical_name`, e.g. `invoice_number` → `Invoice Number`.","example":"Invoice Number"},"data_type":{"type":"string","example":"string"},"tier":{"type":"integer"},"cluster_name":{"type":["string","null"]},"occurrence_count":{"type":"integer"},"master_instruction":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"similar":{"type":"string"}}}}},"FieldDetailResponse":{"allOf":[{"$ref":"#/components/schemas/FieldResponse"},{"type":"object","properties":{"recent_occurrences":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"document_filename":{"type":["string","null"]},"raw_field_name":{"type":["string","null"]},"value":{"description":"Raw extracted value for this occurrence."},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}}}}]},"FieldHarmonizationItem":{"type":"object","required":["id","canonical_name","data_type","tier","occurrence_count","schema_count","is_universal","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"canonical_name":{"type":"string","example":"invoice_number"},"display_name":{"type":["string","null"]},"data_type":{"type":"string","example":"string"},"tier":{"type":"integer"},"occurrence_count":{"type":"integer"},"schema_count":{"type":"integer"},"document_type_names":{"type":"array","items":{"type":["string","null"]}},"is_universal":{"type":"boolean"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"ReferenceDataResponse":{"type":"object","required":["id","name","source_type","row_count","columns","created_at","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"source_type":{"type":"string","description":"e.g. `csv`, `xlsx`."},"row_count":{"type":"integer"},"columns":{"description":"Column schema for the dataset. Shape follows the uploaded file's header row."},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"rows":{"type":"string"}}}}},"UsageResponse":{"type":"object","required":["period","totals","breakdown","links"],"properties":{"period":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"to":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"totals":{"type":"object","required":["input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls"],"properties":{"input_tokens":{"type":"integer","description":"Uncached input tokens (cached tokens are reported separately)."},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer","description":"Tokens served from the provider's prompt cache."},"cache_creation_tokens":{"type":"integer","description":"Tokens written to the provider's prompt cache (Anthropic only; 0 for other providers)."},"calls":{"type":"integer"}}},"breakdown":{"type":"array","items":{"type":"object","required":["operation_type","input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls"],"properties":{"operation_type":{"type":"string"},"model":{"type":"string","description":"Omitted for organizations without the \"Cost control endpoints\" approval (see `cost_fields` on the parent response)."},"input_tokens":{"type":"integer","description":"Uncached input tokens (cached tokens are reported separately)."},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer","description":"Tokens served from the provider's prompt cache."},"cache_creation_tokens":{"type":"integer","description":"Tokens written to the provider's prompt cache (Anthropic only; 0 for other providers)."},"calls":{"type":"integer"}}}},"cost_fields":{"type":"string","enum":["redacted"],"description":"Present and set to `\"redacted\"` only for organizations without the \"Cost control endpoints\" approval — signals that `breakdown[].model` has been omitted. Absent for approved organizations."},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"DocumentUsageResponse":{"type":"object","required":["document_id","totals","entries","links"],"properties":{"document_id":{"type":"string","format":"uuid","example":"f0e1d2c3-b4a5-9687-8765-432109876543"},"totals":{"type":"object","required":["input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls"],"properties":{"input_tokens":{"type":"integer","description":"Uncached input tokens (cached tokens are reported separately)."},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer","description":"Tokens served from the provider's prompt cache."},"cache_creation_tokens":{"type":"integer","description":"Tokens written to the provider's prompt cache (Anthropic only; 0 for other providers)."},"cost_estimate_usd":{"type":"number","format":"float","description":"Omitted for organizations without the \"Cost control endpoints\" approval (see `cost_fields` on the parent response)."},"calls":{"type":"integer"}}},"entries":{"type":"array","items":{"type":"object","required":["id","operation_type","input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","created_at"],"properties":{"id":{"type":"string"},"operation_type":{"type":"string"},"model":{"type":"string","description":"Omitted for organizations without the \"Cost control endpoints\" approval."},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":["integer","null"],"description":"Tokens served from the provider's prompt cache."},"cache_creation_tokens":{"type":"integer","description":"Tokens written to the provider's prompt cache (Anthropic only; 0 for other providers)."},"cost_estimate_usd":{"type":"number","format":"float","description":"Omitted for organizations without the \"Cost control endpoints\" approval."},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}}},"cost_fields":{"type":"string","enum":["redacted"],"description":"Present and set to `\"redacted\"` only for organizations without the \"Cost control endpoints\" approval — signals that `model` and all `cost_estimate_usd` fields have been omitted. Absent for approved organizations."},"links":{"type":"object","properties":{"self":{"type":"string"},"document":{"type":"string"}}}}},"PipelineUsageResponse":{"type":"object","required":["pipeline_id","period","scope","scope_note","totals","breakdown","documents","links"],"properties":{"pipeline_id":{"type":"string","format":"uuid","example":"b3c4d5e6-f7a8-9012-bcde-f34567890123"},"period":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"to":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"scope":{"type":"string","enum":["pipeline_calls_only"],"description":"Fixed code identifying the attribution rule applied to this response."},"scope_note":{"type":"string","description":"Human-readable statement of what this response covers — pipeline-stamped calls only. The ingest OCR leg (shared across runs) is excluded by design.","example":"Calls stamped with this pipeline id in call metadata. The shared ingest OCR leg is excluded."},"totals":{"type":"object","required":["input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls","cost_estimate_usd"],"properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer"},"cache_creation_tokens":{"type":"integer","description":"Cache-write tokens, billed at 1.25× the fresh input rate."},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}},"breakdown":{"type":"array","items":{"type":"object","required":["operation_type","model","input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls","cost_estimate_usd"],"properties":{"operation_type":{"type":"string"},"model":{"type":"string"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer"},"cache_creation_tokens":{"type":"integer"},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}}},"documents":{"type":"array","description":"Per-document rollup of the same pipeline-stamped calls.","items":{"type":"object","required":["document_id","filename","input_tokens","output_tokens","calls","cost_estimate_usd"],"properties":{"document_id":{"type":"string","format":"uuid"},"filename":{"type":["string","null"],"description":"The document's filename, or null if it could not be resolved."},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}}},"links":{"type":"object","properties":{"self":{"type":"string"},"pipeline":{"type":"string"}}}}},"RunUsageResponse":{"type":"object","required":["run_id","pipeline_id","period","scope","scope_note","totals","breakdown","documents","links"],"properties":{"run_id":{"type":"string","format":"uuid","example":"c4d5e6f7-a8b9-0123-cdef-456789012345"},"pipeline_id":{"type":["string","null"],"format":"uuid","description":"Null while the run is still ingesting or if it failed before a pipeline was created — the response still returns `200` with zero totals in that case, never `404`."},"period":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"to":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"scope":{"type":"string","enum":["run_attributed_calls"],"description":"Fixed code identifying the attribution rule applied to this response."},"scope_note":{"type":"string","description":"Human-readable statement of attribution: pipeline-stamped calls, limited to the run's own documents and active time window. Documented as approximate under shared-pipeline concurrency (append mode / several runs on one pipeline); a document skipped by dedup or extraction-reuse legitimately reports zeros. Explains the zero-totals case (still-ingesting/pre-pipeline run, or a legacy run predating per-request document tracking) when applicable.","example":"Calls stamped with the run's pipeline id, restricted to the run's own documents and lifetime. Approximate under shared-pipeline concurrency (append mode); the shared ingest OCR leg is excluded."},"totals":{"type":"object","required":["input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls","cost_estimate_usd"],"properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer"},"cache_creation_tokens":{"type":"integer","description":"Cache-write tokens, billed at 1.25× the fresh input rate."},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}},"breakdown":{"type":"array","items":{"type":"object","required":["operation_type","model","input_tokens","output_tokens","cache_read_tokens","cache_creation_tokens","calls","cost_estimate_usd"],"properties":{"operation_type":{"type":"string"},"model":{"type":"string"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_read_tokens":{"type":"integer"},"cache_creation_tokens":{"type":"integer"},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}}},"documents":{"type":"array","description":"Per-document rollup, one row per entry in the run's own `documents[]` echo. A document skipped by dedup or extraction-reuse legitimately appears with all-zero counts.","items":{"type":"object","required":["document_id","input_tokens","output_tokens","calls","cost_estimate_usd"],"properties":{"document_id":{"type":"string","format":"uuid"},"filename":{"type":["string","null"],"description":"The document's filename. Omitted entirely (not merely null) on the zero-totals placeholder rows returned for a still-ingesting/pre-pipeline or legacy echo-less run."},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"calls":{"type":"integer"},"cost_estimate_usd":{"type":"number","format":"float"}}}},"links":{"type":"object","properties":{"self":{"type":"string"},"run":{"type":"string"}}}}},"ResultsColumn":{"type":"object","required":["field_key","display_name","data_type"],"properties":{"field_key":{"type":"string","description":"Stable machine key. Rows in `data` are keyed by this, never by the label."},"display_name":{"type":"string","description":"Human-readable column label, always present. A stored display name (a Spec field's title or a minted registry display name) wins; otherwise it is derived from `field_key`, e.g. `charge_type` → `Charge Type`."},"data_type":{"type":"string"}}},"ResultsCell":{"type":"object","required":["value","status","confidence","source","document_id","filename"],"properties":{"value":{"nullable":true,"description":"The cell's coalesced value; null for a held (pending_approval) cell. A structured-subschema cell is emitted TYPED — each object's subfields projected to their declared subfield data_type, matching json/ndjson delivery and the run.completed webhook. A number/boolean subfield parse-miss serializes null (no string wire form); an enum/date miss and any nested array/object subfield value pass through raw."},"status":{"type":"string","example":"filled"},"confidence":{"type":["number","null"],"format":"float"},"source":{"type":["string","null"],"description":"Opaque-but-stable cell-source vocabulary (e.g. llm_extraction, field_registry, pipeline_resolution, pipeline_assembly, pipeline_assembly_anchor, human_review, auto_adjudication, review_gate). New values may appear over time; existing values do not rename."},"document_id":{"type":["string","null"],"format":"uuid","description":"On a composed row, the cell's real source document — may differ from the record's anchor document_id."},"filename":{"type":["string","null"]}}},"ResultsProvenance":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["span","assembly_override","auto_adjudication","human","derived","legacy"],"description":"legacy covers the internal legacy_unvalidated kind plus any unparseable/unknown envelope."},"text":{"type":["string","null"],"description":"The winning value's genesis span text. Absent for a held cell (kind-only redaction) and never a displaced/previous value even when unheld."},"derived_reason":{"type":"string","description":"Open enum; documented values today include inferred_no_span, source_text_unlocated, inferred_absence, customer_injected, resolved_default. Consumers must tolerate new values."},"source_document_id":{"type":["string","null"],"format":"uuid"},"page_index":{"type":["integer","null"]}}},"ResultsAuditVersion":{"type":"object","required":["version","value","status","source","confidence","created_at"],"properties":{"version":{"type":["integer","null"]},"value":{"nullable":true,"description":"Redacted (null) for EVERY version in a field's trail when that field's LATEST version is held — the hold mechanism copies the held value forward, making the prior version an equal leak. Serializes normally once the hold resolves. This audit trail is the deliberate RAW history view — structured-subschema subfields are NOT type-projected here (unlike fields and cells[].value)."},"status":{"type":["string","null"]},"source":{"type":["string","null"]},"confidence":{"type":["number","null"],"format":"float"},"created_at":{"type":["string","null"],"format":"date-time"}}},"ResultsRecord":{"type":"object","required":["document_id","filename","run_id","pipeline_id","record_id","status","completed_at","fields"],"properties":{"document_id":{"type":["string","null"],"format":"uuid","description":"Null only for an anchor-less composed row (the product record's anchor could not be resolved)."},"filename":{"type":["string","null"]},"run_id":{"type":["string","null"],"format":"uuid","description":"The attributed /v1/run request id (echo containment, newest-for-pipeline fallback restricted to echo-less legacy rows); null for a UI or POST /v1/pipelines run."},"pipeline_id":{"type":"string","format":"uuid"},"record_id":{"type":"string","description":"The row's record identity — the pipeline_document id on the main set, the product record id on the composed set."},"status":{"type":"string","enum":["complete","partial","error","processing"],"description":"Folded from ~10 internal pipeline_documents states. Deliberately keeps partial (unlike GET /v1/run/{id}'s documents[].status, which folds partial into completed)."},"completed_at":{"type":["string","null"],"format":"date-time","description":"COALESCE of the last per-phase completion stamp. Tracks document PROCESSING completion, not value change — a review promotion or assembly recompose never advances it, and a phase rerun nulls it until the document re-processes."},"metadata":{"type":"object","additionalProperties":true,"description":"Caller tags; present only when set."},"batch_id":{"type":"string","description":"Present only when set."},"fields":{"type":"object","additionalProperties":true,"description":"field_key -> clean value. Held (pending_approval) fields serialize null; demoted fields and __ diagnostics are absent. A structured-subschema field is emitted TYPED (subfields projected to their declared data_type; number/boolean parse-miss -> null, enum/date miss and nested values -> raw), matching the cells[].value projection and the run.completed webhook."},"cells":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ResultsCell"},"description":"Present only when include=cells. Keyed by field_key."},"provenance":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ResultsProvenance"},"description":"Present only when include=provenance. Keyed by field_key."},"audit":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ResultsAuditVersion"}},"description":"Present only when include=audit. Keyed by field_key; the cell-version trail."}}},"ResultsPagination":{"type":"object","required":["total","limit","has_more","next_cursor"],"properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Opaque cursor keyed on record_id. Stable under concurrent appends."}}},"PipelineResultsResponse":{"type":"object","required":["pipeline_id","spec_id","status","view","generated_at","columns","data","pagination","pending_review_count","links"],"properties":{"pipeline_id":{"type":"string","format":"uuid"},"spec_id":{"type":"string","format":"uuid","description":"pipeline.schema_id — the Spec this run compiled from."},"status":{"type":"string","description":"The pipeline's own lifecycle status. Never settles for an append pipeline that keeps receiving requests."},"view":{"type":"string","enum":["composed","documents"]},"generated_at":{"type":"string","format":"date-time"},"columns":{"type":"array","items":{"$ref":"#/components/schemas/ResultsColumn"}},"data":{"type":"array","items":{"$ref":"#/components/schemas/ResultsRecord"}},"pagination":{"$ref":"#/components/schemas/ResultsPagination"},"pending_review_count":{"type":"integer","description":"Held cells in the current page's records only."},"scope_note":{"type":"string","description":"Present only for the echo-less legacy run_id zero-state — a 200 empty page, never a guess."},"links":{"type":"object","required":["self","pipeline","progress"],"properties":{"self":{"type":"string"},"pipeline":{"type":"string"},"progress":{"type":"string"}}}}},"RunResultsResponse":{"type":"object","required":["run_id","pipeline_id","spec_id","status","view","generated_at","columns","data","pagination","pending_review_count","links"],"properties":{"run_id":{"type":"string","format":"uuid"},"pipeline_id":{"type":["string","null"],"format":"uuid","description":"Null while the run has no compiled pipeline yet."},"spec_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processing","completed","failed"],"description":"The folded public run status (same vocabulary as GET /v1/run/{id}) — settles even for an append pipeline that never settles at the pipeline level."},"view":{"type":"string","enum":["documents"],"description":"Always documents on this route."},"generated_at":{"type":"string","format":"date-time"},"columns":{"type":"array","items":{"$ref":"#/components/schemas/ResultsColumn"}},"data":{"type":"array","items":{"$ref":"#/components/schemas/ResultsRecord"}},"pagination":{"$ref":"#/components/schemas/ResultsPagination"},"pending_review_count":{"type":"integer"},"scope_note":{"type":"string","description":"Present only for the two zero-states — no pipeline yet, or an echo-less legacy run."},"links":{"type":"object","required":["self","run"],"properties":{"self":{"type":"string"},"run":{"type":"string"},"composed_results":{"type":"string","description":"Present only when a pipeline exists — GET /v1/pipelines/{id}/results, where an assembly run's composed rows actually live."}}}}},"ResultsBadRequestError":{"type":"object","required":["error","code","message"],"properties":{"error":{"type":"string","enum":["bad_request"]},"code":{"type":"string","enum":["invalid_view","invalid_document_ids","invalid_run_id","invalid_time_range","invalid_status","invalid_include","unsupported_filter","audit_include_too_broad"]},"message":{"type":"string"}}},"ResolutionResponse":{"type":"object","required":["id","status","created_at","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"source_run_id":{"type":"string","format":"uuid","example":"f2a3b4c5-d6e7-8901-fabc-012345678901"},"status":{"type":"string","example":"completed","enum":["pending","running","completed","failed"]},"documents_processed":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"results":{"type":"string"}}}}},"LinkKeyResponse":{"type":"object","required":["field_name","category"],"properties":{"field_name":{"type":"string","example":"invoice_number"},"category":{"type":"string","example":"identity","enum":["identity","transaction","reference"]},"auto_classified":{"type":"boolean"},"frequency":{"type":["number","null"],"format":"float","description":"Fraction of documents containing this link key value."}}},"SchemaGraphClassResponse":{"type":"object","required":["id","name","version","field_count","links"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"description":{"type":["string","null"]},"version":{"type":"integer"},"field_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"versions":{"type":"string"}}}}},"SchemaGraphDiffResponse":{"type":"object","required":["id","class_id","status","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"class_id":{"type":"string","format":"uuid","example":"a7b8c9d0-e1f2-3456-abcd-567890123456"},"from_version":{"type":["integer","null"]},"to_version":{"type":["integer","null"]},"status":{"type":"string","example":"completed","enum":["pending","approved","rejected"]},"changes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"List of field additions, removals, and modifications."},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"decided_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"StructuringCheckResponse":{"type":"object","required":["id","name","type","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":"string","description":"Check type: field_format, value_range, cross_field, ai_coherence."},"config":{"type":"object","additionalProperties":true},"enabled":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"StructuringCheckCreateRequest":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","description":"Check type: field_format, value_range, cross_field, ai_coherence."},"config":{"type":"object","additionalProperties":true},"enabled":{"type":"boolean","default":true}}},"StructuringGateResponse":{"type":"object","required":["id","name","rules","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"description":{"type":["string","null"]},"schema_id":{"type":["string","null"],"format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"type":{"type":"string"},"threshold":{"type":"number","format":"float"}}}},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"updated_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"}}},"StructuringGateCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"schema_id":{"type":"string","format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"}}},"GroundTruthResponse":{"type":"object","required":["id","name","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string"},"description":{"type":["string","null"]},"sample_count":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"}}}}},"ValidationRunResponse":{"type":"object","required":["id","status","created_at"],"properties":{"id":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"golden_sample_id":{"type":"string","format":"uuid","example":"e5f6a7b8-c9d0-1234-efab-345678901234"},"schema_id":{"type":["string","null"],"format":"uuid","example":"b2c3d4e5-f6a7-8901-bcde-f12345678901"},"status":{"type":"string","example":"completed","enum":["pending","running","completed","failed"]},"accuracy_overall":{"type":["number","null"],"format":"float"},"documents_processed":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time","example":"2026-04-25T14:30:00.000Z"},"completed_at":{"type":["string","null"],"format":"date-time","example":"2026-04-25T14:30:00.000Z"},"links":{"type":"object","properties":{"self":{"type":"string"},"results":{"type":"string"}}}}},"Pagination":{"type":"object","properties":{"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}}},"DataProduct":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"schema_id":{"type":"string","format":"uuid"},"run_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft","ready","published","archived"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"DataPolicy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"DataPolicyField":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"field_key":{"type":"string"},"field_type":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"DataPolicyRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"field_key":{"type":"string"},"rule_type":{"type":"string"},"config":{"type":"object"},"ordinal":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}},"NodeRun":{"type":"object","description":"A standalone run of one One Engine phase over a record set.","properties":{"id":{"type":"string","format":"uuid"},"node_type":{"type":"string","enum":["transfer","extraction","resolution","validation","assembly"]},"status":{"type":"string","enum":["queued","running","completed","partial","error"]},"record_set_id":{"type":"string","format":"uuid","nullable":true},"product_record_set_id":{"type":"string","format":"uuid","nullable":true},"total":{"type":"integer"},"completed":{"type":"integer"},"errors":{"type":"integer"},"error_message":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"links":{"type":"object"}}},"RecordSet":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"layer":{"type":"string","enum":["capture","structured","resolved","product"]},"kind":{"type":"string","description":"Source kind (e.g. structuring_run, resolution_run, data_product)."},"source_id":{"type":["string","null"],"format":"uuid","description":"Owning run/product ID where applicable."},"status":{"type":"string","description":"Lifecycle state (e.g. active)."},"record_count":{"type":"integer"},"field_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"links":{"type":"object","properties":{"self":{"type":"string"},"fields":{"type":"string"},"records":{"type":"string"},"export":{"type":"string"}}}}}}}}