Skip to main content

Query the Registry

Query previously-extracted field values across all documents without re-extraction. Zero AI calls. Filter by field values and select which fields to return.

The registry query endpoint searches across all previously-extracted documents by field values. No document upload, no re-extraction, no AI calls. Documents ingested days or months ago are queryable immediately: ingest once, query forever. The endpoint is mounted at two prefixes that serve the same handler: POST /v1/fields/registry/query is the canonical path, part of the Field Registry surface alongside GET /v1/fields, and POST /v1/registry/query is a deprecated alias kept for existing integrations. Both mounts are live, equivalent, and share one rate-limit namespace.

POST/v1/fields/registry/query

Body parameters

where*objectField-value conditions. Keys are field names, values are the expected values. All conditions are ANDed. Values match case-insensitively; use `%` wildcards for partial matches.
selectstring[]Field names to return in results. If omitted, returns all fields referenced in `where`. Fields used in `where` are always included in the output.
limitintegerMaximum rows to return (default 100, max 500). Default: 100

Request

Field names in where and select are resolved against your workspace's Field Registry by canonical name (case-insensitive). An unknown field name in where returns a 200 response with an error body ({ "error": "unknown_field", "message": "..." }), not an HTTP error status, so check the body for an error key before reading data.

How it works: The query searches the resolved_document_values table — materialized field values produced by extraction and Jobs. Every field extracted from every document is queryable, and matching documents are returned newest first. Value matching uses case-insensitive SQL ILIKE, so "meridian energy ag" matches "Meridian Energy AG", and "%energy%" matches any value containing "energy". No LLM calls are made.

Response

Response fields

dataarrayArray of flat row objects, one per matching document.
data[].document_idstringUUID of the matching document.
data[].filenamestringOriginal filename of the document.
data[].document_typestring | nullInferred document type (e.g. "Framework Agreement").
data[].<field_name>stringEach requested field appears as a top-level key with its string value.
totalintegerNumber of documents returned (capped at limit).

Response

{
  "data": [
    {
      "document_id": "d7a1b2c3-...",
      "filename": "meridian-framework-2026.pdf",
      "document_type": "Framework Agreement",
      "vendor_name": "Meridian Energy AG",
      "contract_year": "2026",
      "contract_value": "450000",
      "auto_renew": "true",
      "notice_period_days": "90"
    },
    {
      "document_id": "e8f4a5b6-...",
      "filename": "meridian-amendment-q2.pdf",
      "document_type": "Contract Amendment",
      "vendor_name": "Meridian Energy AG",
      "contract_year": "2026",
      "contract_value": "475000",
      "auto_renew": "true",
      "notice_period_days": "90"
    }
  ],
  "total": 2
}

Errors

Error responses

400bad_request`where` is missing or empty. Provide at least one field-value condition.
200unknown_fieldA field name in `where` was not found in the registry. Returned as a 200 with an `error` body, not an HTTP error. Check field names with GET /v1/fields.
401unauthorizedMissing or invalid API key.
429rate_limitedToo many requests. Retry after the period indicated in the Retry-After header.

Most integrations use registry query as a lookup layer after ingestion is complete. Call POST /v1/extract to ingest documents, wait for the document.extraction.completed webhook, then query the registry by field values to retrieve structured data across your entire corpus. Pair with GET /v1/fields to discover available canonical field names before building where conditions.