Skip to content

County Verification API ​

County Verification searches the court records of a single county for a subject's criminal case history. Provide the subject's name and date of birth and the state and county to search. Each search is saved.

Unlike a real-time search, a county search is asynchronous: the request returns immediately with a processing status, and the records are available once the county search completes. You provide a webhookUrl and the finished search is sent to it when it completes; see Webhooks.

County Verification is available for enabled accounts. Contact your Infocus Info representative to enable the product and configure account pricing.

Authentication ​

All endpoints require an API key passed as a Bearer token in the Authorization header:

http
Authorization: Bearer your-api-key

The key must belong to an account with County Verification enabled. Saved searches belong to the account that placed them. All County Verification endpoint responses include Cache-Control: no-store.

A missing or invalid key returns 403 with an empty body.

Endpoints ​

MethodPathDescription
GET/county/coverageList the states and counties that can be searched
POST/county/searchPlace and save a search

Use https://api.infocusinfo.com as the base URL. The {id} path parameter is the searchId (a numeric string) or the uuid returned when the search is created.

Coverage ​

GET /county/coverage returns every state and county that can be searched, with the county names exactly as the API recognizes them. Use it to build state and county pickers or to check a county before submitting.

bash
curl "https://api.infocusinfo.com/county/coverage" \
  -H "Authorization: Bearer your-api-key"
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var request = HttpRequest.newBuilder(URI.create("https://api.infocusinfo.com/county/coverage"))
    .header("Authorization", "Bearer your-api-key")
    .GET()
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
csharp
using System.Net.Http;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.infocusinfo.com/county/coverage");
request.Headers.Add("Authorization", "Bearer your-api-key");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
http
GET https://api.infocusinfo.com/county/coverage
Authorization: Bearer your-api-key
json
{
  "states": [
    {
      "state": "TX",
      "counties": [
        { "countyId": 101, "county": "Harris" },
        { "countyId": 102, "county": "Travis" }
      ]
    }
  ]
}
http
POST /county/search

Send a JSON object with the following fields. The subject goes in subject, the same object an Instant Criminal Search takes (subject.alias is not supported on this search). A subject's first name, last name, and complete birth date are required, along with the state and county to search and a webhookUrl to receive the result.

Request Fields ​

FieldTypeRequiredDescription
clientRequestIdString (≤36 chars)NoYour own identifier for the request; echoed back in request.clientRequestId
subject.name.firstNameString (≤120 chars)YesSubject's first name
subject.name.middleNameString (≤120 chars)NoSubject's middle name
subject.name.lastNameString (≤120 chars)YesSubject's last name
subject.name.suffixStringNoName suffix, such as Jr
subject.birthDateObjectYesComplete, valid birth date as numeric year, month and day; year must be at least 1 and the date cannot be in the future
subject.ssnStringNoThe last four digits, or a full nine-digit SSN (NNNNNNNNN or NNN-NN-NNNN). Send a string to preserve leading zeros
genderStringNoMale or Female
stateStringYesTwo-letter state abbreviation, such as TX
countyStringYesCounty name from the coverage list. The County suffix is optional
searchYearsIntegerNoHow many years back to search, 0–99. 0 or omitted uses the default search period
clientCodeString (≤255 chars)NoYour own reference code for the search
specialInstructionsString (≤2000 chars)NoInstructions for the researcher performing the search
userIdString (numeric)NoConsole-only user attribution; requires the protected Console credential. Omit from ordinary API integrations
productIdString (numeric)NoCounty Verification product to bill against. Required only when your account has more than one
webhookUrlString (≤2048 chars)YesWhere the completed search is sent. Must be an absolute https URL that resolves to a public address. See Webhooks

A state and county outside the coverage list return a 400 error. The SSN is input-only: it is not echoed in responses or saved requests, and only its last four digits are retained on the search record.

Example ​

All identities and identifiers in these examples are synthetic.

