Back to blog
API integration exampleOctober 29, 2026·12 min read

API Integration Example for Business Entity Search

By The SOSfinder Team

API Integration Example for Business Entity Search

Finance is holding the vendor payout because nobody has confirmed the company is real, active, and represented by a registered agent. You're looking at an application that names a Delaware LLC and a street address, and the release clock is already running. A single search call can pull the official record, but the happy-path POST is only the start. A useful API integration example stores provenance, refuses a silent name match, and treats a valid credential as the first security boundary, not the last one.

The Entity Search Contract You Can Store

A payout rule needs fields it can evaluate consistently: whether the vendor exists, its registry status, and whether an agent is listed. SOSfinder covers all 50 states and the District of Columbia through one endpoint, with jurisdiction supplied as a request parameter. For a Delaware search, for example, send { "jurisdiction": "DE", "name": "Acme Holdings LLC" }. If the applicant has a state file number, send entity_id instead of name.

A normalized response may include status, entity type, formation date, registered agent, principal address, and entity ID. Treat those values as registry data, not a decision by themselves. Store the jurisdiction and record identifier with the result so a reviewer can trace which filing informed the decision. SOSfinder's business entity data is sourced from official state registries; the service itself is not a government agency.

Map each field to a hold or a pass

Define the fields your payout rules will read before you choose a client library. An inactive status or missing agent can stop onboarding; filing PDFs can be attached to the audit record when needed.

Field What it tells you Onboarding decision
Status Active, inactive, or other registry status Block payout if not in good standing
Entity type LLC, corporation, or other formation type Match the type the vendor claimed
Formation or registration date When the state recorded the entity Flag very new entities for extra review
Registered agent Agent name on the official filing Require a present agent before approval
Principal address Address returned with the record Compare with the address on the application
Related identifiers Entity ID and other registry keys Store the ID for later exact lookups
Similar filings Neighbor matches for a common name Keep for review; do not auto-approve
Filing history links Annual reports, amendments, and state PDFs where offered Attach for audit, do not block the first check

Persist the original query alongside the returned fields. If the API marks a result as best_match, treat that as a candidate, not proof of identity. Review similar filings before approving a common-name match, and keep the record ID available for an exact follow-up lookup.

A stable schema protects the rules built on top of it. If a status field changes meaning or disappears, a payout hold can fail unnoticed. Store the raw response as well as the fields your rules consume, and keep filing links with the audit record when the registry provides them.

How to Authenticate and Send One POST Search

A KYC or vendor check has one production path. Skip a step and the call still returns JSON, just JSON you can't defend later.

A four-step infographic illustrating how to securely authenticate and send a POST search for API integration.

The picture is the short version. The slips sit in the details.

  1. Create the credential server-side. Issue the key inside a registry product such as SOSfinder, and keep it off the browser. A public front end is the wrong place for a registry key. The common slip is pasting the key into a React env file that ships to every visitor.

  2. Store it where only the server can read it. An environment variable or a secret manager is enough if injection happens on the host that sends the request. Hard-coding the key in a repo, even a private one, is how it ends up in a ticket screenshot.

  3. Set a correlation ID on the outbound request. Tie the lookup to one tenant and one application before you leave your network. Dropping that ID means a later dispute is a pile of identical POSTs with no owner.

  4. Build one JSON body. Send jurisdiction plus either the entity name or the Entity ID. Use the ID when the applicant already has a state file number, and the name for first-time clearance. Omitting jurisdiction, or sending a name when you already hold a file number, is how you search the wrong registry.

  5. POST to the single search endpoint with a bounded timeout. I use about 10 to 15 seconds, because a live registry is slower than a cache hit. An unbounded client hangs the onboarding worker, and a two-second timeout fails healthy states.

  6. Read the best match and the similar-filings array as two objects. Don't fold the neighbors into the winner. Treating the best match as certain is the slip that auto-approves the wrong Acme.

  7. Persist before you decide. Write the original query, the candidates, the normalized record, the source jurisdiction, and the record identifier before any approve or deny. If you decide first and log later, a crash leaves a payout with no evidence.

