curl --request POST \
--url https://cra.pr.snh-ai.com/evaluate \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"record": {
"search_id": "<string>",
"search_date": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"xml": "<string>",
"record_json": {},
"submission_type": "<string>",
"tenant_id": "<string>",
"applicant_state": "<string>",
"cases": [
{
"court_search_id": "<string>",
"offense_id": "<string>",
"is_excluded": true
}
],
"offense_ids": [
{}
],
"candidate_info": {
"first_name": "<string>",
"middle_name": "<string>",
"last_name": "<string>",
"date_of_birth": "<string>",
"ssn": "<string>",
"address": "<string>",
"source_type": "<string>",
"source_reliability_rating": "<string>",
"verification_status": "<string>"
},
"search_type": "<string>"
}
}
'import requests
url = "https://cra.pr.snh-ai.com/evaluate"
payload = { "record": {
"search_id": "<string>",
"search_date": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"xml": "<string>",
"record_json": {},
"submission_type": "<string>",
"tenant_id": "<string>",
"applicant_state": "<string>",
"cases": [
{
"court_search_id": "<string>",
"offense_id": "<string>",
"is_excluded": True
}
],
"offense_ids": [{}],
"candidate_info": {
"first_name": "<string>",
"middle_name": "<string>",
"last_name": "<string>",
"date_of_birth": "<string>",
"ssn": "<string>",
"address": "<string>",
"source_type": "<string>",
"source_reliability_rating": "<string>",
"verification_status": "<string>"
},
"search_type": "<string>"
} }
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
record: {
search_id: '<string>',
search_date: '<string>',
order_id: '<string>',
order_number: '<string>',
xml: '<string>',
record_json: {},
submission_type: '<string>',
tenant_id: '<string>',
applicant_state: '<string>',
cases: [{court_search_id: '<string>', offense_id: '<string>', is_excluded: true}],
offense_ids: [{}],
candidate_info: {
first_name: '<string>',
middle_name: '<string>',
last_name: '<string>',
date_of_birth: '<string>',
ssn: '<string>',
address: '<string>',
source_type: '<string>',
source_reliability_rating: '<string>',
verification_status: '<string>'
},
search_type: '<string>'
}
})
};
fetch('https://cra.pr.snh-ai.com/evaluate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cra.pr.snh-ai.com/evaluate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'record' => [
'search_id' => '<string>',
'search_date' => '<string>',
'order_id' => '<string>',
'order_number' => '<string>',
'xml' => '<string>',
'record_json' => [
],
'submission_type' => '<string>',
'tenant_id' => '<string>',
'applicant_state' => '<string>',
'cases' => [
[
'court_search_id' => '<string>',
'offense_id' => '<string>',
'is_excluded' => true
]
],
'offense_ids' => [
[
]
],
'candidate_info' => [
'first_name' => '<string>',
'middle_name' => '<string>',
'last_name' => '<string>',
'date_of_birth' => '<string>',
'ssn' => '<string>',
'address' => '<string>',
'source_type' => '<string>',
'source_reliability_rating' => '<string>',
'verification_status' => '<string>'
],
'search_type' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://cra.pr.snh-ai.com/evaluate"
payload := strings.NewReader("{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://cra.pr.snh-ai.com/evaluate")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://cra.pr.snh-ai.com/evaluate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"search_id": "<string>",
"correlation_id": "<string>",
"status": "<string>",
"errors": [
{}
],
"validation": {
"status": "<string>",
"issues": {
"errors": [
{
"level": "<string>",
"field": "<string>",
"issue": "<string>",
"description": "<string>",
"case_id": "<string>",
"case_number": "<string>",
"offense_id": "<string>"
}
],
"warnings": [
{}
]
}
},
"decision": {
"search_id": "<string>",
"decision_date": "<string>",
"record_decision": "<string>",
"search_queue": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"ubs_search_type": "<string>",
"court_decisions": [
{
"court_search_id": "<string>",
"court_decision": "<string>",
"court_queue": "<string>",
"case_decisions": [
{
"case_number": "<string>",
"case_decision": "<string>",
"case_queue": "<string>",
"jurisdiction_state": "<string>",
"id_match": {
"is_match": true,
"match_score": 123,
"name_score": 123,
"dob_score": 123,
"ssn_score": 123,
"address_score": 123,
"details": "<string>"
},
"offenses": [
{
"offense_id": "<string>",
"charge": "<string>",
"charge_decision": "<string>",
"type": "<string>",
"disposition": "<string>",
"rationale": "<string>",
"needs_human_review": true,
"cited_rules": [
{}
],
"citations": [
{}
],
"routing": {
"queue": "<string>",
"reportability": "<string>",
"is_automatable": true,
"identity_level": "<string>",
"identity_score": 123,
"identity_insufficient": true,
"reportability_insufficient": true,
"third_id_required": true
}
}
]
}
]
}
]
},
"timing": {},
"degradation": {}
},
"meta": {
"api_version": "<string>",
"process_time_ms": 123,
"correlation_id": "<string>"
}
}Evaluate
Evaluate a single criminal record for compliance and reportability
curl --request POST \
--url https://cra.pr.snh-ai.com/evaluate \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"record": {
"search_id": "<string>",
"search_date": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"xml": "<string>",
"record_json": {},
"submission_type": "<string>",
"tenant_id": "<string>",
"applicant_state": "<string>",
"cases": [
{
"court_search_id": "<string>",
"offense_id": "<string>",
"is_excluded": true
}
],
"offense_ids": [
{}
],
"candidate_info": {
"first_name": "<string>",
"middle_name": "<string>",
"last_name": "<string>",
"date_of_birth": "<string>",
"ssn": "<string>",
"address": "<string>",
"source_type": "<string>",
"source_reliability_rating": "<string>",
"verification_status": "<string>"
},
"search_type": "<string>"
}
}
'import requests
url = "https://cra.pr.snh-ai.com/evaluate"
payload = { "record": {
"search_id": "<string>",
"search_date": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"xml": "<string>",
"record_json": {},
"submission_type": "<string>",
"tenant_id": "<string>",
"applicant_state": "<string>",
"cases": [
{
"court_search_id": "<string>",
"offense_id": "<string>",
"is_excluded": True
}
],
"offense_ids": [{}],
"candidate_info": {
"first_name": "<string>",
"middle_name": "<string>",
"last_name": "<string>",
"date_of_birth": "<string>",
"ssn": "<string>",
"address": "<string>",
"source_type": "<string>",
"source_reliability_rating": "<string>",
"verification_status": "<string>"
},
"search_type": "<string>"
} }
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
record: {
search_id: '<string>',
search_date: '<string>',
order_id: '<string>',
order_number: '<string>',
xml: '<string>',
record_json: {},
submission_type: '<string>',
tenant_id: '<string>',
applicant_state: '<string>',
cases: [{court_search_id: '<string>', offense_id: '<string>', is_excluded: true}],
offense_ids: [{}],
candidate_info: {
first_name: '<string>',
middle_name: '<string>',
last_name: '<string>',
date_of_birth: '<string>',
ssn: '<string>',
address: '<string>',
source_type: '<string>',
source_reliability_rating: '<string>',
verification_status: '<string>'
},
search_type: '<string>'
}
})
};
fetch('https://cra.pr.snh-ai.com/evaluate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cra.pr.snh-ai.com/evaluate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'record' => [
'search_id' => '<string>',
'search_date' => '<string>',
'order_id' => '<string>',
'order_number' => '<string>',
'xml' => '<string>',
'record_json' => [
],
'submission_type' => '<string>',
'tenant_id' => '<string>',
'applicant_state' => '<string>',
'cases' => [
[
'court_search_id' => '<string>',
'offense_id' => '<string>',
'is_excluded' => true
]
],
'offense_ids' => [
[
]
],
'candidate_info' => [
'first_name' => '<string>',
'middle_name' => '<string>',
'last_name' => '<string>',
'date_of_birth' => '<string>',
'ssn' => '<string>',
'address' => '<string>',
'source_type' => '<string>',
'source_reliability_rating' => '<string>',
'verification_status' => '<string>'
],
'search_type' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://cra.pr.snh-ai.com/evaluate"
payload := strings.NewReader("{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://cra.pr.snh-ai.com/evaluate")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://cra.pr.snh-ai.com/evaluate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"record\": {\n \"search_id\": \"<string>\",\n \"search_date\": \"<string>\",\n \"order_id\": \"<string>\",\n \"order_number\": \"<string>\",\n \"xml\": \"<string>\",\n \"record_json\": {},\n \"submission_type\": \"<string>\",\n \"tenant_id\": \"<string>\",\n \"applicant_state\": \"<string>\",\n \"cases\": [\n {\n \"court_search_id\": \"<string>\",\n \"offense_id\": \"<string>\",\n \"is_excluded\": true\n }\n ],\n \"offense_ids\": [\n {}\n ],\n \"candidate_info\": {\n \"first_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"<string>\",\n \"ssn\": \"<string>\",\n \"address\": \"<string>\",\n \"source_type\": \"<string>\",\n \"source_reliability_rating\": \"<string>\",\n \"verification_status\": \"<string>\"\n },\n \"search_type\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"search_id": "<string>",
"correlation_id": "<string>",
"status": "<string>",
"errors": [
{}
],
"validation": {
"status": "<string>",
"issues": {
"errors": [
{
"level": "<string>",
"field": "<string>",
"issue": "<string>",
"description": "<string>",
"case_id": "<string>",
"case_number": "<string>",
"offense_id": "<string>"
}
],
"warnings": [
{}
]
}
},
"decision": {
"search_id": "<string>",
"decision_date": "<string>",
"record_decision": "<string>",
"search_queue": "<string>",
"order_id": "<string>",
"order_number": "<string>",
"ubs_search_type": "<string>",
"court_decisions": [
{
"court_search_id": "<string>",
"court_decision": "<string>",
"court_queue": "<string>",
"case_decisions": [
{
"case_number": "<string>",
"case_decision": "<string>",
"case_queue": "<string>",
"jurisdiction_state": "<string>",
"id_match": {
"is_match": true,
"match_score": 123,
"name_score": 123,
"dob_score": 123,
"ssn_score": 123,
"address_score": 123,
"details": "<string>"
},
"offenses": [
{
"offense_id": "<string>",
"charge": "<string>",
"charge_decision": "<string>",
"type": "<string>",
"disposition": "<string>",
"rationale": "<string>",
"needs_human_review": true,
"cited_rules": [
{}
],
"citations": [
{}
],
"routing": {
"queue": "<string>",
"reportability": "<string>",
"is_automatable": true,
"identity_level": "<string>",
"identity_score": 123,
"identity_insufficient": true,
"reportability_insufficient": true,
"third_id_required": true
}
}
]
}
]
}
]
},
"timing": {},
"degradation": {}
},
"meta": {
"api_version": "<string>",
"process_time_ms": 123,
"correlation_id": "<string>"
}
}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
Therecord object accepts two mutually exclusive input types:
| Input | Use case |
|---|---|
record.xml + record.candidate_info | Initial submission — raw vendor XML |
record.submission_type + record.record_json + record.candidate_info | Resubmission — corrected mapped criminal JSON |
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
Bearer YOUR_JWT_TOKEN — see Authenticationxml (initial submission) or record_json (resubmission), plus search metadata.Show Record Properties
Show Record Properties
YYYY-MM-DD formatrecord alongside search_id and search_date. Required, non-empty string. Must not be null, empty (""), or nested inside record_json or record_json.search. Echoed in the response.orderID.subOrderID) — top-level on record. Required, non-empty string. Must not be null, empty (""), or nested inside record_json or record_json.search.<ScreeningResults>...</ScreeningResults>). Initial submission — provide this or record_json, not both.criminal_search_results. Must not include candidate_info, submission_type, order_id, or order_number — provide those as sibling fields on record. Requires submission_type: "resubmit" on record. Mutually exclusive with xml.record_json is provided — must be "resubmit". Omit on initial XML submissions. Must be a top-level field on record, not inside record_json or record_json.search."CA", "TX"). Used for state-specific compliance rules.[] to evaluate all offenses (count-reconciliation gate not applied). When non-empty, cases[] must enumerate every court and offense in the parsed XML or record_json — counts must match exactly. Partial or filtered subsets are rejected.cases[] entries are mapped to charges in the vendor XML by sequential position. You must include an entry for every charge in the XML, in the same order the charges appear, even for charges that don’t need a decision. For charges to exclude from the response, set is_excluded: true. Sending fewer entries than XML charges causes positional drift — identifiers will be mapped to the wrong cases.Show Case Mapping Properties
Show Case Mapping Properties
"CS40929433A"). Required on each row when cases is non-empty — must be non-empty. Multiple rows may share the same court_search_id when that court has multiple offenses (1 court : many offenses)."34789896"). Required on each row when cases is non-empty — must be non-empty. Total offense_id rows must equal the total number of offenses/charges in the record.true, the charge is excluded from the response — no decision is returned for it. All charges and cases are still processed on the backend. Defaults to false if omitted. Use this to include all charges in the array (preserving positional alignment with the vendor XML) while excluding specific charges from the response.cases for full charge mapping.record for both initial XML and resubmission paths — non-empty object (not null, missing, or {}). Must not be nested inside record_json. Use the flat request shape below. Do not send aliases[] or addresses[] on the request.Show Candidate Info Properties
Show Candidate Info Properties
"John""A""Doe"YYYY-MM-DD format. Required, non-empty string. Example: "2000-01-01""123-45-6789""123 Main St, Austin, TX 78701""Statewide_criminal", "County_criminal"Request validation
| Rule | Detail |
|---|---|
| Exactly one input | Must provide exactly one of xml or record_json (not both, not neither) |
record_json shape | Must contain top-level criminal_search_results — non-empty array; each item and nested criminal_records[] entry must include all required fields (not null, missing, or "") — see record_json reference |
submission_type with record_json | record_json requires submission_type: "resubmit" on record |
cases[] | Optional — omit or send [] to evaluate all offenses (gate not applied). When non-empty, distinct court_search_id count must equal the number of XML/record_json cases with at least one offense, and total offense_id row count must equal total offenses/charges — partial subsets rejected (see below) |
candidate_info | Required on record — non-empty object (not null, missing, or {}); must include non-empty first_name, last_name, and date_of_birth; must not be inside record_json |
order_id / order_number | Required on record — non-empty strings (not null, missing, or ""); must not be inside record_json or record_json.search |
| Message | Cause |
|---|---|
Either xml or record_json is required | Neither input field was provided |
Provide exactly one of xml and record_json | Both fields were provided |
record_json must contain criminal_search_results | record_json is missing the required top-level key |
criminal_search_results must not be empty | criminal_search_results is null, missing, or [] |
court_search_id must not be empty | court_search_id is null, missing, or "" in record_json.criminal_search_results[] |
search_date must not be empty | search_date is null, missing, or "" in record_json.criminal_search_results[] |
criminal_records must not be empty | criminal_records is null, missing, or [] in record_json.criminal_search_results[] |
case_number must not be empty | case_number is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
jurisdiction_state must not be empty | jurisdiction_state is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
file_date must not be empty | file_date is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
subject_name must not be empty | subject_name is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
sub_first_name must not be empty | sub_first_name is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
sub_middle_name must not be empty | sub_middle_name is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
sub_last_name must not be empty | sub_last_name is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
subject_dob must not be empty | subject_dob is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
subject_ssn must not be empty | subject_ssn is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
subject_address must not be empty | subject_address is null, missing, or "" in record_json.criminal_search_results[].criminal_records[] |
offenses must not be empty | offenses is null, missing, or [] in record_json.criminal_search_results[].criminal_records[] |
submission_type must be 'resubmit' when record_json is provided | record_json sent without submission_type: "resubmit" |
submission_type 'resubmit' requires record_json, not xml | submission_type: "resubmit" sent with xml instead of record_json |
submission_type must not be inside record_json; provide it as a separate field | submission_type nested inside record_json |
submission_type must not be inside record_json.search; provide it as a separate field | submission_type nested inside record_json.search |
candidate_info must not be inside record_json; provide it as a separate field | candidate_info was nested inside record_json |
candidate_info must not be empty | candidate_info is null, missing, or {} |
candidate_info requires at minimum: first_name, last_name, and date_of_birth | Required candidate_info fields are missing or empty ("") |
order_id must not be inside record_json; provide it as a separate field | order_id nested inside record_json or record_json.search |
order_number must not be inside record_json; provide it as a separate field | order_number nested inside record_json or record_json.search |
order_id must not be empty | order_id is null, missing, or "" |
order_number must not be empty | order_number is null, missing, or "" |
| Message | Cause |
|---|---|
Court search ID and offense ID counts do not match the XML: {n} court search ID(s) in the request but {m} case(s) in the XML; {p} offense ID(s) in the request but {q} offense(s) in the XML. Each court search ID must map to exactly one XML case and each offense ID to exactly one XML offense; resubmit with the complete set. | Non-empty cases[] — distinct court search ID count or total offense ID row count does not match parsed XML/record_json (error_code: CASE_OFFENSE_COUNT_MISMATCH) |
/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.
| Check | Rule |
|---|---|
| Distinct courts | Number of distinct court_search_id values in cases[] = number of XML/record_json cases that have at least one offense |
| Total offenses | Number of offense_id entries in cases[] = total number of XML/record_json offenses/charges |
| One court, many offenses | Multiple cases[] rows may share the same court_search_id (1 court : N offenses) |
| Partial subsets | Rejected — you cannot send a filtered subset of courts or offenses |
| Omit or empty | Omit cases[] or send cases: [] — evaluate all offenses; gate not applied |
[
{ "court_search_id": "A", "offense_id": "1", "is_excluded": false },
{ "court_search_id": "A", "offense_id": "2", "is_excluded": true },
{ "court_search_id": "B", "offense_id": "3", "is_excluded": false }
]
"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.
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).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:true when status is success or partial. false on failed.Show Data Properties
Show Data Properties
success (all engines completed), partial (some engines failed), or failed[] when no errors occurred. These are different from data-quality issues, which appear under validation.Show Validation Properties
Show Validation Properties
needs_manual_review)Show Issues Properties
Show Issues Properties
Show Error Item Properties
Show Error Item Properties
candidate, case_subject, case, or offensesubject_ssn, disposition_class)errors.Show Decision Properties
Show Decision Properties
"2026-05-19T14:22:10Z"REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW. At aggregated levels (record_decision, court_decision, case_decision), this is derived from the matching *_queue: Automation → NOT_REPORTABLE, Auditor → REPORTABLE, Insufficient Data → MANUAL_REVIEW.Automation, Auditor, Insufficient Data. Precedence: Insufficient Data > Auditor > Automation.orderID.subOrderID form (populated when supplied in the request)Show Court Properties
Show Court Properties
"111111", "TBD" when not supplied.REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW — derived from court_queue (see record_decision).Automation, Auditor, Insufficient Data.Show Case Properties
Show Case Properties
"2009D 008764", "2024-CF-00312"REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW — derived from case_queue (see record_decision).Automation, Auditor, Insufficient Data."TX", "NC", "CA"Show Identity Match Properties
Show Identity Match Properties
details for the qualify percentage).0.85, 0.925, 0.40 (range 0–1)1, 0, or -1 when address was not scoredShow Offense Properties
Show Offense Properties
"NO LIABILITY INSURANCE")REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW"Misdemeanor", "Felony", "FELONY", "M", "D""Guilty", "GUILTY", "Dismissed", "Pending", "Deferred", "No Information"true when charge_decision is MANUAL_REVIEWGENERAL_TRAFFIC_NON_REPORT, CA_NONCONV_7YR_LIMIT)"15 U.S.C. § 1681c(a)(5)"). May be empty when the cited rules do not include explicit statute references.Show Routing Properties
Show Routing Properties
Automation, Auditor, Insufficient DataReportable, Not Reportable, Not Enough Infotrue only when queue is AutomationHigh, Medium, Not Enough Info, Not Matching. Derived from identity_score: ≥ 0.9 → High; 0.7–0.89 → Medium; ≤ −1 → Not Matching; otherwise → Not Enough Info.0.925, 0.85, 0.40true when identity data is too sparsetrue when offense data is too sparsetrue when a third identity factor is required for routingtotal_ms and per-component timing.status is partial or failed. Shows per-component availability status. Values include available, degraded, unavailable, failed, and not_called (e.g., compliance engine not invoked when XML-Transformer fails on cases[] count mismatch).HTTP Status Codes
| Status | Meaning |
|---|---|
| 200 | success — all processing completed |
| 206 | partial — some components failed, results may be incomplete |
| 400 | Invalid request — missing or conflicting xml / record_json, empty required fields |
| 422 | Validation error — payload does not reconcile with the record (includes court search ID / offense ID count mismatch when cases[] is non-empty). XML-Transformer returns 422 internally; /evaluate embeds it in a 500 / failed response |
| 500 | failed — processing failed entirely (orchestrator response when XML-Transformer rejects count mismatch or other XT failures) |
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).
| Field | Required | Example values |
|---|---|---|
criminal_search_results | Yes | Non-empty array of court search objects |
search | No | Optional search metadata — see record_json.search |
tenant_id | No | "UBS", "T001" |
record_json.search
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.
| Field | Example values |
|---|---|
search_id | "99908723" — should align with outer search_id |
vendor_source | "DataDivers" |
search_type | "USA Criminal Offender" |
criminal_search_results[]
| Field | Required | Example values |
|---|---|---|
court_search_id | Yes | "CS40929433A", "78901234" |
search_date | Yes | "2026-06-16" |
criminal_records | Yes | Non-empty array of case objects |
search_jurisdiction | No | "NC-MECKLENBURG", "TX-HARRIS" — optional; ignored for validation when missing or empty; accepted when provided (e.g. enrichment / federal fallback). Prefer case-level jurisdiction_state for location. |
criminal_records[] (case)
| Field | Required | Example values |
|---|---|---|
case_number | Yes | "2009D 008764", "2024-CF-00312" |
jurisdiction_state | Yes | "NC", "TX", "CA" |
file_date | Yes | "2009-02-10" |
subject_name | Yes | "JOHN A DOE" |
sub_first_name | Yes | "John" |
sub_middle_name | Yes | "A" |
sub_last_name | Yes | "Doe" |
subject_dob | Yes | "2000-01-01" |
subject_ssn | Yes | "123-45-6789" |
subject_address | Yes | "123 Main St, Charlotte, NC 28202" |
offenses | Yes | Non-empty array of offense objects |
offenses[] (charge)
| Field | Meaning | Example values |
|---|---|---|
offense_id | Charge identifier (required for routing) | "48870", "4628347" |
charge | Charge description | "Speeding", "THEFT OF PROPERTY >= $2,500" |
disposition | Case outcome | "Guilty", "Dismissed", "Pending", "Deferred", "No Information" |
type | Offense severity | "Misdemeanor", "Felony", "M", "FELONY", "D" |
charge_date | Charge date | "2009-02-10", null |
disposition_date | Disposition date | "2009-02-10", null |
arrest_date | Arrest date | "2009-02-08", null |
pending_court_date | Next court date when pending | "2026-07-15", null |
sentence | Optional structured sentence object | See sentence — omit if not applicable |
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.
| Field | Meaning | Example values |
|---|---|---|
incarceration_date | Date incarceration began | "2009-02-15", null (YYYY-MM-DD or null) |
release_date | Date released from custody | "2010-01-15", null (YYYY-MM-DD or null) |
is_serving | Whether the subject is currently serving this sentence | true, false |
probation | Probation term | "12 months", null |
jail_time | Jail sentence | "30 days", null |
prison_time | Prison sentence | "2 years", null |
suspended | Suspended sentence | "6 months suspended", null |
restitution | Restitution amount | "500.00", null |
community_service | Community service hours | "40 hours", null |
fines | Fine amount | "250.00", null |
court_costs | Court costs | "100.00", null |
sentence_comments | Free-text notes | "Credit for time served", null |
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
Resubmission — mapped JSON (record_json)
Resubmission — mapped JSON (record_json)
{
"record": {
"search_id": "99908723",
"search_date": "2026-06-16",
"order_id": "789",
"order_number": "789.1",
"submission_type": "resubmit",
"cases": [
{ "court_search_id": "CS40929433A", "offense_id": "34789896" }
],
"record_json": {
"criminal_search_results": [{
"court_search_id": "CS40929433A",
"search_date": "2026-06-16",
"criminal_records": [{
"case_number": "2009D 008764",
"jurisdiction_state": "NC",
"file_date": "2009-02-10",
"subject_name": "JOHN A DOE",
"sub_first_name": "John",
"sub_middle_name": "A",
"sub_last_name": "Doe",
"subject_dob": "2000-01-01",
"subject_ssn": "123-45-6789",
"subject_address": "123 Main St, Charlotte, NC 28202",
"offenses": [{
"offense_id": "34789896",
"type": "Misdemeanor",
"charge": "Speeding",
"disposition": "Guilty",
"charge_date": "2009-02-10",
"disposition_date": "2009-02-10",
"pending_court_date": null,
"sentence": {
"incarceration_date": "2024-06-01",
"release_date": "2026-06-01",
"is_serving": true,
"probation": null,
"jail_time": "30 days",
"prison_time": null,
"fines": "250.00",
"court_costs": "100.00"
}
}]
}]
}]
},
"candidate_info": {
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2000-01-01",
"address": "123 Main St, Austin, TX 78701"
}
}
}
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.Resubmission — pending charge (offense snippet)
Resubmission — pending charge (offense snippet)
Pending disposition and a future pending_court_date:{
"offense_id": "48871",
"type": "Misdemeanor",
"charge": "Driving While License Revoked",
"disposition": "Pending",
"charge_date": "2024-03-15",
"disposition_date": null,
"pending_court_date": "2026-07-15",
"sentence": {
"incarceration_date": null,
"release_date": null,
"is_serving": false,
"probation": null,
"jail_time": null,
"prison_time": null,
"suspended": null,
"restitution": null,
"community_service": null,
"fines": null,
"court_costs": null,
"sentence_comments": null
}
}
Initial submission — raw XML
Initial submission — raw XML
xml instead of record_json + submission_type. Omit submission_type on initial submissions:{
"record": {
"search_id": "99908723",
"search_date": "2026-06-16",
"order_id": "789",
"order_number": "789.1",
"xml": "<ScreeningResults>...</ScreeningResults>",
"cases": [
{ "court_search_id": "CS40929433A", "offense_id": "34789896" }
],
"candidate_info": {
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2000-01-01",
"address": "123 Main St, Austin, TX 78701"
}
}
}
Full Request Body — XML with candidate overrides
Full Request Body — XML with candidate overrides
{
"record": {
"xml": "<ScreeningResults>...</ScreeningResults>",
"search_id": "76190bc0-e58c-494f-92c5-0c9a47389528",
"search_date": "2025-04-30",
"order_id": "41115779",
"order_number": "41115779.1",
"applicant_state": "CA",
"candidate_info": {
"first_name": "John",
"middle_name": "A",
"last_name": "Doe",
"date_of_birth": "1990-05-15",
"ssn": "123-45-6789",
"address": "123 Main St, Los Angeles, CA 90001"
},
"cases": [
{ "court_search_id": "CS40929433A", "offense_id": "34789896" }
],
"search_type": "Statewide_criminal"
}
}
Example Request (cURL / Python / JavaScript)
Example Request (cURL / Python / JavaScript)
curl -X POST "https://cra.pr.snh-ai.com/evaluate" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"xml": "<ScreeningResults><login><account>05022022</account><username>test</username></login><postResults order=\"12345\"><case><case_number>MJ-05003-TR-0006023-2020</case_number><offense_date>20200310</offense_date><jurisdiction_state>PA</jurisdiction_state><chargeinfo><charge>DRIVING WHILE OPERATOR PRIVILEGES SUSPENDED</charge><disposition>GUILTY</disposition></chargeinfo></case></postResults></ScreeningResults>",
"search_id": "76190bc0-e58c-494f-92c5-0c9a47389528",
"search_date": "2025-04-30",
"order_id": "41115779",
"order_number": "41115779.1",
"applicant_state": "CA",
"candidate_info": {
"first_name": "John",
"middle_name": "A",
"last_name": "Doe",
"date_of_birth": "1990-05-15",
"ssn": "123-45-6789",
"address": "123 Main St, Los Angeles, CA 90001"
},
"cases": [
{ "court_search_id": "CS40929433A", "offense_id": "34789896" }
],
"search_type": "Statewide_criminal"
}
}'
import requests
response = requests.post(
"https://cra.pr.snh-ai.com/evaluate",
headers={
"Authorization": "Bearer YOUR_JWT_TOKEN",
"Content-Type": "application/json"
},
json={
"record": {
"xml": "<ScreeningResults>...</ScreeningResults>",
"search_id": "76190bc0-e58c-494f-92c5-0c9a47389528",
"search_date": "2025-04-30",
"order_id": "41115779",
"order_number": "41115779.1",
"applicant_state": "CA",
"candidate_info": {
"first_name": "John",
"middle_name": "A",
"last_name": "Doe",
"date_of_birth": "1990-05-15",
"ssn": "123-45-6789",
"address": "123 Main St, Los Angeles, CA 90001"
},
"cases": [
{ "court_search_id": "CS40929433A", "offense_id": "34789896" }
],
"search_type": "Statewide_criminal"
}
}
)
result = response.json()
decision = result["data"]["decision"]
print(f"Search queue: {decision['search_queue']}")
for court in decision["court_decisions"]:
for case in court["case_decisions"]:
for offense in case["offenses"]:
print(offense["offense_id"], offense["charge_decision"], offense["routing"]["queue"])
const response = await fetch("https://cra.pr.snh-ai.com/evaluate", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_JWT_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
record: {
xml: "<ScreeningResults>...</ScreeningResults>",
search_id: "76190bc0-e58c-494f-92c5-0c9a47389528",
search_date: "2025-04-30",
order_id: "41115779",
order_number: "41115779.1",
applicant_state: "CA",
candidate_info: {
first_name: "John",
middle_name: "A",
last_name: "Doe",
date_of_birth: "1990-05-15",
ssn: "123-45-6789",
address: "123 Main St, Los Angeles, CA 90001"
},
cases: [
{ court_search_id: "CS40929433A", offense_id: "34789896" }
],
search_type: "Statewide_criminal"
}
})
});
const result = await response.json();
const decision = result.data.decision;
console.log(`Search queue: ${decision.search_queue}`);
for (const court of decision.court_decisions) {
for (const c of court.case_decisions) {
for (const offense of c.offenses) {
console.log(offense.offense_id, offense.charge_decision, offense.routing.queue);
}
}
}
Example Response — Success (200)
Example Response — Success (200)
{
"success": true,
"data": {
"search_id": "42198501",
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "success",
"errors": [],
"decision": {
"search_id": "42198501",
"decision_date": "2026-05-19T14:22:10Z",
"record_decision": "REPORTABLE",
"search_queue": "Auditor",
"order_id": "41115779",
"order_number": "41115779.1",
"ubs_search_type": "Statewide_criminal",
"court_decisions": [
{
"court_search_id": "TBD",
"court_decision": "REPORTABLE",
"court_queue": "Auditor",
"case_decisions": [
{
"case_number": "2024-CF-00312",
"case_decision": "REPORTABLE",
"case_queue": "Auditor",
"jurisdiction_state": "TX",
"id_match": {
"is_match": true,
"match_score": 0.925,
"name_score": 1,
"dob_score": 1,
"ssn_score": 0,
"address_score": 1,
"details": "Name/Alias Score: 100 % (Weight: 45 %)\nDOB Score: 100 % (Weight: 40 %)\nSSN Score: 0 % (Weight: 10 %)\nAddress Score: 100 % (Weight: 5 %)\nOverall Score: 92.5 % (Qualify: 85 %)"
},
"offenses": [
{
"offense_id": "40112987",
"charge": "THEFT OF PROPERTY >= $2,500",
"charge_decision": "REPORTABLE",
"rationale": "Conviction within 7-year lookback period. Felony conviction is reportable under FCRA and Texas state law.",
"type": "FELONY",
"disposition": "GUILTY",
"needs_human_review": false,
"cited_rules": [
"FCRA_CONV_NO_FEDERAL_LIMIT",
"TX_CONV_NO_STATE_LIMIT"
],
"citations": [
"15 U.S.C. § 1681c(a)(2) - No federal time limit on criminal convictions",
"Tex. Bus. & Com. Code § 20.05 - Texas has no state-specific conviction limit"
],
"routing": {
"queue": "Auditor",
"reportability": "Reportable",
"is_automatable": false,
"identity_level": "High",
"identity_score": 0.925,
"identity_insufficient": false,
"reportability_insufficient": false
}
}
]
}
]
}
]
},
"timing": {
"xml_transformer_ms": 1200.5,
"compliance_ms": 330.7,
"total_ms": 1850.3
}
},
"meta": {
"api_version": "2.0.0",
"process_time_ms": 1855,
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
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.Example Response — With Validation Issues (200)
Example Response — With Validation Issues (200)
validation object alongside the decision. The validation field is only present when issues exist:{
"success": true,
"data": {
"search_id": "40851153",
"correlation_id": "966f69b2-2855-4a67-b4f3-cd8b3da053c7",
"status": "success",
"errors": [],
"validation": {
"status": "needs_manual_review",
"issues": {
"errors": [
{
"level": "candidate",
"field": "subject_ssn",
"issue": "SSN is missing or could not be determined.",
"description": "SSN is required to confirm identity at the highest tier.",
"case_id": "",
"case_number": ""
},
{
"level": "offense",
"field": "disposition",
"issue": "Disposition is missing or could not be determined.",
"description": "Disposition drives reportability, so missing values force the charge to Insufficient Data.",
"case_id": "case-1",
"case_number": "J-1401-TR-200304452",
"offense_id": "34714104"
}
],
"warnings": [
{
"level": "offense",
"field": "type_class",
"issue": "Type class mismatch: rule='MISDEMEANOR', llm/cache='Other'",
"description": "The rule-engine classification takes precedence; this is informational.",
"case_id": "case-1",
"case_number": "J-1401-TR-200304452",
"offense_id": "34714104"
}
]
}
},
"decision": {
"search_id": "40851153",
"decision_date": "2026-03-31T20:22:36Z",
"search_queue": "Insufficient Data",
"order_id": "",
"court_decisions": [ "..." ]
},
"timing": {
"xml_transformer_ms": 22095.3,
"compliance_ms": 330.7,
"total_ms": 30016.1
}
},
"meta": {
"api_version": "2.0.0",
"process_time_ms": 30020,
"correlation_id": "966f69b2-2855-4a67-b4f3-cd8b3da053c7"
}
}
issues.errors— Hard data-quality problems (missing SSN, missing disposition, indeterminate charge classification). These typically force affected charges into theInsufficient Dataqueue, which then propagates up throughcase_queue,court_queue, andsearch_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.
Example Response — Partial (206)
Example Response — Partial (206)
status is partial and degradation is included. The errors array carries the engine-level failure messages:{
"success": true,
"data": {
"search_id": "42198503",
"correlation_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "partial",
"errors": [
"Compliance-Engine failed: read timeout after 30s"
],
"decision": {
"search_id": "42198503",
"decision_date": "2026-05-22T01:00:00Z",
"search_queue": "Auditor",
"order_id": "",
"court_decisions": [ "..." ]
},
"degradation": {
"xml_transformer": { "status": "available", "error": null },
"compliance_engine": { "status": "degraded", "error": "read timeout after 30s" }
},
"timing": {
"xml_transformer_ms": 1500.2,
"compliance_ms": 400.1,
"total_ms": 2100.5
}
},
"meta": {
"api_version": "2.0.0",
"process_time_ms": 2105,
"correlation_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
}
Example Response — Failed (court search ID / offense ID count mismatch)
Example Response — Failed (court search ID / offense ID count mismatch)
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:{
"success": false,
"data": {
"search_id": "76190bc0-e58c-494f-92c5-0c9a47389528",
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "failed",
"errors": [
"XML-Transformer HTTP error 422: Court search ID and offense ID counts do not match the XML: 17 court search ID(s) in the request but 24 case(s) in the XML; 22 offense ID(s) in the request but 32 offense(s) in the XML. Each court search ID must map to exactly one XML case and each offense ID to exactly one XML offense; resubmit with the complete set."
],
"degradation": {
"xml_transformer": {
"status": "failed",
"error": "Court search ID and offense ID counts do not match the XML: 17 court search ID(s) in the request but 24 case(s) in the XML; 22 offense ID(s) in the request but 32 offense(s) in the XML. Each court search ID must map to exactly one XML case and each offense ID to exactly one XML offense; resubmit with the complete set."
},
"compliance_engine": { "status": "not_called", "error": null }
},
"timing": {
"xml_transformer_ms": 120.5,
"compliance_ms": 0,
"total_ms": 125.0
}
},
"meta": {
"api_version": "2.0.0",
"process_time_ms": 130,
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
/transform-xml (HTTP 422):{
"status": "error",
"error_code": "CASE_OFFENSE_COUNT_MISMATCH",
"message": "Court search ID and offense ID counts do not match the XML: 1 court search ID(s) in the request but 2 case(s) in the XML; 1 offense ID(s) in the request but 3 offense(s) in the XML. Each court search ID must map to exactly one XML case and each offense ID to exactly one XML offense; resubmit with the complete set.",
"search_id": "99916916",
"details": {
"court_search_id_count": 1,
"xml_case_count": 2,
"offense_id_count": 1,
"xml_offense_count": 3,
"court_search_id_matches_cases": false,
"offense_id_matches_offenses": false
}
}
| Field | Example |
|---|---|
error_code | CASE_OFFENSE_COUNT_MISMATCH |
http_status | 422 |
details.court_search_id_count | 17 (evaluate example) / 1 (transform-xml example) |
details.xml_case_count | 24 / 2 |
details.offense_id_count | 22 / 1 |
details.xml_offense_count | 32 / 3 |
details.court_search_id_matches_cases | false |
details.offense_id_matches_offenses | false |
Validation
Thevalidation 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:
{
"validation": {
"status": "needs_manual_review",
"issues": {
"errors": [ { "level": "...", "field": "...", "issue": "...", "description": "...", "case_id": "...", "case_number": "...", "offense_id": "..." } ],
"warnings": [ { "level": "...", "field": "...", "issue": "...", "description": "...", "case_id": "...", "case_number": "...", "offense_id": "..." } ]
}
}
}
| Field | Type | Description |
|---|---|---|
level | string | Where the issue was found: candidate, case_subject, case, or offense |
field | string | The specific field that failed. Examples: subject_ssn, disposition, disposition_class, type_class |
issue | string | Short human-readable description |
description | string | Longer explanation of why the field matters |
case_id | string | Internal case identifier (empty for candidate-level issues) |
case_number | string | Associated case number (empty for candidate-level issues) |
offense_id | string | Offense identifier (only on offense-level items) |
errors vs warnings:errorsare hard data-quality problems — they typically force affected charges into theInsufficient Dataqueue, which then bubbles up throughcase_queue→court_queue→search_queue.warningsare 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
| Field | Example values | Notes |
|---|---|---|
search_id | "99908723", "76190bc0-e58c-494f-92c5-0c9a47389528" | Required — any non-empty string |
search_date | "2026-06-16", "2024-01-15" | Required — YYYY-MM-DD |
order_id | "789", "41115779" | Required — non-empty; top-level on record only; echoed in response |
order_number | "789.1", "41115779.1" | Required — non-empty; UBS format orderID.subOrderID; top-level on record only |
xml | "<ScreeningResults>...</ScreeningResults>" | Initial submission — mutually exclusive with record_json |
submission_type | "resubmit" | Required when record_json is present — top-level on record only |
record_json | { "criminal_search_results": [...] } | Resubmission — must not contain candidate_info, submission_type, order_id, or order_number |
candidate_info | { "first_name": "John", "last_name": "Doe", "date_of_birth": "2000-01-01", "address": "123 Main St, Austin, TX 78701" } | Required — non-empty; sibling on record for both XML and JSON paths — flat shape only |
candidate_info.first_name | "John" | Required — non-empty |
candidate_info.last_name | "Doe" | Required — non-empty |
candidate_info.date_of_birth | "2000-01-01" | Required — non-empty; YYYY-MM-DD |
candidate_info.ssn | "123-45-6789" | Any format (normalized internally) |
candidate_info.address | "123 Main St, Austin, TX 78701" | Single-line string — not addresses[] |
tenant_id | "UBS", "T001" | Optional |
applicant_state | "CA", "TX", "NC" | Optional — US state code |
cases | See matching example below | Optional — omit or [] to evaluate all. When non-empty, must map every court and offense (exact count match); partial subsets rejected |
cases[] (matching) | [{ "court_search_id": "A", "offense_id": "1" }, { "court_search_id": "A", "offense_id": "2" }, { "court_search_id": "B", "offense_id": "3" }] | 2 courts, 3 offenses — same counts as XML |
cases[].court_search_id | "CS40929433A", "A" | One row per offense; same ID may repeat across rows |
cases[].offense_id | "34789896", "1" | Total rows = total offenses in record |
cases[].is_excluded | true, false | Optional — defaults to false. When true, charge is excluded from response but still processed |
offense_ids | ["4628347", "48870"] | Deprecated — use cases |
search_type | "Statewide_criminal", "County_criminal" | Optional |
Response — envelope
| Field | Example values | Notes |
|---|---|---|
success | true, false | true for HTTP 200/206 when processing succeeded or partial |
data.status | "success", "partial", "failed" | Processing outcome |
data.errors | [], ["Compliance-Engine failed: read timeout after 30s"], ["XML-Transformer HTTP error 422: Court search ID and offense ID counts do not match the XML: ..."] | Service-level failures (timeouts, engine errors, court search ID / offense ID count mismatch) |
data.validation.status | "needs_manual_review" | Only present when data-quality issues exist; omitted when clean |
data.timing.total_ms | 2121, 1850.3 | Processing time in ms |
data.degradation.*.status | "available", "degraded", "unavailable", "failed", "not_called" | On partial/failed — e.g. compliance_engine: not_called when XT fails on cases[] |
meta.api_version | "2.0.0" | API version |
meta.correlation_id | "a1b2c3d4-e5f6-7890-abcd-ef1234567890" | Request trace ID |
200 success · 206 partial · 400 bad input · 422 validation · 500 failed
Response — decision labels (*_decision)
| Field | Example values | Notes |
|---|---|---|
offenses[].charge_decision | REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW | Per-offense — from compliance engine |
case_decisions[].case_decision | REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW | Derived from case_queue |
court_decisions[].court_decision | REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW | Derived from court_queue |
record_decision | REPORTABLE, NOT_REPORTABLE, MANUAL_REVIEW | Derived from search_queue |
*_queue value | *_decision value |
|---|---|
Automation | NOT_REPORTABLE |
Auditor | REPORTABLE |
Insufficient Data | MANUAL_REVIEW |
Response — routing queues (*_queue)
| Field | Example values | Rollup precedence |
|---|---|---|
search_queue, court_queue, case_queue, routing.queue | Automation, Auditor, Insufficient Data | Insufficient Data > Auditor > Automation |
Response — per-offense routing
| Field | Example values | Notes |
|---|---|---|
routing.reportability | Reportable, Not Reportable, Not Enough Info | Human-readable reportability |
routing.identity_level | High, Medium, Not Enough Info, Not Matching | From identity_score: ≥ 0.9 → High; 0.7–0.89 → Medium; ≤ −1 → Not Matching; else Not Enough Info |
routing.identity_score | 0.925, 0.85, 0.40 | 0–1 |
routing.is_automatable | true, false | true only when queue is Automation |
routing.identity_insufficient | true, false | Identity data too sparse |
routing.reportability_insufficient | true, false | Offense data too sparse |
routing.third_id_required | true, false | Third identity factor required |
needs_human_review | true, false | true when charge_decision is MANUAL_REVIEW |
Response — id_match (per case)
| Field | Example values | Notes |
|---|---|---|
is_match | true, false | From identity-match service |
match_score | 0.85, 0.925, 0.40 | Overall weighted score 0–1 |
name_score, dob_score, ssn_score | 0–1 typically | Component scores |
address_score | 1, 0, -1 | -1 when address was not scored |
details | "Name/Alias Score: 100 % ... Qualify: 70 %" | Human-readable breakdown |
Response — other offense fields
| Field | Example values | Notes |
|---|---|---|
offense_id | "48870", "40112987" | Charge identifier from source data |
charge | "Speeding", "THEFT OF PROPERTY >= $2,500" | Free text |
type, disposition | Echoed from the input record | Free text — see request examples |
cited_rules | ["GENERAL_TRAFFIC_NON_REPORT", "TX_CONV_NO_STATE_LIMIT"] | Rule IDs — not a fixed enum |
citations | ["15 U.S.C. § 1681c(a)(5)"], [] | Statute refs — often empty |
court_search_id | "111111", "TBD" | Vendor passthrough |
case_number | "2009D 008764" | Court case number |
Request — offense sentence (optional)
Omit sentence entirely when not applicable. When included, all fields below are optional.
| Field | Example values | Notes |
|---|---|---|
incarceration_date | "2009-02-15", null | YYYY-MM-DD or null |
release_date | "2010-01-15", null | YYYY-MM-DD or null |
is_serving | true, false | Whether the subject is currently serving this sentence |
Response — validation (when issues exist)
| Field | Example values | Notes |
|---|---|---|
validation.status | "needs_manual_review" | Omitted when data is clean |
issues.errors[].level | candidate, case_subject, case, offense | Where the issue was found |
issues.errors[].field | subject_ssn, disposition, disposition_class, type_class | Field that failed |
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):
record_decision + search_queue (record level)
└── court_decisions[]
├── court_decision + court_queue (court level)
└── case_decisions[]
├── case_decision + case_queue (case level)
├── id_match (identity match scores)
└── offenses[]
├── charge_decision (REPORTABLE | NOT_REPORTABLE | MANUAL_REVIEW)
├── rationale
├── cited_rules
├── citations
└── routing (queue, reportability, identity_level, ...)
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:
*_queue | *_decision |
|---|---|
Automation | NOT_REPORTABLE |
Auditor | REPORTABLE |
Insufficient Data | MANUAL_REVIEW |
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:
Insufficient Data(highest) — if any child queue isInsufficient DataAuditor— if any child isAuditor(and none areInsufficient Data)Automation(lowest) — every child isAutomation
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".Related
- Charge-Level Routing — Queue categories, routing matrix, and overrides
- Authentication — How to get JWT tokens
- Glossary — Decision values and compliance terminology