bash
curl -X POST "https://api.infocusinfo.com/county/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
  "subject": {
    "name": { "firstName": "Jane", "lastName": "Doe" },
    "birthDate": { "year": 1980, "month": 1, "day": 2 }
  },
  "gender": "Female",
  "state": "TX",
  "county": "Travis",
  "searchYears": 7,
  "webhookUrl": "https://example.com/hooks/county"
}'
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var request = HttpRequest.newBuilder(URI.create("https://api.infocusinfo.com/county/search"))
    .header("Content-Type", "application/json")
    .header("Authorization", "Bearer your-api-key")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "subject": {
            "name": { "firstName": "Jane", "lastName": "Doe" },
            "birthDate": { "year": 1980, "month": 1, "day": 2 }
          },
          "gender": "Female",
          "state": "TX",
          "county": "Travis",
          "searchYears": 7,
          "webhookUrl": "https://example.com/hooks/county"
        }
        """))
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
csharp
using System.Net.Http;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.infocusinfo.com/county/search");
request.Headers.Add("Authorization", "Bearer your-api-key");
request.Content = new StringContent("""
    {
      "subject": {
        "name": { "firstName": "Jane", "lastName": "Doe" },
        "birthDate": { "year": 1980, "month": 1, "day": 2 }
      },
      "gender": "Female",
      "state": "TX",
      "county": "Travis",
      "searchYears": 7,
      "webhookUrl": "https://example.com/hooks/county"
    }
    """, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
http
POST https://api.infocusinfo.com/county/search
Content-Type: application/json
Authorization: Bearer your-api-key

{
  "subject": {
    "name": { "firstName": "Jane", "lastName": "Doe" },
    "birthDate": { "year": 1980, "month": 1, "day": 2 }
  },
  "gender": "Female",
  "state": "TX",
  "county": "Travis",
  "searchYears": 7,
  "webhookUrl": "https://example.com/hooks/county"
}

The response confirms the search was placed. The records are not available yet; they are sent to your webhookUrl when the search completes:

json
{
  "request": {
    "subject": {
      "name": {
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "birthDate": {
        "year": 1980,
        "month": 1,
        "day": 2
      },
      "alias": []
    },
    "state": "TX",
    "county": "Travis",
    "searchYears": 7
  },
  "result": {
    "offset": 0,
    "limit": 100,
    "hasMore": false,
    "size": 0,
    "data": []
  },
  "searchId": "16001",
  "uuid": "3f2b8c1e-9d4a-4c6b-8e1f-0a1b2c3d4e5f",
  "status": "processing",
  "message": "The county search is processing."
}

Search Response ​

Create operations and webhook deliveries return the same response structure.

Top-Level Fields ​

FieldTypeDescription
requestObjectThe request as saved, in the same shape you sent. The SSN and webhookUrl are never included
resultObjectThe court records found: offset, limit, hasMore, size and data, the same envelope an Instant Criminal Search uses. Empty until the search completes, and may be empty after
searchIdString (numeric)Saved search identifier
uuidStringSearch identifier that is also sent as the webhook-id header of the webhook delivery.
statusStringprocessing, completed, or error
messageStringOptional explanation for a processing state, empty result, or error

The state and county searched, as named in the coverage list, are in request.state and request.county.

Records ​

Each entry in result.data is one court record, shaped like an Instant Criminal Search result: name, alias and birthDate are the same objects, and physical details sit in offender. The subject's SSN is never returned. Fields with no value are omitted and lists are empty arrays.

FieldTypeDescription
caseNumStringCourt case number
sourceTitleStringThe court or source of the record
nameObjectName on the record: firstName, middleName, lastName and suffix
aliasArray of objectsOther names on the record, in the same shape as name
birthDateObjectDate of birth on the record as numeric year, month and day; parts not on the record are omitted
offenderObjectDescription on the record: age, sex, race, hair, eye, height, weight, scarsMarks and fullAddress
matchedByArray of stringsThe subject details the record matched on, such as FirstName, LastName, DateOfBirth
fileDate, arrestDate, dispositionDateStringCase dates
caseType, dispositionStringType of case and its disposition
defendantNames, plaintiffNamesArray of stringsParties on the case
offensesArray of objectsCharges on the case. See Offenses
commentsArray of stringsNotes on the case
attachmentsArray of objectsDocuments associated with the case, each with id, name, description, and viewUrl

Offenses ​

FieldTypeDescription
offenseDesc1, offenseCode, severity, levelStringThe charge as recorded after any reduction
originalOffense, originalStatute, originalSeverity, originalLevelStringThe charge as originally filed
pleaStringPlea entered
offenseDateStringDate of the offense
disposition, dispositionDateStringOutcome of the charge and its date
jailTime, jailTimeSuspended, jailTimeCreditStringJail sentence, suspended portion, and credit
probationTimeStringProbation sentence
prisonTime, prisonTimeCreditStringPrison sentence and credit
communityServiceTimeStringCommunity service sentence
fine, courtCostsStringFine and court costs
commentsArray of stringsNotes on the charge

Completed Search Example ​

The record below is abbreviated.

json
{
  "request": {
    "subject": {
      "name": {
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "birthDate": {
        "year": 1980,
        "month": 1,
        "day": 2
      },
      "alias": []
    },
    "state": "TX",
    "county": "Travis",
    "searchYears": 7
  },
  "result": {
    "offset": 0,
    "limit": 100,
    "hasMore": false,
    "size": 1,
    "data": [
      {
        "sourceTitle": "Travis County District Court",
        "caseNum": "D-1-DC-20-000000",
        "name": {
          "firstName": "Jane",
          "lastName": "Doe"
        },
        "birthDate": {
          "year": 1980,
          "month": 1,
          "day": 2
        },
        "alias": [
          {
            "firstName": "Jane",
            "lastName": "Smith"
          }
        ],
        "offender": {
          "age": 46,
          "sex": "Female",
          "race": "White",
          "hair": "Brown",
          "eye": "Green",
          "height": "5'6\"",
          "weight": "140",
          "fullAddress": "100 Example St, Austin, TX"
        },
        "matchedBy": [
          "FirstName",
          "LastName",
          "DateOfBirth"
        ],
        "fileDate": "2020-03-14",
        "caseType": "Felony",
        "disposition": "Convicted",
        "dispositionDate": "2020-09-30",
        "defendantNames": [],
        "plaintiffNames": [],
        "offenses": [
          {
            "offenseDesc1": "Theft of Property",
            "offenseCode": "31.03",
            "severity": "Felony",
            "level": "State Jail",
            "disposition": "Guilty",
            "dispositionDate": "2020-09-30",
            "probationTime": "2 years",
            "fine": "500.00",
            "comments": []
          }
        ],
        "comments": [],
        "attachments": []
      }
    ]
  },
  "searchId": "16001",
  "uuid": "3f2b8c1e-9d4a-4c6b-8e1f-0a1b2c3d4e5f",
  "status": "completed"
}

No Matching Records ​

A completed search with no matching records is completed, not an error, and is still billed.

json
{
  "request": {
    "subject": {
      "name": {
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "birthDate": {
        "year": 1980,
        "month": 1,
        "day": 2
      },
      "alias": []
    },
    "state": "TX",
    "county": "Travis",
    "searchYears": 7
  },
  "result": {
    "offset": 0,
    "limit": 100,
    "hasMore": false,
    "size": 0,
    "data": []
  },
  "searchId": "16002",
  "uuid": "7a91d2c4-5b3e-4f08-9c1d-2e6f8a0b3c47",
  "status": "completed",
  "message": "No matching county records."
}

Webhooks ​

A webhookUrl is required for County Verification. County searches always complete later, so the API replies as soon as the search is placed (HTTP 200, status: processing) and sends the finished search to your URL when the county completes it.

webhookUrl must be an absolute https URL, up to 2048 characters, without embedded credentials, whose host resolves to a public address (loopback, private, link-local, multicast, carrier-grade NAT, and IPv6 unique-local addresses are refused, as is a host that cannot be resolved). An invalid URL returns 400 with an error under webhookUrl. The URL is kept only to deliver the webhook; it is not echoed in responses or stored in the saved request.

Example ​

bash
curl -X POST "https://api.infocusinfo.com/county/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-api-key" \
  -d '{
  "subject": {
    "name": { "firstName": "Jane", "lastName": "Doe" },
    "birthDate": { "year": 1980, "month": 1, "day": 2 }
  },
  "state": "TX",
  "county": "Travis",
  "webhookUrl": "https://example.com/hooks/county"
}'
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var request = HttpRequest.newBuilder(URI.create("https://api.infocusinfo.com/county/search"))
    .header("Content-Type", "application/json")
    .header("Authorization", "Bearer your-api-key")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "subject": {
            "name": { "firstName": "Jane", "lastName": "Doe" },
            "birthDate": { "year": 1980, "month": 1, "day": 2 }
          },
          "state": "TX",
          "county": "Travis",
          "webhookUrl": "https://example.com/hooks/county"
        }
        """))
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
csharp
using System.Net.Http;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.infocusinfo.com/county/search");
request.Headers.Add("Authorization", "Bearer your-api-key");
request.Content = new StringContent("""
    {
      "subject": {
        "name": { "firstName": "Jane", "lastName": "Doe" },
        "birthDate": { "year": 1980, "month": 1, "day": 2 }
      },
      "state": "TX",
      "county": "Travis",
      "webhookUrl": "https://example.com/hooks/county"
    }
    """, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
http
POST https://api.infocusinfo.com/county/search
Content-Type: application/json
Authorization: Bearer your-api-key

{
  "subject": {
    "name": { "firstName": "Jane", "lastName": "Doe" },
    "birthDate": { "year": 1980, "month": 1, "day": 2 }
  },
  "state": "TX",
  "county": "Travis",
  "webhookUrl": "https://example.com/hooks/county"
}

The reply is the saved search in the processing state. Keep its uuid:

json
{
  "request": {
    "subject": {
      "name": {
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "birthDate": {
        "year": 1980,
        "month": 1,
        "day": 2
      },
      "alias": []
    },
    "state": "TX",
    "county": "Travis",
    "searchYears": 7
  },
  "result": {
    "offset": 0,
    "limit": 100,
    "hasMore": false,
    "size": 0,
    "data": []
  },
  "searchId": "16001",
  "uuid": "3f2b8c1e-9d4a-4c6b-8e1f-0a1b2c3d4e5f",
  "status": "processing",
  "message": "The county search is processing."
}

Placement problems (validation, product access, account checks) are reported immediately with the usual 400, 403, 404, or 503, before anything is accepted.

When the search finishes, the API sends a POST to your URL with the same body as the create response, including status (completed or error). The request follows the Standard Webhooks specification and carries these headers:

HeaderDescription
webhook-idThe search's uuid. Identical on every retry, so use it to de-duplicate
webhook-timestampUnix time in seconds of the attempt
webhook-signaturev1, plus the base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the API key that placed the search

Respond with any 2xx status to acknowledge. Other responses, timeouts (10 seconds), and connection errors are retried after 1 minute, 5 minutes, 15 minutes, 1 hour, 4 hours, 12 hours, and 24 hours, after which the API stops. Delivery is at least once, and redirects are not followed. If the API key that placed the search has since been revoked or has expired, the delivery cannot be signed and is abandoned without retries. See Verifying a webhook for signature code samples.

A search that cannot be completed is delivered with status: error. A county search is finished by the provider's order rather than a background job, so it is not affected by an API restart: the API keeps checking the order until it completes. Searches are never re-sent to a provider automatically. Billing is unchanged: a search is billed once, when it completes.

Validation and Errors ​

HTTP Response Codes ​

CodeDescription
200A search response returned. Inspect status to distinguish processing, completion, and failure. A search the provider rejects when the order is placed is also a 200 with status: error
400Invalid fields (including a missing or invalid webhookUrl), a state or county outside coverage, or malformed JSON; includes an errors object keyed by field or request category
403Missing or invalid API key, County Verification is not enabled for the account, or console-only attribution is not authorized
404County Verification product or saved search not found, invalid search ID, or search is not owned by the account
500Unexpected request failure
503The search service is not configured

Errors other than field validation use these keys in the errors object:

KeyMessageCode
requestMalformed request.400 (invalid JSON or a field of the wrong type)
userIdInvalid user ID.400
accessThis search product is not enabled for this account.403
searchNot found.404
searchCounty verification is not configured.503
searchThe request could not be completed.500

For example, a county outside coverage returns HTTP 400:

json
{
  "errors": {
    "county": "County is not covered. See the coverage list for supported states and counties."
  }
}

A request missing required fields returns every problem at once:

json
{
  "errors": {
    "lastName": "Last name is required.",
    "birthDate": "Enter a valid complete date of birth (year, month and day).",
    "state": "State is required.",
    "county": "County is required."
  }
}

Search-Level Failure ​

A search that could not be placed, or that the county could not complete, has a persisted search whose status is error. The status can appear on the create response, in the webhook delivery, so check it every time:

json
{
  "request": {
    "subject": {
      "name": {
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "birthDate": {
        "year": 1980,
        "month": 1,
        "day": 2
      },
      "alias": []
    },
    "state": "TX",
    "county": "Travis",
    "searchYears": 7
  },
  "result": {
    "offset": 0,
    "limit": 100,
    "hasMore": false,
    "size": 0,
    "data": []
  },
  "searchId": "16003",
  "uuid": "c04e6b79-1d2a-4a35-b8f0-91d7e3a5c612",
  "status": "error",
  "message": "The county search could not be completed. No automatic retry was made."
}

Billing and Retries ​

A search is billed once, when it completes, at the account's price when the order is written: its active price override, otherwise the product price. This includes completed searches with no matching records. A search that ends in error is not billed.

There is no automatic retry and no request-level idempotency key: submitting another POST /county/search places another search and can incur another charge. If a request is interrupted, do not automatically resubmit it; the search may already have been placed. If you received a searchId, the search was placed, and its result is sent to your webhook if you set one.