Name clearance uses the same call earlier, before a formation filing, so a taken name doesn't become a rejected submission. Follow the authentication docs for the header shape, then keep the secret on the server that already owns step 2.

A usable success is narrow. You have one stored record, the correlation ID on that row, and an explicit uncertain flag when the similar-filings array isn't empty. A 200 with a pretty name and no stored identifier isn't done.

The Same Search in Five Languages

Use one shared call so the snippets stay comparable. A server handling a new merchant application searches Delaware for a name like Acme Holdings LLC. Every sample sends the same JSON body and reads the key from the environment, never from source control. Don't invent a second endpoint or a different schema per language.

What each client actually changes

cURL is the playground check. POST, a content-type header, the auth header, and the body, then pretty-print the JSON. If this fails, the other four will fail the same way.

Python uses requests, reads the key with os.environ, sets a timeout on the call, and parses with response.json(). The slip is forgetting the timeout argument, which defaults to waiting forever.

JavaScript uses fetch on the server in Node, process.env for the key, and response.json() for the body. Browser fetch would leak the key. If the route runs in the page, move it.

PHP uses curl or Guzzle, getenv for the key, and json_decode on the body. Check the HTTP status before you decode, or a gateway HTML page becomes a null you treat as "no entity."

Go uses net/http, os.Getenv, a timeout on the client, and json.Unmarshal into a small struct that matches the field table. A struct that drops unknown fields is fine. A struct that omits entity_id is not, because you just threw away the lookup key.

Language HTTP client Where the key lives How you read JSON
cURL curl Shell environment variable in the auth header Pipe to jq or parse in the app
Python requests os.environ response.json()
JavaScript fetch on the server process.env response.json()
PHP curl or Guzzle getenv json_decode on the body
Go net/http os.Getenv json.Unmarshal into a struct

After the table, each sample should print the same five values and nothing else on the first pass: status, entity type, registered agent, record identifier, and the count of similar filings. Printing the whole payload hides a missing agent inside a wall of address lines.

Run cURL first. When status, agent, and identifier look right, port the body unchanged into the language your onboarding service already runs. Changing the JSON while you change the client is how a working Delaware search becomes a validation error you blame on the library.

Retries Caching and Uncertain Matches

A 200 isn't the whole integration. Registries block, time out, and return several companies with nearly the same name. Split the outcome before you write a retry loop.

Outcome Retry What to store
Authentication failure No Correlation ID only; fix the server-side key
Validation error such as a bad jurisdiction No Request body and error text; correct the input
Temporary registry block or transport timeout Yes, with backoff and jitter Attempt count and last error
Successful single match No Normalized record, jurisdiction, record ID, cache age
Ambiguous name with similar filings No Uncertain state plus every candidate
Cached repeat of the same record No, unless the cache is stale Cached payload and its age

A diagram explaining API request handling, categorizing outcomes into failures, temporary issues, and uncertain matches.

Bad credentials and an invalid jurisdiction stop immediately. Validation errors are never retried. A second POST with the same bad state code only burns time.

Three cases that aren't a generic failure

Backoff. A temporary registry block or a transport timeout retries with exponential backoff and jitter. Waits of about 1, 2, and 4 seconds, plus random jitter, and a cap of three attempts, stay bounded even when the provider already retries some transient blocks. A client loop on top of that without a cap is how you stampede a slow state site. Read the rate limit notes before you pick the cap, and don't retry a 4xx you caused.

Cache age. A repeat lookup of the same record may reuse the stored row only while its cache age sits inside the team's window. Twenty-four hours is a reasonable onboarding window. A payout release should use zero and search again. Outside the window, the cached row is a hint, not a clearance. Store the age next to the payload so a reviewer can see it.

