Skip to main content
POST /v1/kyc/verify returns the verdict for a client profile and the documents behind it. Scope: kyc:verify. It does not read files and it costs no document read. POST /v1/kyc/assess takes the same body, runs this same verdict, and adds a risk assessment.

Request

JSON body. Every field is optional, but an empty body verifies nothing.

values

values is a free object. The engine reads the keys below and ignores the others. Send strings. Dates are YYYY-MM-DD. The completeness check counts these keys as present when they are non-empty. The required list comes from an engine that was first built for North American files. It asks for province, postal_code and a sin or ssn, so a Moroccan individual can reach 27 of 28 at most (96 percent) and sin/ssn stays in missing. 80 percent or more is not flagged. The sample requests here use country MA, id_type National ID and a CIN number such as BK123456; province and postal_code take any text for a Moroccan address, and the Canadian postal format is checked only when country is CA. Other keys the checks use:

Response

The checks list above is shortened to three entries; a full answer has more. The example is the real output of the engine for fake data (a Moroccan national ID and a payslip for Test Client). Each check has five keys. Do not match on label: it can change. Match on id, and treat the part after the first colon as a variable.

How to read the verdict

The file passes when no critical check failed. A file with 30 warnings still passes, so look at flags as well as passed.

The three layers

  1. Per document: the same checks /extract already returned for each file (type, readable, expiry, adult, MRZ, recency, provenance, specimen).
  2. Cross-document and profile: the name, date of birth and address agree across documents and with values; the formats of numbers; the bank details; the required identity document is among the uploads.
  3. File level: sanctions and PEP screening, beneficial ownership for entities, registry checks, the policy’s own determinations, then completeness.
Verification is deterministic: the same input gives the same verdict, except for screening (which depends on the list loaded) and the date, which comes from the server clock.

Checks

Ids are listed with the part after the first colon replaced by *. “Document” means the label of the step or the doc_type hint (for example passport, or Government photo ID when a step_key is sent).

Per document

Across documents and profile

File level

Screening

Every party on the file is screened by default (screen: true). A sanctions hit is critical and blocks. A PEP hit is a warning. A clean result produces one screening check that says what the party was screened against: With canadian_screening true (or the policy asking for it) and a Canadian client (country is CA, CAN or Canada), the parties the bundle found nothing on are also screened by the eID provider’s Canadian AML and PEP tables, when the workspace has an account. The screening:canchek check says how many parties were screened.

Policy and switches

Each call runs under your workspace’s KYC policy for the client kind (kyc for a person, kyb for any entity) and the environment. The answer’s policy says which one. A request switch can add checks or be stricter. It cannot turn off an item the policy locks. A refused switch is not an error: the call runs with the stricter rule and the refusal is recorded.
(Illustrative: the shape of overrides_refused is real, the values are an example.) A refusal also adds an info check policy:override_refused:screen. What a policy can change: Policy values are edited in the console, not through the API.

Periodic review

purpose: "periodic_review" is for a client already onboarded. It does not re-verify identity (PCMLTFR s.155(1)): the identity documents, the eID requirement and the slot checks are not applied. Screening, the determinations and every other lock still run.
  • With a passed onboarding on file at Sahl for the same reference and environment, the review adds an info check policy:periodic_review.
  • With none, or without a reference, the review is honoured but adds a warning policy:periodic_review_unanchored: identity was skipped on your word alone.

Your own checks

extra_checks lets you fold a check you ran yourself, such as a duplicate client or a blocklist in your database, into the verdict so it can block it.
Each needs id, label, severity (critical, warning or info) and passed; detail is optional. An id that starts with eid: or policy: is Sahl’s alone: it comes back as partner:eid:... or partner:policy:..., shown and still able to block, but it never meets the policy’s eID requirement.

Corporations Canada registry

For a corporation the advisor says is federally incorporated (CBCA), and when the policy enables it (default on), Sahl looks the company up. registry then holds the normalised record, so you can pre-fill from it, and the registry: checks compare it with your data. In every other case registry is null.

Filing

With a reference the verdict is filed on the case for (workspace, environment, reference). Documents whose document_id came from /extract are linked to it. A status a person set (approved, refused) is never undone by a new verdict. The kyc.case_verified webhook fires after the commit.

Examples

A blocked file

An expired national ID gives passed: false and two critical failures, one from the document and one from the profile: