Skip to main content
POST
Evaluate
Initial submissions: record.xml + record.candidate_info. Resubmissions: record.submission_type ("resubmit") + record.record_json + record.candidate_info. Both paths require search_id, search_date, order_id, and order_number on record. The response shape is unchanged for both paths.

Input modes: XML vs JSON

The record object accepts two mutually exclusive input types: For resubmissions, send sibling fields on record: submission_type ("resubmit"), record_json (mapped criminal data only), candidate_info, plus search_id, search_date, order_id, and order_number. submission_type: "resubmit" is required whenever record_json is provided, and must be a top-level field on record — not inside record_json or record_json.search. Initial submissions use record.xml + record.candidate_info with no submission_type (or omit it).

Request

Authorization
string
required
Bearer YOUR_JWT_TOKEN — see Authentication
record
object
required
The criminal record to evaluate. Provide exactly one of xml (initial submission) or record_json (resubmission), plus search metadata.

Request validation

Common HTTP 400 errors: Common HTTP 422 errors (XML-Transformer — court search ID / offense ID count mismatch):
This validation runs inside XML-Transformer and returns HTTP 422 on /transform-xml. On POST /evaluate, the orchestrator still returns HTTP 500 with data.status: "failed" and embeds the XT error as XML-Transformer HTTP error 422: ... in data.errors[].

cases[] count reconciliation (XML-Transformer gate)

When record.cases[] is non-empty, XML-Transformer validates that counts match the parsed record before enrichment or compliance evaluation. Processing stops immediately on mismatch. Matching example — XML has 2 cases and 3 charges:
Offense "2" is included in the array to maintain positional alignment but excluded from the response (is_excluded: true). All three charges are still processed. Mismatch example — UBS sends 17 distinct court_search_id values and 22 offense_id rows, but XML has 24 cases and 32 offenses → rejected.
This gate is not surfaced as HTTP 422 on POST /evaluate. XML-Transformer returns HTTP 422 internally (error_code: CASE_OFFENSE_COUNT_MISMATCH); the orchestrator surfaces HTTP 500 with data.status: "failed". See Example Response — Failed (court search ID / offense ID count mismatch).
The record_json structure errors above apply when record_json is provided (resubmission path). The sentence block on offenses is optional and is not validated as required on input. Other offense-level fields are validated separately during enrichment.

Response

All responses are wrapped in a standard envelope:
success
boolean
true when status is success or partial. false on failed.
data
object
The evaluation result payload.
meta
object
Request metadata.

HTTP Status Codes


record_json reference

record_json is mapped-tier criminal data — court searches, cases, and charges from a prior pipeline output. It does not include candidate demographics or order metadata; send candidate_info, order_id, and order_number via sibling fields on record. Required top-level key: criminal_search_results (non-empty array) Each criminal_search_results[] item must include required fields (court_search_id, search_date, criminal_records) — values must not be null, missing, or empty (""). search_jurisdiction is optional (ignored for validation when missing or empty; still accepted when provided). Nested criminal_records[] items must include all required case fields. Arrays (criminal_records, offenses) must not be empty. Prefer case-level jurisdiction_state (and jurisdiction when available) for location. Forbidden inside record_json: candidate_info, submission_type (including record_json.search.submission_type on input), order_id, order_number (including inside record_json.search), status (including record_json.search.status on input). Optional metadata in record_json.search. Do not include submission_type, order_id, order_number, or status here on input — send record.submission_type, record.order_id, and record.order_number instead.

criminal_search_results[]

criminal_records[] (case)

offenses[] (charge)

sentence (on offense)

Optional — omit the entire sentence block when sentence data is not available or not yet in scope. When provided, individual fields within sentence are also optional unless noted otherwise.
Send candidate_info as a flat block with a single-line address string and submission_type as a top-level field on record. The API handles normalization internally — you do not need to send structured addresses[] or nest these fields inside record_json.

Code Examples

