What Fields Does a Secretary of State API Return? A Developer Reference

August 7, 2026
August 7, 2026
15 Minutes Read
Business Verificationblog main image

Executive Summary: A Secretary of State API returns two things: an envelope that tells you whether the lookup finished, and a results array that tells you what the state holds on the entity. Most integration defects trace back to a team that read the second and skipped the first. This reference walks the documented response for Cobalt's SOS Search endpoint field by field, says what each field can carry, what it cannot, and how to type it so your underwriting logic does not treat a silent state as a negative answer. Precision matters here because the fields feed decisions with money attached. In a Celent survey of 115 U.S. financial institutions published May 7, 2026, 93 percent of lenders said fraud contributes to their credit losses and 82 percent reported fraud losses rose year over year, with synthetic identity fraud at 61 percent, bust-out fraud at 56 percent, and application stacking at 55 percent named as the fastest-growing types.[1] Every one of those patterns is detectable, or missable, at the field level. This post stays in the response body. If you are deciding whether to buy the category at all rather than mapping a schema this week, read what an entity validation API actually validates first.

What Does the Response Envelope Return Before You Reach the Results Array?

The envelope is the part of the payload that describes the lookup itself. It exists because an SOS lookup is not a database read against Cobalt's own store when `liveData=true`; it is a live retrieval from a state system that may be slow, may be down, or may be charging for the record. The envelope is where that reality surfaces.

Which Envelope Fields Are Documented?

The published example response carries these top-level keys alongside the results:

`status`. A lifecycle value for the lookup. The documented example returns `"complete"`, and this is the field your retry loop reads, not the HTTP code.

`statusCode`. An integer mirroring the HTTP result. The documented example returns `200`, which RFC 9110 defines as "The request succeeded. The result meaning of 'success' depends on the HTTP method."[2]

`message`. A human-readable string. The documented example returns `"Search completed successfully"`. Log it, do not branch on it.

`requestId`. A correlation identifier for the individual call, documented in the example as `"abc123-def456"`.

`nameAvailable`. A boolean indicating whether the business name is still available for registration in that state, which is a proxy for whether an entity of that name exists in state records.

`results`. The array of matched entity objects, covered in the sections below.

`possibleAlternatives`. Up to ten close matches returned when the exact match is uncertain, empty in the clean-match example.

`retryId`. Not present in the clean example. It appears on lookups that exceed the async threshold, and the documented integration pattern reads `data.retryId` to decide whether to poll.

Why Should the Retry Branch Read `status` Instead of `statusCode`?

Because they answer different questions. `statusCode` tells you the API served your request. `status` tells you whether the state finished answering it. A long-running state can produce a well-formed served response that carries no entity data yet, the same distinction RFC 9110 draws for 202, where "the request has been accepted for processing, but the processing has not been completed."[2] Cobalt's documented polling loop branches on `retryData.status === 'complete'`, and that is the condition to copy.

One casing trap costs an afternoon when it bites. The main documented response example returns `"status": "complete"` in lowercase, while the Find Related Businesses example returns `"status": "Complete"` capitalized. Compare case-insensitively rather than against a single literal, and confirm the observed casing in your sandbox before you ship the comparison.

Which Fields Identify the Entity, and What Can Each One Prove?

The identity block is the smallest reliably present set of fields, and the set your loan documents depend on.

What Do the Four Core Identity Fields Carry?

FieldDocumented contentUnderwriting use
`title`Legal business name as registered with the state, returned uppercased in the documented example as `"ACME CORPORATION"`The exact legal name for loan documents. A mismatch against the application is a name-normalization question before it is a fraud question.
`filingDate`Date of formation or registration, documented as `"2015-03-15"`Time in business, which for most alternative lenders is a hard cutoff rather than a scored input.
`entityType`Corporation, LLC, Partnership, and similarEntity structure verification, and a gate on which signature authority you should expect to see.
`stateOfFormation`The state where the entity was originally formed, documented as `"Delaware"`Identifies a foreign registration, meaning the entity operates somewhere other than where it was formed.

`filingDate` in the documented example follows the RFC 3339 full-date production, `full-date = date-fullyear "-" date-month "-" date-mday`, the unambiguous YYYY-MM-DD ordering.[3] Parse it as a date rather than a string, and do the time-in-business arithmetic in your own code against your own clock.

How Should You Treat `title` When It Does Not Match the Application?

