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

curl -X POST https://api.talonic.com/v1/fields/registry/query \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "where": {
      "vendor_name": "Meridian Energy AG",
      "contract_year": "2026"
    },
    "select": ["contract_value", "auto_renew", "notice_period_days"],
    "limit": 50
  }'
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.

Frequently asked questions

Does registry query re-extract documents?+
No. It searches previously-extracted field values with zero AI calls. Documents can have been ingested days or months ago.
What field names can I use in where and select?+
Any canonical field name from your workspace's Field Registry. Names are resolved case-insensitively. Use GET /v1/fields to discover available field names.
How is this different from POST /v1/documents/filter?+
Registry query returns flat rows (field name to value), shaped for agents and programmatic consumption, and takes field names directly. Filter documents returns document objects with nested field values, takes field IDs, and supports richer operators like ranges and emptiness checks.
Can I do partial or case-insensitive matching in where conditions?+
Yes. Values are matched with case-insensitive SQL ILIKE, so exact matches ignore case by default. Include `%` wildcards in a value (for example `"%energy%"`) to match substrings.
Which path should I use, /v1/registry or /v1/fields/registry?+
Both prefixes are live and resolve to the same handler with the same rate limits. `/v1/fields/registry` is the canonical path; `/v1/registry` is a deprecated alias kept so existing integrations keep working. New integrations should use `/v1/fields/registry`.