Primary example for JSON resubmission:
Do not nest candidate_info, submission_type, order_id, or order_number inside record_json. Send submission_type: "resubmit" as a top-level field on record whenever record_json is provided.
Example offense with Pending disposition and a future pending_court_date:
Same envelope as resubmission — use xml instead of record_json + submission_type. Omit submission_type on initial submissions:
Copy and modify this JSON payload for initial XML submissions:
When the source data is clean, the validation field is omitted entirely from the response (not returned as an empty object). It only appears when there are real data-quality issues — see the next example.
When the source data has quality issues, the response includes a structured validation object alongside the decision. The validation field is only present when issues exist:
Validation issue types:
  • issues.errors — Hard data-quality problems (missing SSN, missing disposition, indeterminate charge classification). These typically force affected charges into the Insufficient Data queue, which then propagates up through case_queue, court_queue, and search_queue.
  • issues.warnings — Soft mismatches (e.g., type-class or disposition-class disagreements between the rule engine and the ML model). The rule-engine classification takes precedence — these are informational only and do not change routing on their own.
When some components fail, status is partial and degradation is included. The errors array carries the engine-level failure messages:
When court search ID / offense ID counts in cases[] do not match the parsed XML/record_json, XML-Transformer rejects the request internally (HTTP 422, error_code: CASE_OFFENSE_COUNT_MISMATCH). The orchestrator returns HTTP 500 with data.status: "failed" and no compliance evaluation:
XML-Transformer response on /transform-xml (HTTP 422):

Validation

The validation object surfaces data-quality issues in the source record. It is omitted entirely from the response when the source data is clean — your client should treat the absence of validation as “no issues”. When present, it has this shape:
Each item:
errors vs warnings:
  • errors are hard data-quality problems — they typically force affected charges into the Insufficient Data queue, which then bubbles up through case_queuecourt_queuesearch_queue.
  • warnings are soft mismatches (e.g., the rule engine and ML model disagree on type class). The rule-engine classification wins; these are informational only.
errors here is not the same as the top-level data.errors array. data.errors carries service-level failures (engine timeouts, network errors). validation.issues.errors carries data-level problems in the input record.

JSON Field Reference

Field values below are sourced from the live API contract. See also Glossary and Routing.

Request — outer record

Response — envelope

HTTP status: 200 success · 206 partial · 400 bad input · 422 validation · 500 failed

Response — decision labels (*_decision)

Queue → decision mapping (aggregated levels only):

Response — routing queues (*_queue)

Response — per-offense routing

Response — id_match (per case)

Response — other offense fields

Request — offense sentence (optional)

Omit sentence entirely when not applicable. When included, all fields below are optional.

Response — validation (when issues exist)

record_decision vs search_queue: These are linked at aggregated levels — e.g. search_queue: "Automation" always pairs with record_decision: "NOT_REPORTABLE". Per-offense charge_decision comes from the compliance engine independently; aggregated *_decision labels mirror the queue mapping above.

Decision Hierarchy

The evaluation result (data.decision) is structured hierarchically: Record → Court → Case → Offense Each level carries both a reportability label (*_decision) and a routing queue (*_queue):

Aggregated decision labels (*_decision)

At case, court, and record levels, *_decision is derived from the matching *_queue, not rolled up from child charge_decision values: charge_decision on each offense is computed independently by the compliance engine (REPORTABLE | NOT_REPORTABLE | MANUAL_REVIEW).

Queue rollup (*_queue)

case_queue, court_queue, and search_queue are aggregated from per-charge routing.queue values:
  1. Insufficient Data (highest) — if any child queue is Insufficient Data
  2. Auditor — if any child is Auditor (and none are Insufficient Data)
  3. Automation (lowest) — every child is Automation
Use per-offense charge_decision and routing.queue for charge-level handling. At aggregated levels, *_decision mirrors *_queue via the mapping above — e.g. one reportable charge routed to Auditor yields record_decision: "REPORTABLE" and search_queue: "Auditor".