Search¶
Search official government registries for a company, or look up a fund on GLEIF. Searches are asynchronous: you submit a request, receive a searchId (and caseId), then poll until the work finishes.
A successful corporate search creates a new case and sets case.target to the found company. A successful fund search creates a new case and sets case.target to the fund; the fund manager is a counterparty. To dig into a counterparty already on a case (ownership tree), use Expand search. Fund search may start that expand on the manager automatically.
Submit a company search¶
Request¶
Headers
| Header | Value |
|---|---|
Content-Type |
application/json |
X-API-Key or Authorization |
rev_… or Bearer <idToken> |
Body
| Field | Type | Required | Description |
|---|---|---|---|
target_type |
string | No | Omit or "corporate" for a registry search. "fund" selects Submit a fund search. |
identifier |
string | Conditional | Registry registration number / search id. Required for most jurisdictions. |
legal_name |
string | Conditional | Legal name. Required (instead of or in addition to identifier) for name-based jurisdictions (e.g. ID, MX, IQ, and others whose coverage schema lists legal_name without a required identifier). |
jurisdiction |
string | Yes (corporate) | Jurisdiction code (e.g. GB, DE, US-DE, CH-ZH). Not required for fund search. |
include |
object | No | Optional add-ons |
include.financials |
boolean | No | Request financial metrics when the jurisdiction supports them. Extra credits only if financials data is returned. |
Info
At least one of identifier or legal_name is required, depending on the jurisdiction’s search schema. If both are missing, or only a name is sent for an identifier-only jurisdiction, the API returns 400.
Immediate response (200)¶
A search record with status: "PENDING":
{
"_id": "abc123searchId",
"caseId": "xyz789caseId",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:00.000Z",
"userId": "user-uid",
"searchInputs": {
"identifier": "HRB 246975",
"jurisdiction": "DE",
"include": { "financials": true }
},
"status": "PENDING"
}
| Field | Type | Description |
|---|---|---|
_id |
string | Search ID. Use this to poll status. |
caseId |
string | New case grouping this search (and later expands / LEI lookups) |
status |
string | PENDING, COMPLETED, or FAILED |
searchInputs |
object | Echo of accepted search parameters |
userId |
string | Owner uid |
createdAt / updatedAt |
string | ISO 8601 timestamps |
Work continues in the background. Poll Get search status.
Error responses¶
Credits¶
- The jurisdiction search cost is debited up front when the search is accepted.
- On scrape / processing failure, that cost is refunded.
include.financials: charged after success only if numeric financials came back. A charge failure is logged and does not roll back the search.
You must be subscribed to the jurisdiction and have enough volume_remaining.
Submit a fund search¶
Look up a fund by exact legal name on GLEIF. The case target is the fund. The fund manager is a counterparty with natureOfRelationship: "Fund Manager".
jurisdiction is not required. GLEIF supplies the fund and manager jurisdictions. Extra corporate fields (identifier, jurisdiction, include) are ignored.
The fund search is not billed. Work runs as a Cloud Task (processFundSearchTask) after the PENDING write, so GLEIF and the manager follow-on are not tied to the HTTP request lifetime.
After GLEIF names a fund manager:
- Path A — the manager's jurisdiction has a registry handler (and is not the US): an expand search may start as a second search on the manager. That expand uses the existing expand pipeline and bills the manager jurisdiction through
consumeVolume. Auto-expand is registry-only (noinclude.financials). - Path B — the manager is registered in the US (including
US-DEand other state codes), or the jurisdiction has no registry handler (for exampleKY): a US state registry expand is not started. An expand search still starts on the manager (searchType: "expand",entityId= manager). That expand looks up the manager's legal name on Investment Adviser Public Disclosure and grafts Form ADV owners under the manager. It does not overwritecase.target. IAPD expand is not billed. A no-match still leaves the fund searchCOMPLETEDwith the GLEIF manager on the graph.
Request¶
Body
| Field | Type | Required | Description |
|---|---|---|---|
target_type |
string | Yes | Must be "fund". |
legal_name |
string | Yes | Exact fund legal name (GLEIF entity.legalName). |
Optional development_mode: true is stored on the fund search and forwarded to expand. It has no GLEIF meaning.
Immediate response (200)¶
A search record with status: "PENDING" and searchType: "fund":
{
"_id": "fundSearchId",
"caseId": "caseId",
"createdAt": "2026-08-25T12:00:00.000Z",
"updatedAt": "2026-08-25T12:00:00.000Z",
"userId": "user-uid",
"searchType": "fund",
"status": "PENDING",
"searchInputs": {
"target_type": "fund",
"legal_name": "Fundsmith Reserve Fund"
}
}
Work continues in the background. Poll Get search status on this fund search id. That status never includes the expand or IAPD result. Those have their own search ids. The case snapshot is the join.
What the case becomes¶
After GLEIF (Fundsmith example):
case.targetis the fund (legalNameFundsmith Reserve Fund,jurisdictionKY, LEI9845005FH3C0B3C9F726, identifier1632831).case.target.counterparties[0]is the manager (legalNameFUNDSMITH INVESTMENT SERVICES LIMITED,jurisdictionMU, LEI213800YINPPN97G4IU14, identifierC123910).- That counterparty's relationship is
{ _parentId: <fund._id>, natureOfRelationship: "Fund Manager" }. searches/{fundSearchId}isCOMPLETEDwithresultequal tocase.target.- Fund
searchInputsstill have no jurisdiction. Fund KY and manager MU live on the entities.
Then, if the manager jurisdiction has a handler and is not the US and you are subscribed to it, a second search appears on the case:
{
"searchType": "expand",
"entityId": "<manager._id>",
"status": "PENDING",
"searchInputs": {
"identifier": "C123910",
"jurisdiction": "MU",
"legalName": "FUNDSMITH INVESTMENT SERVICES LIMITED"
}
}
That record is the existing expand pipeline. It grafts under the manager. It does not overwrite case.target.
If the manager is US, or there is no registry handler, Path B writes a second expand instead of a registry search:
{
"searchType": "expand",
"entityId": "<manager._id>",
"status": "PENDING",
"searchInputs": {
"identifier": "ACME ADVISERS LLC",
"regulator": "IAPD",
"legalName": "ACME ADVISERS LLC"
}
}
That record is the existing expand pipeline. The scraper is search-iapd, not a state registry. A match grafts Form ADV owners under the manager. It does not overwrite case.target.
If Path A is blocked by subscription, credits, rate limit, or lock, the fund search still stays COMPLETED with the GLEIF manager on the graph. You can POST /search/expand later for a covered non-US manager. Path B IAPD no-match or scrape failure also leaves the fund search COMPLETED.
If GLEIF reports the fund but no manager, the fund search still COMPLETED with the fund as case.target and no expand or IAPD.
Fund search errors at POST¶
| Status | When |
|---|---|
400 |
target_type is "fund" and legal_name is missing or blank |
400 |
target_type is present and is not "fund" or "corporate" |
401 |
Missing or invalid auth |
403 |
Account locked (access_locked) |
429 |
Rate limit |
No 400 for missing jurisdiction. No 403 for coverage at this POST. Coverage is checked when expand starts.
Fund search completion errors¶
Poll GET /search/{fundSearchId}/status. These mark the fund search FAILED. There is no refund (the fund search was not billed). Expand does not start.
result.error |
When |
|---|---|
No matching LEI found for "<name>" |
No exact GLEIF legal-name match |
"<name>" is not registered as a fund on GLEIF |
Exact match exists but is not a fund |
A GLEIF HTTP failure also marks the fund search FAILED.
Get search status / results¶
Request¶
Headers
| Header | Value |
|---|---|
X-API-Key or Authorization |
API key or Bearer token |
Path parameters
| Parameter | Type | Description |
|---|---|---|
searchId |
string | _id from the POST response |
Response¶
{
"_id": "abc123searchId",
"caseId": "xyz789caseId",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:05.000Z",
"userId": "user-uid",
"searchInputs": {
"identifier": "HRB 246975",
"jurisdiction": "DE"
},
"status": "COMPLETED",
"result": {
"_id": "entity-uuid",
"legalName": "EXAMPLE GMBH",
"legalForm": "Gesellschaft mit beschränkter Haftung",
"companyStatus": "Active",
"countryOfRegistration": "DE",
"jurisdiction": "DE",
"registrationDate": "2020-03-15",
"addresses": [],
"identifiers": [],
"relationships": [],
"activities": [],
"capital": {},
"otherNames": [],
"counterparties": [],
"sourceDocuments": []
}
}
result is a full Entity. On some jurisdictions (e.g. Singapore async document fulfilment) the search may stay PENDING with pendingDocument: true while a paid filing is still generating.
{
"_id": "abc123searchId",
"caseId": "xyz789caseId",
"status": "FAILED",
"result": {
"error": "Timeout while fetching registry data"
},
"searchInputs": {
"identifier": "HRB 246975",
"jurisdiction": "DE"
},
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:30.000Z",
"userId": "user-uid"
}
Polling strategy¶
- Wait ~2 seconds after submit.
GET /search/{searchId}/status.- If
PENDING, wait 3 seconds and poll again. - Increase the interval up to ~10 seconds.
- Stop on
COMPLETEDorFAILED.
Average registry times vary widely (seconds to a few minutes). See Data Coverage.
Example (cURL)¶
RESPONSE=$(curl -sS -X POST https://api.revolutio.systems/search \
-H "Content-Type: application/json" \
-H "X-API-Key: $REV_API_KEY" \
-d '{"identifier": "09215191", "jurisdiction": "GB"}')
SEARCH_ID=$(echo "$RESPONSE" | jq -r '._id')
CASE_ID=$(echo "$RESPONSE" | jq -r '.caseId')
sleep 3
curl -sS "https://api.revolutio.systems/search/$SEARCH_ID/status" \
-H "X-API-Key: $REV_API_KEY" | jq .
Expand search¶
Follow-on registry search on a counterparty already on a case.
Unlike POST /search (new case, overwrites case.target), expand grafts the new ownership layer under the chosen company node.
The request is async: HTTP returns as soon as a PENDING search is saved.
Endpoint¶
Same function as company search. Related paths:
| Method | Path | Purpose |
|---|---|---|
POST |
/search/expand |
Start expand |
GET |
/search/{searchId}/status |
Full search doc (incl. result when done) |
GET |
/casefile/{caseId} |
Case + search summaries (no nested result) |
Request body¶
{
"caseId": "abc123",
"entityId": "entity-uuid-on-case",
"jurisdiction": "DE",
"identifier": "HRB 12345",
"legalName": "Example GmbH",
"include": {
"financials": true
}
}
| Field | Required | Notes |
|---|---|---|
caseId |
Yes | Existing case id |
entityId |
Yes | _id of the target or a counterparty on that case |
jurisdiction |
No | Defaults from the entity (jurisdiction / countryOfRegistration) |
identifier |
No* | Registry registration number. Defaults from the entity’s identifiers |
legalName |
No | Defaults from the entity |
include.financials |
No | Same opt-in as POST /search |
* A registration number is required. If neither the body nor the entity has one, the API responds 400 and tells you to resolve it first via IDFinder. Expand does not auto-pick a registry id (wrong match would corrupt the ownership graph).
Minimal example¶
curl -sS -X POST "https://api.revolutio.systems/search/expand" \
-H "Content-Type: application/json" \
-H "X-API-Key: $REV_API_KEY" \
-d '{
"caseId": "CASE_ID",
"entityId": "ENTITY_ID"
}'
Immediate response (200)¶
{
"_id": "SEARCH_ID",
"caseId": "CASE_ID",
"createdAt": "2026-…",
"updatedAt": "2026-…",
"userId": "UID",
"searchType": "expand",
"entityId": "ENTITY_ID",
"searchInputs": {
"identifier": "…",
"jurisdiction": "DE",
"legalName": "…"
},
"status": "PENDING"
}
Poll GET /search/{searchId}/status until COMPLETED or FAILED. On success, new counterparties are merged onto the case under entityId.
Expand credits¶
- Base jurisdiction cost debited up front (same as
POST /search). - On failure, base cost is refunded.
- Financials charged after success only if data returns.
Expand errors¶
| Status | When |
|---|---|
400 |
Missing caseId / entityId; unsupported jurisdiction; no registration number |
401 |
Missing or invalid auth |
402 |
Insufficient credits |
403 |
Not case owner; account locked; not subscribed to jurisdiction |
404 |
Case not found; entity not on case; user profile missing |
409 |
Counterparty already expanded, or an expand for that entity is already PENDING |
429 |
Rate limit |
500 |
Internal error (credits refunded if already charged) |
Example when the entity has no registry number:
{
"error": "No registration number for this company. Resolve it first via /idfinder.",
"legalName": "Example GmbH",
"jurisdiction": "DE"
}
Expand behaviour notes¶
- Idempotent per entity: once something in the case already points at
entityIdas a parent, further expands return409. - One in-flight expand per
entityId(PENDINGblocks a second start). - Expand does not create a new case; it mutates the existing case graph under the expanded node.
- Only the case owner may expand (collaborator access is not enough).
- Prefer re-fetching the case for UI structure; use search status for the full expand
resultand failure details.
Typical end-to-end flow¶
1. POST /search → caseId + root company
2. (optional) POST /idfinder → registry number for a counterparty without one
3. POST /search/expand → caseId + entityId (+ identifier if needed)
4. GET /search/{id}/status → wait for COMPLETED | FAILED
5. GET /casefile/{caseId} → updated ownership tree (summaries + target graph)
Fund path: