How it works
- You submit business details (legal name, jurisdiction, registration number, and optionally address and people)
- The API fetches fresh data from the relevant provincial or federal business registry
- Each field is compared against the registry data with configurable similarity thresholds
- An AI analyst summary is generated for compliance review
Synchronous vs asynchronous
When a fresh registry lookup is required,POST /verify responds with 202 Accepted and a reportFetchId instead of the full result:
GET /verify/{id} (using the reportFetchId) until it returns the completed result. The poll endpoint always returns 200; branch on the body:
- Pending —
{ "pending": true, "status": "pending" | "processing" | "waiting_for_registry" }— keep polling. - Failed —
{ "status": "failed", "error": "<reason>" }. - Completed — the full verification response (the shape shown under Response).
POST /verify returns the completed result synchronously with 200. Always branch on the HTTP status (or the presence of pending: true) rather than assuming 200.
Request
Required fields
These three become optional when you reference a stored business record
with
businessId or businessExternalId (see below) — they’re hydrated from
the record.Optional fields
Jurisdictions
Accepts codes or full names:AB, BC, MB, NB, NL, NS, NT, NU, ON, PE, QC, SK, YT, FED (or “Ontario”, “British Columbia”, “Federal”, etc.)
Matching thresholds
Matching is governed by your account’s verification settings; a per-requestmatching object overrides them for that call. If you haven’t customized your settings, the defaults are:
A threshold of
1.0 requires an exact (normalized) match; lower values allow proportionally fuzzier matches. Override any subset per request:
normalization.enabled is true (the default), values are normalized before comparison — corporate suffixes are stripped, abbreviations expanded, postal codes standardized, etc. Set to false for strict character-for-character comparison.
Response
results.fields always includes legalName, registrationNumber, status, businessNumber, entityType, and address; a field you didn’t submit comes back with status: "not_submitted" (its registry value is still populated when the registry has one). address is always an object (with a nested fields breakdown), never null. people is present whenever people matching is enabled (the default) — even with no people submitted, where it reports not_submitted with an empty matches array — and is omitted entirely only when you disable it (matching.people.enabled: false).
Result status
Field match status
Scalar identity fields (legalName, registrationNumber, status, businessNumber, entityType):
address can additionally be partial_match (some components matched, others didn’t). The people block uses all_matched | partial_match | no_matches | not_submitted, and each entry in its matches array uses matched | partial_match | not_matched.
People matching
People matching is on by default — you don’t need to setenabled: true. When you submit people, they’re compared against the registry and, by default, the result affects the overall status. Control it via matching.people: set enabled: false to skip it entirely (the people field is then omitted), or impactsVerification: false to keep it informational (reported but not affecting status).
Each submitted person is compared against registry directors/officers. The people result includes a unified matches array containing both submitted and registry-only people:
- Submitted people not found in the registry have
registry: null - Registry people not in your submitted list have
provided: null
Common patterns
Verify a stored business record
Reference a business you’ve already stored — its legal name, jurisdiction, registration number (and address/people) are hydrated from the record. Use our id (businessId) or your own id on the record (businessExternalId).