Treat the registry name as the authority and the application as the claim, because the registry name is the one a court will use. Run a normalization pass before you compare: uppercase both sides, strip punctuation from the suffix, and treat "LLC" and "L.L.C." as equal. Whether that comparison should run against an exact-identifier retrieval or a fuzzy name search is a real design fork, worked through in company lookup API versus company search API.

What Does the Status Field Return Across Fifty-One Jurisdictions?

`status` is the single field most likely to be wired directly into an automated decline, which makes it the field most worth slowing down on.

What Is the Difference Between `status` and the Normalized Status?

The documented response returns a `status` value, shown as `"Active"` in the example, described as the registration status with values including Active, Inactive, and Dissolved. Separately, the documented data points list includes a normalized status, standardized across all states, on the stated ground that states return wildly different formats and that "Active" in one state is "In Good Standing" in another.

The honest handling for a developer reference: the normalized status is documented as a returned data point, but it carries no key in the published example JSON. Do not guess the key name and do not write a mapping against a field you have not seen in a live payload. Call the endpoint in your sandbox, print the raw object, and bind to the key you observe. The same applies to the confidence score and the entity subtype, both listed as data points without a key in the example.

Why Do Status Strings Diverge So Widely Between States?

Because the grounds are statutory and the statutes differ. Nebraska lists dissolution for "failure to file an annual/biennial report with our office, maintain a registered agent, or the corporate existence has expired."[4] Texas runs a separate tax track where an involuntarily terminated entity "is considered to have continued in existence without interruption only if it is reinstated before the third anniversary of the date of its involuntary termination."[5] California attaches its own consequence to a missed filing, stating that failure to file the required Statement of Information "may result in penalties being assessed by the Franchise Tax Board and suspension or forfeiture."[6]

Three states, three vocabularies, three remediation clocks. Per-state string meanings are already documented at the state level, including the Alabama business entity status definitions page, and the cross-state interpretation workflow lives in how to read registration statuses across states via API. This reference defines nothing further beyond the field itself.

What Is Inside the Registered Agent Block?

`registeredAgent` is a nested object rather than a flat string, and the documented shape is a name and address pair.

"registeredAgent": {
  "name": "CT Corporation System",
  "address": "1209 Orange St, Wilmington, DE 19801"
}

Why Is the Agent Field Structurally Reliable?

Because keeping it current is a condition of staying registered. Nebraska names failure to maintain a registered agent as an independent ground for administrative dissolution, sitting alongside the annual report failure.[4] An entity that intends to keep its registration has a standing reason to keep this field accurate, which is not true of every field in the record.

What Should Your Parser Do With the Address String?

Expect one string rather than a structured address. The documented example returns `"1209 Orange St, Wilmington, DE 19801"` as a single value, so if your risk model needs a ZIP or a state code from the agent address, you are writing a parser and should write it defensively. Points worth handling before you go live:

Comma count varies. Suite lines, county lines, and missing ZIP+4 all change the token count between records.

Commercial agents dominate certain states. A national commercial agent name repeats across thousands of unrelated entities and carries no entity-specific signal by itself.

Agent address equal to `physicalAddress` is common for small operators and legitimate, but it collapses two of your independent address checks into one.

A missing agent block is not proof of a missing agent. It may be a state that does not expose the field in the record Cobalt retrieves.

Cross-applicant repetition is the signal worth building. The same non-commercial agent appearing across several unrelated applications in a short window is the pattern that pays for the parser.

The Find Related Businesses beta addresses that last pattern at the response level, covered below.

What Do the Officer and Address Fields Return, and Where Do They Go Missing?

`officers` is an array of objects, each documented with `name`, `title`, and `address`. Alongside it sit two flat address fields, `physicalAddress` for the principal business address and `mailingAddress` for correspondence.

What Can the Officer Array Legitimately Support?

It supports the control side of customer due diligence. Under 31 CFR 1010.230, a beneficial owner includes "a single individual with significant responsibility to control, manage, or direct a legal entity customer, including: An executive officer or senior manager," and the same rule separately requires each individual who "owns 25 percent or more of the equity interests."[7] A registry officer array can corroborate the first. It cannot answer the second, because state registries do not publish equity percentages, and no amount of field mapping will produce a number the source does not hold.

Which States Actually Publish Officers?

This is the sharpest field-availability split in the whole response, and it is verifiable from the state sources directly. North Carolina's business registration division exposes search by "Company Officials" and by "Registered Agents" as first-class search modes, so officer data is part of the public record there.[8] Delaware's entity search returns "entity name, file number, incorporation/formation date, registered agent name, address, phone number and residency," and officers and directors are not among them.[9]

