Reference
Docs
Recordwire turns the official business registries of 12 U.S. states into one normalized API: every company on file, plus an append-only feed of the formations, name changes, status changes, moves, agent changes, and officer changes those states publish. These docs cover the record model, the six event payloads, every REST parameter, signed webhooks, and how to connect the MCP server. Base URL https://api.recordwirehq.com.
The model
One normalized record shape for every state. The ID combines the jurisdiction and the state’s own ID, for example US-VA:11406679.
legalName the registered business name
entityType llc | corporation | lp | gp | business_trust | public_service_authority | other
status active | inactive | pending_inactive
statusReason the state's own wording
formationDate YYYY-MM-DD
formationJurisdiction e.g. US-DE for a Delaware company registered here
principalAddress { street1, street2, city, state, postalCode }
mailingAddress { street1, street2, city, state, postalCode }
registeredAgent { name, address }
officers [{ name, title }] (titles verbatim per state)
industryCode the state's own code, where published (CT has NAICS)Every business also includes first_seen_at, changed_at, absent_since,source, and verified_at (the date of the last file that confirmed it). Fields depend on what each state publishes.
Six event payloads
Events are append-only. effective_at is when the state says it happened; observed_at is the date of the file we saw it in. Events include id, type, entity_id, both dates, and payload.
business.created
{ legalName, entityType, status, formationDate, formationJurisdiction }
effective_at = formation date (or file date when unknown)
business.name_changed
{ from, to } or a source-published change
business.status_changed
{ from: { status, statusReason }, to: { status, statusReason } }
business.address_changed
{ field: "principalAddress" | "mailingAddress", from, to }
business.agent_changed
{ from, to } (registered agent objects)
business.officers_changed
{ added: [{ name, title }], removed: [{ name, title }] }REST
Base URL: https://api.recordwirehq.com. Send Authorization: Bearer rk_live_.... JSON in and out; dates areYYYY-MM-DD. Lists return { data, next_cursor }; pass cursor back to page. Single-business responses use { data, next_cursor: null }.
GET /v1/businesses?jurisdiction=US-VA&formed_after=2026-09-01&status=active&entity_type=llc&q=acme&limit=50
GET /v1/businesses/US-VA:11406679
GET /v1/businesses/US-VA:11406679/events
GET /v1/events?type=business.created&jurisdiction=US-FL&since=2026-09-01&limit=100
GET /v1/events?observed_since=2026-09-07
GET /v1/sources/v1/sources returns each state’s last file date, last completed run, run count, and entity count. Keys may be restricted to states; asking for another returns 403.
| Parameter | Applies to | Meaning |
|---|---|---|
| jurisdiction | Businesses, events | State code, for example US-VA |
| formed_after / formed_before | Businesses | Inclusive formation-date bounds |
| status | Businesses | active, inactive, or pending_inactive |
| entity_type | Businesses | Normalized entity type, for example llc |
| q | Businesses | Case-insensitive legal-name prefix |
| type | Events | One of the six event types |
| since / until | Events | Inclusive effective-date bounds |
| observed_since | Events | Inclusive file-date bound; sorts by observed_at instead of effective_at |
| limit | Businesses, events, business events | Positive integer; default 50, maximum 500 |
| cursor | Businesses, events, business events | Opaque next_cursor from the previous page; keep filters unchanged |
Business lists sort by formation date descending, unknown dates last. Events sort by effective date descending unless observed_since is set. Invalid dates, limits, and cursors return 400; invalid keys return 401; missing businesses return 404. Rate limits return 429 with Retry-After: 60.
curl -H "Authorization: Bearer $KEY" \
"https://api.recordwirehq.com/v1/businesses?jurisdiction=US-VA&formed_after=2026-09-01&limit=3"Webhooks
A subscription pushes new change events to your HTTPS endpoint, so you do not have to poll/v1/events. Create one with POST /v1/subscriptions: a name, anhttps url, and optional filters jurisdictions, event_types, and entity_ids (up to 10,000 company IDs). States outside your key's scope return 400. The response includes a secret; it is shown once, so store it. Delivery starts with events recorded after the subscription is created.
curl -X POST "https://api.recordwirehq.com/v1/subscriptions" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name": "new LLCs", "url": "https://example.com/hooks/recordwire",
"jurisdictions": ["US-FL"], "event_types": ["business.created"]}'Every 5 minutes, Recordwire sends each subscription its new events in order, up to 500 per request, as a JSONPOST. Answer with any 2xx within 10 seconds. Anything else, a redirect, or a timeout counts as a failure, and the same batch is sent again on the next run, so handle an event ID you have already seen. After 20 failed batches in a row the subscription is disabled.
POST https://example.com/hooks/recordwire
Recordwire-Signature: t=1792857600,v1=5f0c...
Recordwire-Subscription: 12
{ "subscription_id": "12", "cursor": "88123", "events": [ { "id", "type", "jurisdiction",
"entity_id", "effective_at", "observed_at", "payload" }, ... up to 500 ] }Recordwire-Signature carries a Unix timestamp t and v1, the hex HMAC-SHA256 of t, a period, and the raw request body, keyed with your secret. Recompute it and compare before you trust the body.
import { createHmac, timingSafeEqual } from 'node:crypto';
// body: the raw request body as a string, before JSON.parse
function verify(body, header, secret) {
const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
const expected = createHmac('sha256', secret).update(`${parts.t}.${body}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}GET /v1/subscriptions lists your live subscriptions. GET /v1/subscriptions/{id}adds the last 10 delivery attempts with their status and error. DELETE /v1/subscriptions/{id}stops it. An account can hold 25 live subscriptions.
MCP
The same five operations, using the same key.
claude mcp add registry --transport http https://api.recordwirehq.com/mcp \
--header "Authorization: Bearer $KEY"search_businessesget_businessget_business_eventssearch_eventslist_sources