Skip to main content

Create Check

Create a validation check with POST /v1/structuring/checks: pick a type (field_format, field_range, cross_field, lookup), a per-type config, and severity.

POST /v1/structuring/checks creates a validation check: an in-pipeline data quality rule that runs automatically against future structuring results for one schema. Each check has a type (field_format, field_range, field_presence, cross_field, lookup, or custom_expression), a severity label, and a type-specific config. Newly created checks are active immediately and evaluate against the next result produced under their schema — existing results are never re-evaluated retroactively.

The config shape depends on the type. For field_range, provide field plus min and/or max (and optionally allow_null: true). For field_format, provide field and a format of regex (with pattern), email, url, date, iso_date, or uuid. For cross_field, provide rule (date_before, date_after, not_equal, or sum_equals), field_a, field_b, and for sum_equals an optional tolerance (default 0.01). For field_presence, provide fields and an optional mode (all or any). For lookup, provide field and a values allowlist.

The config object is not schema-validated at create time — the API accepts any JSON and the shape is only interpreted at evaluation. A typo'd type or format does not error: an unknown check type or field_format format records a skip outcome on every result, which reads as "never fails". After creating a check, verify the first outcomes via GET /v1/structuring/results/{id}/checks.
POST/v1/structuring/checks

Body parameters

name*stringCheck name, shown on outcomes and in the pending review queue.
type*stringCheck type: field_format, field_range, field_presence, cross_field, lookup, or custom_expression.
user_schema_id*uuidSchema this check is scoped to. Must be a valid UUID.
descriptionstringOptional description of what the check validates.
severitystringSeverity label stamped on outcomes: warning (default), error, or critical. critical failures are countable by validation_pass gate rules with scope critical_only.
configobjectType-specific configuration (see above). Optional in the API contract, but every type except custom_expression reads it — without one the check records skip or fail outcomes.

curl

curl -s -X POST https://api.talonic.com/v1/structuring/checks \
  -H "Authorization: Bearer tlnc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Total amount range",
    "type": "field_range",
    "user_schema_id": "36ef3a00-a4dc-4e49-af6a-66ae20f9b58a",
    "severity": "error",
    "description": "Totals must be plausible",
    "config": { "field": "total_amount", "min": 0, "max": 1000000 }
  }'

Response

Response fields (201 Created)

idstringCheck UUID.
user_schema_idstringSchema scope.
namestringCheck name.
descriptionstring | nullOptional description.
typestringCheck type.
severitystringSeverity label (warning when omitted).
configobject | nullType-specific configuration, echoed as stored.
is_activebooleanAlways true for newly created checks.
sort_orderintegerEvaluation order; defaults to 0. Adjust later via PUT.
created_atstringISO 8601 creation timestamp.
updated_atstringISO 8601 last update timestamp.
linksobjectRelated resource URLs (self).

Response (201 Created)

{
  "id": "5fee4bba-8380-44b8-9780-5e4548424b3c",
  "user_schema_id": "36ef3a00-a4dc-4e49-af6a-66ae20f9b58a",
  "name": "Total amount range",
  "description": "Totals must be plausible",
  "type": "field_range",
  "severity": "error",
  "config": { "field": "total_amount", "min": 0, "max": 1000000 },
  "is_active": true,
  "sort_order": 0,
  "created_at": "2026-08-29T11:35:01.940Z",
  "updated_at": "2026-08-29T11:35:01.940Z",
  "links": {
    "self": "/v1/structuring/checks/5fee4bba-8380-44b8-9780-5e4548424b3c"
  }
}

Errors

Error responses

400VALIDATION_ERRORA required field is missing or malformed — the message names the offending fields (e.g. "user_schema_id must be a UUID; type must be a string"). Also returned when a master-view API key is used on a create operation, since no single organization context exists.
401unauthorizedMissing or invalid API key.
429rate_limitedToo many requests. Retry after the period indicated in the Retry-After header.

A typical invoice setup pairs three checks on one schema: a field_range on the total (severity error), a field_format date check on due_date (severity warning), and a cross_field sum_equals between line_items[].amount and total_amount. Checks flag issues; to make flags block delivery, wire a gate: create one with [POST /v1/structuring/gates](create-structuring-gate) and attach a validation_pass rule with max_failures: 0, so any failing check parks the result for manual review.

Severity is worth choosing deliberately even though it never blocks anything on its own. Reserve critical for the checks that must gate delivery, then scope your gate rule with { "scope": "critical_only" } — advisory checks keep running and recording warning failures without ever holding a record. This split lets one schema carry both hard contract checks and soft data-hygiene signals through the same pipeline.

Frequently asked questions

Can I create a check without a config object?+
The API accepts it, but only custom_expression is meaningful without one — and that type is reserved and currently records skip outcomes. Every other type reads its config at evaluation: field_range and field_format skip or fail without their field, and lookup with no values list fails everything. In practice, always pass the config for the type.
What happens if I use a master-view API key?+
Create operations require an organization-scoped API key. Using a master-view key returns 400 VALIDATION_ERROR because the system cannot determine which organization to associate the check with. Reads work fine with master-view keys.
Is user_schema_id required when creating a check?+
Yes. Every check created through the API is scoped to one schema via a required user_schema_id UUID. The check then evaluates only results produced against that schema, and the scope cannot be changed later — create a new check to cover another schema.
Do new checks affect results that already exist?+
No. Checks evaluate when a structuring result is produced, so a new check applies only to results created after it. Historical results keep the outcomes they were evaluated with; there is no re-run endpoint on the public API.