Cobalt's documented limitation matches those two pages: officer data availability varies by state, and Cobalt returns whatever the state makes available. The consequence for your model is direct. If a missing `officers` array scores as a negative signal, every Delaware applicant inherits a penalty produced by Delaware's disclosure policy rather than by anything the borrower did. Model the absence as unknown and route it, rather than scoring it.

Which Fields Carry the Audit Trail Your Examiner Will Ask For?

Three fields exist for the file rather than for the decision, and they are the ones most often dropped during integration because nothing downstream reads them on the happy path.

What Do `sosUrl`, `screenshotUrl`, and `requestId` Each Prove?

`sosUrl` is the direct URL to the state's own SOS record, the source-verification link a reviewer will follow. `screenshotUrl` returns a timestamped screenshot of the state webpage, watermarked with the date and time of verification and carrying no Cobalt watermark on the image itself. `requestId` ties the full response to a log line, which is what makes a decision defensible months later.

The retention obligation is what makes storing them a design requirement instead of a preference. Financial institutions must keep required records for "a period of five years," and those records must be:

"filed or stored in such a way as to be accessible within a reasonable period of time, taking into consideration the nature of the record, and the amount of time expired since the record was made."[10]

Cobalt's screenshot URLs are valid for download for roughly three to thirty days, and customers must download and store the image in their own system of record. A five-year retention duty and a thirty-day URL do not reconcile on their own. Fetch the image inside the same job that writes the decision, store the bytes, and persist the `requestId` beside them.

What Should You Persist Beyond the Screenshot?

Persist the whole response object rather than the fields you currently use. The cheapest version is a raw JSON column written before parsing, keyed on `requestId`. When an examiner asks in 2029 about a field your 2026 schema discarded, the raw payload is the only thing that answers it.

How Should You Type Nullability and Confidence in Your Own Schema?

State variance is a typing problem before it is a policy problem, and typing it wrongly is how the policy problem gets created.

Why Does Null Have to Mean Unknown?

Because in this domain absence is a statement about the state, not about the entity. JSON Schema draws the line explicitly, noting that "in JSON, `null` isn't equivalent to something being absent," and it provides separate mechanisms for the two cases.[11] Carry that distinction all the way into your risk model. A three-state representation, present, absent-from-source, and not-requested, keeps your decision logic honest in a way a nullable string cannot.

A typing derived from the documented example, using only documented fields:

interface SosResult {
  title: string;
  filingDate: string | null;        // RFC 3339 full-date when present
  stateOfFormation: string | null;
  status: string;                   // raw state string
  entityType: string | null;
  registeredAgent: { name: string; address: string } | null;
  officers: Array<{ name: string; title: string; address: string }>;
  physicalAddress: string | null;
  mailingAddress: string | null;
  sosUrl: string | null;
  screenshotUrl: string | null;     // only when screenshot=true
}

Every field except `title` and `status` is optional in practice, and `officers` should default to an empty array rather than to null so that iteration never throws on a non-disclosing state.

How Should the Confidence Score Drive Routing?

The documented behavior is a score from 0.0 to 1.0 on every result, with three documented bands: 0.8 to 1.0 as a high confidence match that most customers auto-accept, 0.5 to 0.79 as moderate confidence flagged for human review, and below 0.5 as a likely different entity. Build the threshold as configuration rather than as a constant, because the right cut point depends on the cost asymmetry in your book, and a false negative on a real borrower is not priced the same as a false positive on a shell. Pair the mid-band route with `possibleAlternatives`, which hands a reviewer a shortlist of up to ten close matches instead of sending them to a state website. Which fields your specific state mix will actually populate is mapped in the SOS API data coverage by state checklist.

Which Fields Only Appear When You Ask for Them?

Several fields are parameter-conditional. They are absent by default, and treating their absence as a data gap is a misread of your own request.

Which Parameters Add or Change Fields?

`screenshot=true` produces the `screenshotUrl` field. Without it there is no screenshot to store, and the audit trail described above does not exist.

`liveData` governs freshness rather than shape. Live mode pulls from the state source in ten to one hundred eighty seconds; cached mode answers in under a second against a monthly refresh.

`callbackUrl` moves the result delivery to your webhook for states that exceed the async threshold.

