COMPANY INTELLIGENCE · DEVELOPER GUIDE
Choose the right contract before you write code.
Build a structured company profile, ask an adaptive intelligence question, connect an AI client through MCP, or turn a published claim into durable CompanyProof evidence. Every public interface is CompanyProof-branded and uses the same CompanyProof credential.
https://companyproof.ai/v2Company intelligencehttps://companyproof.ai/v2Recommended profileGET /companies/{id}/profileSTART HERE · INTERFACE CHOOSER
Four jobs. Four deliberate choices.
A stable production integration starts by choosing the output contract, not by choosing the endpoint with the broadest name.
Company Profile REST
Use structured REST when your application needs a complete, machine-readable legal company profile.
/companies/search → /companies/{id}/profileOpen the profile flow →CompanyProof Verification
Use when you already have a claim and need a verdict, evidence record, audit trail and optional monitoring.
POST /v2/claims/verifyOpen the verification contract →Adaptive Intelligence API
Use for adaptive research or conversational experiences where the requested data can change with each question.
POST /v2/intelligence/queryOpen the intelligence guide →CompanyProof MCP
Use when a Streamable HTTP MCP client should search companies, retrieve profiles or verify claims through typed CompanyProof tools.
https://companyproof.ai/v2/mcpOpen the MCP guide →Authorization: Bearer cp_live_…Use the same key for profiles, intelligence queries, verification and MCP. Customers see only CompanyProof contracts, credentials and support boundaries.
COMPANY PROFILE REST · RECOMMENDED
Resolve the entity, then retrieve its profile.
The CompanyProof profile flow has a stable, versioned top-level envelope. Resolve a legal entity first, keep the returned opaque id, then request the consolidated profile. A cp_live_… key is required; test keys never call live company-data services.
- 01Resolve the legal entity
POST /v2/companies/searchwith a name, registration number or VAT/tax ID and country. Check jurisdiction and identifiers before selecting a fuzzy name match. - 02Retrieve the profile envelope
GET /v2/companies/{id}/profilereturnscompany_id,profile, optionalenrichmentandsection_status. - 03Validate availability
On a successful
200,section_status.profileisavailable. Checksection_status.enrichmentindependently; it may beunavailable.
identifier_typeenumnoname (default), registration_number or vat_tax_id.
identifierstringyesThe company name or identifier to resolve.
countrystringyesUppercase ISO 3166-1 alpha-2 jurisdiction code.
limitintegernoNumber of matches, from 1 to 10. Defaults to 8.
{
"identifier_type": "name",
"identifier": "Acme Holdings Limited",
"country": "GB",
"limit": 5
}{
"companies": [
{
"id": "company_123",
"name": "ACME HOLDINGS LIMITED",
"registration_number": "12345678",
"vat_tax_id": "GB123456789",
"country": "GB",
"country_name": "United Kingdom",
"status": "Active",
"legal_form": "Private limited company",
"incorporation_date": "2020-01-15",
"website": "https://acme.example",
"logo_url": null,
"evidence": {
"source_name": "National company register",
"source_url": "https://register.example/company/12345678",
"retrieved_at": "2026-08-29T10:42:11.000Z"
}
}
]
}const headers = {
"Authorization": "Bearer " + process.env.COMPANYPROOF_API_KEY,
"Content-Type": "application/json"
};
// 1. Resolve the legal entity.
const searchResponse = await fetch(
"https://companyproof.ai/v2/companies/search",
{
method: "POST",
headers,
body: JSON.stringify({
identifier_type: "name",
identifier: "Acme Holdings Limited",
country: "GB"
})
}
);
const matches = await searchResponse.json();
if (!searchResponse.ok || !matches.companies?.[0]?.id) {
throw new Error("Company could not be resolved");
}
// 2. Retrieve the consolidated legal company profile.
const profileResponse = await fetch(
`https://companyproof.ai/v2/companies/${matches.companies[0].id}/profile`,
{ headers }
);
const profile = await profileResponse.json();
if (!profileResponse.ok) throw new Error("Profile retrieval failed");
if (profile.section_status.profile !== "available") {
throw new Error("The core profile is unavailable");
}
if (profile.section_status.enrichment !== "available") {
console.warn("Optional enrichment is unavailable");
}
// The stable envelope is profile.profile + profile.enrichment + section_status.
const companyProfile = profile.profile;
const officers = companyProfile.officers?.error
? []
: (companyProfile.officers?.data ?? companyProfile.officers ?? []);{
"company_id": "company_123",
"profile": {
"lite": {
"data": { "basic": { "name": "ACME HOLDINGS LIMITED", "status": "Active" } },
"source": { "name": "National company register", "retrieved_at": "2026-08-29T10:42:11.000Z" }
},
"officers": { "data": [], "source": {} },
"shareholders": {
"error": { "status_code": 403, "message": "This module is unavailable for the selected record." }
},
"group_structures_full": { "data": [], "source": {} },
"financial": { "data": [], "source": {} }
},
"enrichment": {},
"section_status": {
"profile": "available",
"enrichment": "available"
}
}liteLegal identity
Name, registration and VAT/tax identifiers, status, incorporation, legal form and registered address.
officersOfficers
Directors and officers, roles, appointment dates, work status and returned registry addresses.
shareholdersShareholders
Returned holders, ownership percentages when available, share classes, quantities and values.
group_structures_fullCorporate hierarchy
Parent and subsidiary relationships. Treat modelled relationships differently from registry-sourced facts.
financialFinancial statements
Multi-year filings, balance-sheet and income-statement data, cash flow, KPIs and ratios.
enrichmentProfile enrichment
Industry, SIC, size, brands, company contacts and social links when available.
The top-level envelope is the CompanyProof contract. Fields nested inside profile and enrichment vary by jurisdiction and available modules during beta; they are represented as open objects in OpenAPI. A module may contain direct data, a { data, source } provenance wrapper, or an embedded error when that module is unavailable while the overall profile still returns 200. Inspect each module before using it and do not make a nested field mandatory unless your own contract tests observe it for the jurisdictions you support.
Registry-derived facts, enriched contact fields and modelled corporate relationships do not have the same evidential weight. Preserve each returned source category and never label an enriched or modelled field as registry-verified. Returned shareholders and hierarchy are not, by themselves, a calculated UBO determination or a sanctions-screening result.
PUBLIC COMPANYPROOF INTERFACES
One endpoint map, with no implied module routes.
These are the complete public endpoints currently supported. Officers, shareholders, hierarchy and financial data are returned only when present inside the consolidated profile; there are no public per-module routes in this version.
/v2/companies/searchResolve a legal entity by company name, registration number or VAT/tax ID and country.
/v2/companies/{id}/profileRetrieve the consolidated CompanyProof profile envelope and optional enrichment.
/v2/intelligence/queryAdaptive natural-language company intelligence, streamed as Server-Sent Events.
/v2/claims/verifyVerify supplied company claims, preserve evidence and optionally monitor verified facts.
/v2/mcpStreamable HTTP MCP endpoint for CompanyProof agent tools.
Download OpenAPI 3.1 for REST paths, schemas and errors. The consolidated profile returns enrichment separately from registry-derived identity; keep those evidence categories separate in downstream decisions.
CAPABILITY BOUNDARY
Know what this contract does—and what it does not.
/companies/searchsearch_companiesLive key/companies/{id}/profileget_company_profileLive key · beta payload/claims/verifyverify_company_claimsTest + livemonitor: trueverify toolEligible live plans——Not provided——Not providedADAPTIVE INTELLIGENCE API · ORCHESTRATION
Ask for intelligence when the schema can be dynamic.
The Adaptive Intelligence API requires a live key, accepts one self-contained question of 1–4,000 characters and streams Server-Sent Events. Use mode: "ai" for a written answer plus tool data, or mode: "data" for data-oriented output.
const response = await fetch(
"https://companyproof.ai/v2/intelligence/query",
{
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.COMPANYPROOF_API_KEY,
"Content-Type": "application/json",
"Accept": "text/event-stream"
},
body: JSON.stringify({
query: "Find Acme Holdings in GB and show its directors and financials",
mode: "ai"
})
}
);
// Consume response.body as Server-Sent Events.statusProgress message; may occur more than once.
tool_callNames a CompanyProof operation selected for the question.
tool_resultReturns data or a module-level error for a selected operation.
textStreams answer text. Concatenate events in order.
suggested_actionsOptional follow-up questions.
doneTerminal success event. Inspect completeness metadata when supplied.
errorTerminal stream failure. Do not treat preceding partial text as complete.
The initial HTTP request can fail with the normal JSON error envelope. Once streaming begins, errors arrive as SSE error events. The server does not promise replay IDs; retry the complete request with your own correlation ID. Clients must ignore unknown event types for forward compatibility.
Adaptive output depends on the question and the tools selected at runtime. Use Company Profile REST when a predictable envelope matters. Adaptive intelligence does not create a CompanyProof proof or monitoring record.
QUICK START
Verify the documented sample.
Create a test key in your account. Test keys work only with the fictional CompanyProof Sandbox Limited fixture in GB, and they cannot enable monitoring or retrieve live profiles.
curl --request POST \
--url https://companyproof.ai/v2/claims/verify \
--header "Authorization: Bearer $COMPANYPROOF_TEST_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: verify_01J62E8A" \
--data '{
"company": {
"name": "CompanyProof Sandbox Limited",
"country": "GB"
},
"claims": [
{ "field": "status", "published": "Active" },
{ "field": "incorporation_date", "published": "2021-01-15" }
],
"monitor": false
}'A newly created proof returns 201 Created. An idempotent replay returns 200 OK with Idempotent-Replayed: true.
AUTHENTICATION
Use one CompanyProof credential.
API keys begin with cp_test_ or cp_live_. Send them from your server, store them in a secrets manager and rotate or revoke them from the account console. The full token is displayed only once.
Authorization: Bearer YOUR_COMPANYPROOF_KEYToken is accepted for compatibility, but new integrations should use Bearer. Never put a key in browser JavaScript, a URL, logs or a public repository.
MODEL CONTEXT PROTOCOL · COMPANYPROOF
Give agents typed CompanyProof company tools.
CompanyProof MCP uses stateless Streamable HTTP. It is intended for MCP clients that can send a custom Authorization header. Direct ChatGPT connection requires OAuth and is not yet offered; do not paste API keys into a prompt or an OAuth-only connector screen.
STREAMABLE HTTP · PUBLIC BETA
CompanyProof MCP
https://companyproof.ai/v2/mcpConnect with a CompanyProof bearer key. The server exposes read-only company search and profile tools plus the consequential verify_company_claims tool.
{
"mcpServers": {
"companyproof": {
"type": "http",
"url": "https://companyproof.ai/v2/mcp",
"headers": {
"Authorization": "Bearer ${COMPANYPROOF_API_KEY}"
}
}
}
}search_companiesInputs: identifier_type, identifier, country, optional limit. Returns the same typed company list as REST search. Requires a live key.
get_company_profileInput: company_id. Returns the CompanyProof profile envelope and section availability. Requires a live key.
verify_company_claimsInputs: company, exactly one of answer or claims, optional monitor and idempotency_key. Writes a proof and consumes claim credits.
curl --request POST \
--url https://companyproof.ai/v2/mcp \
--header "Authorization: Bearer $COMPANYPROOF_API_KEY" \
--header "Content-Type: application/json" \
--header "Accept: application/json, text/event-stream" \
--header "MCP-Protocol-Version: 2026-07-28" \
--header "Mcp-Method: server/discover" \
--data '{
"jsonrpc": "2.0",
"id": "discover",
"method": "server/discover",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "companyproof-client", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'curl --request POST \
--url https://companyproof.ai/v2/mcp \
--header "Authorization: Bearer $COMPANYPROOF_TEST_KEY" \
--header "Content-Type: application/json" \
--header "Accept: application/json, text/event-stream" \
--header "MCP-Protocol-Version: 2026-07-28" \
--header "Mcp-Method: tools/call" \
--header "Mcp-Name: verify_company_claims" \
--data '{
"jsonrpc": "2.0",
"id": "verify",
"method": "tools/call",
"params": {
"name": "verify_company_claims",
"arguments": {
"company": {
"name": "CompanyProof Sandbox Limited",
"country": "GB",
"registration_number": "CP000001"
},
"claims": [
{ "field": "status", "published": "Active" }
],
"monitor": false,
"idempotency_key": "verify_agent_01J62E8A"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "companyproof-client", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'- 01
server/discoverUse current protocol version
2026-07-28. Send the matchingMCP-Protocol-VersionandMcp-Methodheaders plus the protocol version, client identity and capabilities inparams._meta. The result identifiesCompanyProofand its supported versions. - 02
tools/listSend
Mcp-Method: tools/listand the same request metadata. The JSON result contains deterministic tool order, live input/output schemas, annotations and private cache hints. - 03
tools/callSend
Mcp-Method: tools/calland a matchingMcp-Name. Successful JSON results return typedstructuredContentplus a JSON text fallback.
Clients using 2025-11-25 or 2025-06-18 remain supported through the initialization-based Streamable HTTP flow: initialize, notifications/initialized, then tools/list or tools/call. Legacy post-initialization requests include the negotiated MCP-Protocol-Version and receive SSE responses. The server is stateless and does not issue MCP-Session-Id.
Missing or invalid credentials fail at transport level with HTTP 401. A valid MCP exchange can still return result.isError: true for validation, quota, not-found or dependency errors; parse the JSON fallback in result.content[0].text and branch on error.code. Tool errors preserve REST context in result._meta under companyproof.ai/http-status, companyproof.ai/retry-after, companyproof.ai/rate-limit, companyproof.ai/rate-remaining and companyproof.ai/rate-reset. Read-only tools are safe to auto-approve only if that matches your client policy; require approval for verify_company_claims.
CompanyProof may add optional fields and new tools during beta. Existing tool names and required fields will not be removed or renamed without a documented version transition. Keep keys in the client’s secure credential store and use an idempotency key for retrying verification.
Open platform examples and the tool contract →ENVIRONMENTS
Build safely in test, then issue a live key.
cp_test_…Verification fixture only
Off/claims/verify + MCP verify
cp_live_…Eligible live company records
Paid plansAll plans
Test proofs are persisted in your ledger and use a separate 10-credit monthly test allowance. Search, profile, adaptive intelligence and the corresponding MCP read tools return 403 live_key_required for test keys and never call the live company-data service.
PRIMARY ENDPOINT
POST /v2/claims/verify
Send exactly one input form: a natural-language answer for supported-claim extraction, or a claims array when your system already has structured values.
company.namestringyesEntity name, 1–200 characters.
company.countrystringyesUppercase ISO 3166-1 alpha-2 jurisdiction code.
company.registration_numberstringnoStrong resolution signal, up to 80 characters.
answerstringone ofNatural-language answer, up to 8,000 characters.
claimsarrayone ofUp to 20 unique supported fields; each value is at most 500 characters.
monitorbooleannoDefaults to false. Requires a live key and a paid plan.
{
"company": {
"name": "CompanyProof Sandbox Limited",
"country": "GB",
"registration_number": "CP000001"
},
"answer": "The company is active and was incorporated on 15 January 2020.",
"monitor": false
}{
"company": {
"name": "CompanyProof Sandbox Limited",
"country": "GB"
},
"claims": [
{ "field": "status", "published": "Active" },
{ "field": "legal_form", "published": "Private limited company" }
],
"monitor": false
}For structured claims, send published. The legacy alias expected is also accepted. The complete JSON request is limited to 64 KiB.
DETERMINISTIC SCOPE
Six fields are currently guaranteed.
Officers, shareholders, group structures and financial claims are not yet part of this deterministic endpoint. Do not build production logic that assumes they are returned here.
registered_nameLegal registered company name
registration_numberOfficial company registration identifier
statusCurrent registry status
incorporation_dateOfficial incorporation or formation date
vat_numberVAT or tax identifier when returned by the selected source
legal_formRegistered legal form
RESPONSE MODEL
Evidence travels with every verdict.
The proof ID links the resolved company, individual claims, source context, decision events and future monitoring state. corrected means a supported field was found but its published value did not match the observed value.
The published value matches the observed source value.
The observed source value differs from the published value.
The selected source did not return a value for that field.
A monitored value that previously matched no longer does.
{
"proof_id": "prf_7dcf18e8a2f6c06a9a10d2c1",
"company": {
"id": "sandbox_company_001",
"name": "COMPANYPROOF SANDBOX LIMITED",
"registration_number": "CP000001",
"country": "GB"
},
"claims": [
{
"claim_id": "clm_f3df4360de139d4f9d323779",
"field": "status",
"published": "Active",
"observed": "Active",
"verdict": "verified",
"explanation": "The published value matches the sample company record.",
"evidence": {
"source_name": "CompanyProof Sandbox",
"source_url": "https://companyproof.ai/docs#environments",
"source_record_id": "sandbox_company_001",
"retrieved_at": "2026-08-29T10:42:11.000Z"
}
},
{
"claim_id": "clm_15c1c8ae33b2520c5c9a9701",
"field": "incorporation_date",
"published": "2021-01-15",
"observed": "2020-01-15",
"verdict": "corrected",
"explanation": "The published value conflicts with the sample company record.",
"evidence": {
"source_name": "CompanyProof Sandbox",
"source_url": "https://companyproof.ai/docs#environments",
"source_record_id": "sandbox_company_001",
"retrieved_at": "2026-08-29T10:42:11.000Z"
}
}
],
"summary": {
"verified": 1,
"corrected": 1,
"stale": 0,
"unsupported": 0
},
"monitoring": "off",
"latency_ms": 0
}SAFE RETRIES
One logical verification, one proof.
Send an Idempotency-Key on every write. Keys must contain 8–128 characters from A–Z a–z 0–9 . _ : - and are scoped to your account.
- 01First request
The proof is created, claim credits are consumed and the response is
201. - 02Same key, same request
The stored proof is returned with
200andIdempotent-Replayed: true. No additional credits are consumed. - 03Same key, changed request
The request is rejected with
409 idempotency_conflict.
RATE AND USAGE LIMITS
Predictable monthly allowances. No automatic overage.
1010Not included250 / month30Included5,000 / month60Included50,000 / month120IncludedEach claim in a verification consumes one claim credit. Each monitored claim recheck consumes one more. Search, profile retrieval and adaptive intelligence are rate-limited but do not consume verification claim credits during the current beta. Requests stop at the relevant limit; CompanyProof does not create automatic overage charges.
X-RateLimit-LimitMaximum requests allowed for the API key in the shared 60-second window.
X-RateLimit-RemainingRequests remaining in that window.
X-RateLimit-ResetUnix timestamp when the rate window resets.
X-Usage-LimitMonthly claim-credit allowance.
X-Usage-RemainingClaim credits remaining this month.
X-Usage-ResetUnix timestamp for the next UTC monthly reset.
X-Request-IdRequest correlation identifier. For verification writes it currently equals proof_id; applications should still read the body field as proof identity.
CompanyProof REST 429 responses include Retry-After. The per-minute counter is shared by REST requests and MCP tool calls made with the same key; MCP tool failures are returned inside result.isError. Protocol discovery and tool listing do not consume the tool-call counter. Monitoring that reaches the monthly allowance pauses until the next UTC reset.
CONTINUOUS PROOF
Verified now. Watched afterwards.
With monitor: true, CompanyProof schedules only claims whose initial verdict is verified. The current beta check interval is approximately 24 hours; registry availability and source-refresh timing vary by jurisdiction.
- 01Evidence recorded
The published and observed values, source record and retrieval time enter the ledger.
- 02Claim rechecked
A successful unchanged check produces a ledger event and schedules the next check.
- 03Difference detected
The claim becomes stale, further checks stop for that claim and a signed webhook is queued.
Monitoring records can currently be reviewed in the CompanyProof account console. Public list, pause, resume and delete endpoints are not part of /v2; do not infer them from the dashboard.
WEBHOOKS · CLAIM.STALE
Authenticate every event before acting.
Create up to 10 active HTTPS endpoints in the account console. CompanyProof stores each endpoint secret encrypted, displays the secret once, rejects redirects and treats any 2xx response as successful delivery.
{
"id": "evt_0c1d2e3f4a5b6c7d8e9f1011",
"event": "claim.stale",
"type": "claim.stale",
"created_at": "2026-10-14T11:06:02.000Z",
"data": {
"proof_id": "prf_7dcf18e8a2f6c06a9a10d2c1",
"claim_id": "clm_f3df4360de139d4f9d323779",
"company": {
"id": "sandbox_company_001",
"name": "COMPANYPROOF SANDBOX LIMITED",
"registration_number": "CP000001",
"country": "GB"
},
"field": "status",
"published_value": "Active",
"verified_value": "Active",
"previous_value": "Active",
"current_value": "Dissolved",
"verified_at": "2026-08-29T10:42:11.000Z",
"changed_at": "2026-10-14T11:06:01.000Z",
"source": {
"sourceName": "CompanyProof Sandbox",
"sourceUrl": "https://companyproof.ai/docs#environments",
"retrievedAt": "2026-10-14T11:05:58.000Z",
"recordId": "sandbox_company_001"
}
}
}CompanyProof-Signature: t=UNIX_SECONDS,v1=HEX_HMACv1 is HMAC-SHA256 over timestamp + "." + raw_request_body. Verify the raw bytes before parsing JSON, compare in constant time and reject timestamps older than your tolerance.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyCompanyProofWebhook(rawBody, header, secret) {
const values = Object.fromEntries(
header.split(",").map(part => part.split("=", 2))
);
const timestamp = Number(values.t);
const supplied = Buffer.from(values.v1 || "", "hex");
if (!Number.isFinite(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const signed = Buffer.concat([
Buffer.from(String(timestamp) + ".", "utf8"),
rawBody
]);
const expected = createHmac("sha256", secret).update(signed).digest();
return supplied.length === expected.length &&
timingSafeEqual(supplied, expected);
}CompanyProof-Event-IdStable event ID. Persist it and ignore duplicates.
CompanyProof-SignatureTimestamp and HMAC-SHA256 signature.
User-AgentCompanyProof-Webhooks/1.0
Delivery times out after 10 seconds. CompanyProof makes up to five attempts: immediately, then after roughly 1 minute, 5 minutes, 30 minutes and 2 hours. Delivery order is not guaranteed; deduplicate with CompanyProof-Event-Id and order business events with created_at. There is no public replay endpoint in this version. Return 2xx only after the event is durably accepted.
VERSIONING · LAST UPDATED 29 AUGUST 2026
Pin the major contract; tolerate additive fields.
The REST major version is part of the path: /v2. CompanyProof may add optional response fields, new error codes and new MCP tools without changing that version. Removing or renaming a field, changing its type, or making an optional request field required will use a new major path or a documented migration window.
2026-08-29 — published search and profile schemas, isolated test keys from live profile services, unified the per-key rate-limit bucket, added a machine-readable OpenAPI contract, documented MCP schemas and introduced provider-neutral error naming.
ERROR MODEL
Machine-readable failures.
Errors use { "error": { "code": "…", "message": "…" } }. Branch on error.code; the human-readable message may become clearer without a version change.
400invalid_json · invalid_request · invalid_company · invalid_company_id · invalid_claim · answer_too_long · too_many_claims · duplicate_claim_field · invalid_idempotency_key
401authentication_required · invalid_api_key
403live_key_required · monitoring_requires_live_access · monitoring_requires_live_key · test_key_sample_only
409idempotency_conflict — the key was already used with a materially different request
413body_too_large — search exceeds 32 KiB, another REST JSON request exceeds 64 KiB, or an MCP message exceeds 128 KiB
415unsupported_media_type — Content-Type is not application/json
422no_supported_claims — no supported deterministic claim could be extracted
429rate_limit_exceeded · monthly_quota_exceeded · evaluation_quota_exceeded
502dependency_timeout · company_search_failed · profile_retrieval_failed · intelligence_query_failed · verification_failed
503service_unavailable — a required CompanyProof service is not configured or temporarily unavailable
404company_not_found — no profile exists for the supplied CompanyProof company ID
Ready to integrate?
Create a key, download the OpenAPI 3.1 contract and start with the CompanyProof sandbox fixture. Issue a live key only when you are ready to retrieve eligible company records.
Create an API key