Uncertain matches. When similar filings sit beside the best match, write an uncertain result that lists every candidate. Don't pick the likeliest entity without saying so. Names collide, and a confident best_match: true is still a guess until a person or a file number confirms it.

If the search opens a ticket or triggers a charge, send a stable idempotency key derived from the application ID. A retry must not open a second case.

Imperva reported more than 40,000 API incidents across over 4,000 monitored environments in the first half of 2025, with 37% targeting data-access APIs and 32% targeting checkout or payment APIs. A lookup that can release money sits in both of those neighborhoods. Distinguish retryable transport failures from permanent validation errors, keep freshness on the row, and preserve the source jurisdiction and record identifier used for matching.

One endpoint shrinks the integration surface. It doesn't remove the need to say "we don't know which Acme this is."

Keeping Registry Data Inside the Tenant

A valid key only proves the server may call the registry API. It doesn't prove this user may see this company.

A hand-drawn illustration showing a developer facing an API authorization check error, highlighting tenant-level data permission issues.

That screen is what you want when tenant A asks for tenant B's vendor. Returning the record because the key worked is the mistake.

Checks that sit behind the key

Confirm the tenant owns the application before you return any field. The lookup id in the URL isn't proof of ownership.

Allowlist fields per role. Status and entity type are enough for a clerk. Registered agent and filings belong with compliance. A wider JSON "because the API sent it" is how officer names land in a general queue.

Keep agent, officer, address, and filing fields out of support UI dumps. A screenshot in a ticket is a copy you don't control.

Redact addresses and officer names in logs, and keep the correlation ID on the audit row. You can trace the call without reprinting the residence.

Reject replay of an old onboarding request once a decision is stored. A copied body from last quarter shouldn't reopen a cleared vendor.

Officer and UCC lookups, still in beta, stay behind the same allowlist rather than a wider response. Beta isn't a reason to skip the role check.

A 2025 Salt Labs survey of 206 professionals found that 99% had experienced API security issues in the previous 12 months. Production problems included injection and broken object-level authorization (37%), sensitive-data exposure (34%), and authentication weaknesses (29%). The same research found that 95% of observed API attacks originated from authenticated sources. A green auth check isn't a trust check.

Authenticate the integration, authorize the tenant, then minimize the record.

Watch the failure mode with the team before you argue about log levels. A short walkthrough makes the object check concrete.

I would start with the allowlist, not with a new auth scheme. Most leaks in this workflow are a valid server showing a full filing to the wrong role.

Confirm One Entity Then Subscribe to Changes

The search example is done when one known entity round-trips. Open the API playground, send the same POST the snippets use, and compare status, registered agent, and record ID with the state filing the team already trusts. Only after that match, point a webhook at a server route that accepts change notices for status, registered agent, or address.

  1. Verify the signature or shared secret before parsing the body. An unsigned notice is just another POST from the internet.
  2. Answer quickly with a 2xx and process the update afterward. Slow work inside the request is how you earn retries you didn't ask for.
  3. Match the notice to a stored record by jurisdiction and record identifier. Ignore notices you can't match.
  4. Apply an event only if its timestamp is newer than the stored cache timestamp. Notices can arrive out of order, and an older address must not overwrite a newer one.

Monitoring frequency depends on the plan. Don't promise instant alerts the plan doesn't include. Bulk CSV checks can wait until the single-record path is trusted. Business monitoring software is the layer you add after the first match, not instead of it.

Finish with two checks. Run one playground search, then one server-side POST for the same entity, and store the matched or uncertain result before you register the webhook. If those two disagree, fix the client. Don't subscribe to changes on a record you haven't pinned down.


SOSfinder gives product and compliance teams one REST search across Secretary of State records, with normalized status, agent, and filing fields you can store beside a vendor decision. Use it for the payout hold, the name check, and the later change notice once a single entity round-trips. Start with a playground search and a server-side POST at SOSfinder.

API integration exampleREST APIEntity searchError handlingWebhooks