`retryId` retrieves a previous async result and is the one case where the `state` parameter is not required.

`findRelatedBusinesses=true` adds a `relatedBusinesses` object to the response, containing `byOfficer` and `byAgent` arrays.

`test` returns fixture responses for the values `complete`, `incomplete`, `failed`, `retryIdInvalid`, and `badRequest`, which is how you build error handling without live lookups.

What Does the `relatedBusinesses` Object Actually Contain?

Each entry under `byOfficer` or `byAgent` carries a true or false address match indicator showing whether the related entity's address matches the address returned for the original result, which separates same-location relationships from name-only ones. Name matching runs two passes: an exact pass on the uppercased name, then a normalized pass that strips middle initials and suffixes such as JR, SR, II, and III and reduces to first and last name, so "JOHN F KENNEDY" and "JOHN KENNEDY" both match. Corporations listed as registered agents are filtered out and are almost always excluded from results.

Two limitations belong in your integration notes. The feature is in beta, response times increase by one to two seconds at the top end, and its behavior may change, so treat its output as a review trigger rather than a decision input. Separately, response time is state-dependent in a way no parameter fixes: most states return in ten to thirty seconds, Delaware in fifteen to thirty, and Oregon can take up to five minutes on a live lookup. Oregon's registry page shows why, listing a one to three business day processing window for online Business Registry filings.[12] A state that batches its own intake cannot be made real-time by an API in front of it.

Which States Cost Extra to Read?

Two, per the documented limitations, and both are state-imposed rather than Cobalt charges. Delaware entity status requires a paid request of 10 or 20 dollars depending on the tier, passed through at cost: the state's own fee page lists a 10 dollar option returning current status and a 20 dollar option adding the last 5 filings, franchise tax assessment, and total authorized shares.[14] New Jersey status data is restricted by statute with a small fee attached, and New Jersey routes standing certificates and status reports through a dedicated Division of Revenue business records service rather than a free public search.[13] Budget for both, because a national applicant mix hits them regularly.

The async retrieval pattern, for the states that need it:

const response = await fetch('/v1/search?searchQuery=Acme&state=oregon&liveData=true');
const data = await response.json();

if (data.retryId) {
  const checkResults = async () => {
    const retry = await fetch(`/v1/search?retryId=${data.retryId}&state=oregon&screenshot=true`);
    const retryData = await retry.json();
    if (retryData.status === 'complete') return retryData;
    await new Promise(r => setTimeout(r, 5000));
    return checkResults();
  };
  return await checkResults();
}

The webhook alternative to that polling loop, including delivery guarantees and retry semantics, is covered in async webhook architecture for SOS lookups and is not restated here.

Where this check sits relative to the tax identifier, lien, and sanctions steps is laid out in the best KYB APIs for lending risk assessment, and the wider provider landscape is in the top Secretary of State API solutions for verifying businesses. For the operational sequence of running the check rather than parsing it, see how to verify business registration status via API, and for the rest of the product line, what services Cobalt Intelligence offers.

The pattern across all of these fields is the same one. The response is faithful to fifty-one registries that were never designed to agree with each other, and the fields that are always present are the ones every registry was legally required to create. Everything past that core is a disclosure choice made by a state legislature, which means the useful question for an integration engineer is which of these fields your specific state mix will actually populate. Answer that in a sandbox against your own applicant distribution before you write a single scoring rule, and the fields will hold up under the decisions you hang on them.

References

1. Fraud is Surging Across Consumer Lending as 93% of Lenders Report Credit-Loss Impact, Zest AI and Celent

2. RFC 9110: HTTP Semantics, Internet Engineering Task Force

3. RFC 3339: Date and Time on the Internet: Timestamps, Internet Engineering Task Force

4. Reinstatement Information, Nebraska Secretary of State

5. Terminations and Reinstatements FAQs, Texas Secretary of State

6. Statements of Information Filing Requirements, California Secretary of State

7. 31 CFR 1010.230 Beneficial Ownership Requirements for Legal Entity Customers, U.S. Code of Federal Regulations

8. Business Registration Division, North Carolina Secretary of State

9. General Information Name Search, Delaware Division of Corporations

10. 31 CFR 1010.430 Nature of Records and Retention Period, U.S. Code of Federal Regulations

11. null, JSON Schema

12. Find a Business, Oregon Secretary of State

13. Business Records Service, New Jersey Division of Revenue and Enterprise Services

14. Online Status, Delaware Division of Corporations