> For the complete documentation index, see [llms.txt](https://docs.fill-easy.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fill-easy.com/kyc-licensee.md).

# KYC Licensee

One-request screening of an insurance-intermediary candidate: the Hong Kong licence registers (IA, SFC, MPFA), court records, AML watchlist screening, and — with a mainland resident ID — the mainland China background checks all run in parallel from a single payload and come back as one consolidated result.

Send what you have: only the English name is required, and each check runs only when its own input is present — a licence/registration number per register, the name forms for courts and screening, the resident-ID pair for the mainland. The flow is asynchronous — request, then poll or receive a webhook.

## Licensee screening - Request

> Screens an insurance-intermediary candidate (an individual licensee) across every check\
> the supplied fields enable, in one request: the three Hong Kong licence registers\
> (IA, SFC, MPFA), Hong Kong court records, AML watchlist screening with full profiles,\
> and — when a mainland resident ID is supplied — the mainland China background checks.\
> The outcomes come back as one consolidated result holding each check's raw response.\
> \
> No single field is required — every check does the best it can with the data given\
> (a request just needs at least one name or one identifier). The three registers run\
> by their own identifier when supplied (an unambiguous lookup), otherwise by name —\
> several same-named register entries then come back as an unresolved \`422\` entry, a\
> finding in its own right. The mainland checks alone need their identity pair.\
> \
> \| Check | Searches | Searched by |\
> \|---|---|---|\
> \| \`ia\` | IA Register of Licensed Insurance Intermediaries | \`iaLicenceNo\`, else the names |\
> \| \`sfc\` | SFC Public Register of Licensed Persons | \`sfcCeRef\`, else the names |\
> \| \`mpfa\` | MPFA Register of Subsidiary Intermediaries | \`mpfaRegistrationNo\`, else the names |\
> \| \`litigation\` | Hong Kong court records — one search per name form | the name forms (English name, \`nameChineseTraditional\`, \`aliases\`) |\
> \| \`screening\` | Sanctions / PEP / adverse media — one screen per name form, narrowed by \`dob\` / \`gender\` / \`country\` | the name forms |\
> \| \`cn\` | Mainland China background (\`/kyc/cn\` products) | \`cnIdNumber\` + \`nameChineseSimplified\` — skipped without the pair |\
> \| \`director\` | Companies Registry Directors Index — every company where the person is or was a director | the full English name (else \`nameChineseTraditional\`); \`hkid\` narrows to an exact match |\
> \
> The \`director\` search runs by the full English name (surname + other names; the\
> Chinese name when the English pair is incomplete); a supplied \`hkid\` upgrades it to\
> an exact match of the name plus the HKID's leading characters (the partial form the\
> Registry stores) — the only way to resolve same-name candidates.\
> \
> \### Asynchronous contract\
> \
> The checks run in parallel and take up to a few minutes (bounded at 10), so this\
> endpoint validates, queues, and returns a \`token\` immediately. Poll\
> \[\`POST /kyc/licensee/poll\`]\(#tag/KYC-Licensee/operation/kycLicenseePoll) every \~10\
> seconds, or supply a \`callbackUrl\` to receive the completed result as a webhook —\
> \`event: kyc.licensee.completed\`, or \`kyc.licensee.partial\` when the time budget\
> expired before every check finished. Polling remains available regardless.\
> \
> Validation is strict and free: a \`400\` lists \*\*every\*\* problem in \`problems\`, so a\
> corrected request can be built in one pass. Nothing is searched or billed on a \`400\`.\
> \
> \### Billing\
> \
> Each underlying check bills exactly as it does when called directly — each register\
> lookup, each AML screen (one per name form), each mainland product, and the\
> directorship search — plus one bill for the licensee screening itself. A \`dryRun\`\
> request calls no upstream and is free.<br>

```json
{"openapi":"3.1.0","info":{"title":"Fill Easy Services","version":"1.0.0"},"tags":[{"name":"KYC Licensee","description":"One-request screening of an insurance-intermediary candidate: the Hong Kong licence\nregisters (IA, SFC, MPFA), court records, AML watchlist screening, and — with a\nmainland resident ID — the mainland China background checks all run in parallel from a\nsingle payload and come back as one consolidated result.\n\nSend what you have: only the English name is required, and each check runs only when\nits own input is present — a licence/registration number per register, the name forms\nfor courts and screening, the resident-ID pair for the mainland. The flow is\nasynchronous — request, then poll or receive a webhook.\n"}],"servers":[{"url":"sandbox.staging-api.fill-easy.com"}],"security":[{"ClientID":[],"ClientSecret":[]}],"components":{"securitySchemes":{"ClientID":{"type":"apiKey","description":"Client ID in x-client-id header.","name":"x-client-id","in":"header"}},"schemas":{"Token":{"type":"string","pattern":"^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$","description":"JWT token"}}},"paths":{"/kyc/licensee":{"post":{"tags":["KYC Licensee"],"summary":"Licensee screening - Request","description":"Screens an insurance-intermediary candidate (an individual licensee) across every check\nthe supplied fields enable, in one request: the three Hong Kong licence registers\n(IA, SFC, MPFA), Hong Kong court records, AML watchlist screening with full profiles,\nand — when a mainland resident ID is supplied — the mainland China background checks.\nThe outcomes come back as one consolidated result holding each check's raw response.\n\nNo single field is required — every check does the best it can with the data given\n(a request just needs at least one name or one identifier). The three registers run\nby their own identifier when supplied (an unambiguous lookup), otherwise by name —\nseveral same-named register entries then come back as an unresolved `422` entry, a\nfinding in its own right. The mainland checks alone need their identity pair.\n\n| Check | Searches | Searched by |\n|---|---|---|\n| `ia` | IA Register of Licensed Insurance Intermediaries | `iaLicenceNo`, else the names |\n| `sfc` | SFC Public Register of Licensed Persons | `sfcCeRef`, else the names |\n| `mpfa` | MPFA Register of Subsidiary Intermediaries | `mpfaRegistrationNo`, else the names |\n| `litigation` | Hong Kong court records — one search per name form | the name forms (English name, `nameChineseTraditional`, `aliases`) |\n| `screening` | Sanctions / PEP / adverse media — one screen per name form, narrowed by `dob` / `gender` / `country` | the name forms |\n| `cn` | Mainland China background (`/kyc/cn` products) | `cnIdNumber` + `nameChineseSimplified` — skipped without the pair |\n| `director` | Companies Registry Directors Index — every company where the person is or was a director | the full English name (else `nameChineseTraditional`); `hkid` narrows to an exact match |\n\nThe `director` search runs by the full English name (surname + other names; the\nChinese name when the English pair is incomplete); a supplied `hkid` upgrades it to\nan exact match of the name plus the HKID's leading characters (the partial form the\nRegistry stores) — the only way to resolve same-name candidates.\n\n### Asynchronous contract\n\nThe checks run in parallel and take up to a few minutes (bounded at 10), so this\nendpoint validates, queues, and returns a `token` immediately. Poll\n[`POST /kyc/licensee/poll`](#tag/KYC-Licensee/operation/kycLicenseePoll) every ~10\nseconds, or supply a `callbackUrl` to receive the completed result as a webhook —\n`event: kyc.licensee.completed`, or `kyc.licensee.partial` when the time budget\nexpired before every check finished. Polling remains available regardless.\n\nValidation is strict and free: a `400` lists **every** problem in `problems`, so a\ncorrected request can be built in one pass. Nothing is searched or billed on a `400`.\n\n### Billing\n\nEach underlying check bills exactly as it does when called directly — each register\nlookup, each AML screen (one per name form), each mainland product, and the\ndirectorship search — plus one bill for the licensee screening itself. A `dryRun`\nrequest calls no upstream and is free.\n","operationId":"kycLicensee","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"No single field is required — supply whatever identity data you have; the only rejection is a request with no name and no identifier at all (nothing any check could search). Strings are trimmed and identifiers upper-cased before validation.\n","properties":{"surname":{"type":"string","description":"English surname, casing free."},"otherNames":{"type":"string","description":"English given names, casing free."},"nameChineseTraditional":{"type":"string","description":"Chinese name in Traditional characters, as Hong Kong registers publish it. Adds a Chinese-language search to the court and screening checks — the IA register and the courts match Traditional only.\n"},"nameChineseSimplified":{"type":"string","description":"Chinese name in Simplified characters, exactly as on the mainland resident ID card — pinyin is not accepted. Required with `cnIdNumber`; the pair unlocks the mainland China checks.\n"},"aliases":{"type":"array","items":{"type":"string"},"description":"Other name forms — former names, alternative spellings, English or Chinese. Each becomes a separate court search and AML screen (script is detected automatically). Duplicates of the searched primary names are dropped; at most 10 may remain after that deduplication.\n"},"iaLicenceNo":{"type":"string","description":"IA insurance intermediary licence number — 2 letters + 4 digits. Resolves the IA register lookup unambiguously; without it the register is searched by name, which several same-named licensees can leave unresolved.\n"},"sfcCeRef":{"type":"string","description":"SFC Central Entity (CE) number — 3 letters + 3 digits. Resolves the SFC register lookup unambiguously; without it the register is searched by name, which several same-named persons can leave unresolved.\n"},"mpfaRegistrationNo":{"type":"string","description":"MPF registration number — 6 digits for a person, `A` + 6 digits for an agency. Resolves the MPFA register lookup unambiguously; without it the register is searched by name, which several same-named intermediaries can leave unresolved.\n"},"hkid":{"type":"string","description":"Hong Kong Identity Card number, full (`A123456(7)`) or partial. Upgrades the Companies Registry directorship search from a loose name search to an exact match of the English name plus the HKID's leading characters (the partial form the Registry stores) — the way to resolve same-name candidates. A full HKID has its check digit verified.\n"},"cnIdNumber":{"type":"string","description":"18-digit mainland China Resident Identity Card number (last character may be `X`). With `nameChineseSimplified`, unlocks the mainland China checks and makes their findings identity-certain. Never echoed back in results. When `dob` is also supplied, digits 7–14 must match it.\n"},"dob":{"type":"string","description":"Date of birth, `YYYY-MM-DD`. Narrows watchlist screening."},"gender":{"type":"string","enum":["male","female"],"description":"Narrows watchlist screening."},"country":{"type":"string","description":"Nationality, citizenship, or residency — country name or code. Narrows watchlist screening."},"externalRefId":{"type":"string","description":"Your own reference id, echoed back in poll and webhook payloads."},"callbackUrl":{"type":"string","format":"uri","pattern":"^https://.+","description":"HTTPS URL to receive a webhook POST when the result is ready — the consolidated result wrapped in the standard webhook envelope. Delivered once, best-effort; polling remains available regardless.\n"},"callbackHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom HTTP headers for the webhook request (e.g. authentication)."},"dryRun":{"type":"boolean","description":"When `true`, no upstream is called and nothing is billed: every check the input enables returns a static sample body with the status a real run would carry, so the aggregate mirrors a real run exactly — only the top-level `dryRun: true` in the result marks it. Use to integrate against the contract for free, and to preview which checks a payload triggers.\n"}}}}}},"responses":{"200":{"description":"Request validated and queued. Poll with the returned token, or await the webhook if a `callbackUrl` was supplied.\n","content":{"application/json":{"schema":{"type":"object","required":["token","requestId"],"properties":{"token":{"$ref":"#/components/schemas/Token"},"requestId":{"type":"string"}}}}}},"400":{"description":"Validation failed — nothing was searched or billed. `problems` lists every issue found, so one corrected request can fix them all.\n","content":{"application/json":{"schema":{"type":"object","required":["message","problems","requestId"],"properties":{"message":{"type":"string"},"problems":{"type":"array","items":{"type":"string"}},"requestId":{"type":"string"}}}}}}}}}}}
```

## Licensee screening - Poll

> Returns the state of a licensee screening started with\
> \[\`POST /kyc/licensee\`]\(#tag/KYC-Licensee/operation/kycLicensee): \`202\` while checks\
> are running, \`200\` with the consolidated result once done. Results are kept for 30\
> days; afterwards the poll returns \`410\`.<br>

```json
{"openapi":"3.1.0","info":{"title":"Fill Easy Services","version":"1.0.0"},"tags":[{"name":"KYC Licensee","description":"One-request screening of an insurance-intermediary candidate: the Hong Kong licence\nregisters (IA, SFC, MPFA), court records, AML watchlist screening, and — with a\nmainland resident ID — the mainland China background checks all run in parallel from a\nsingle payload and come back as one consolidated result.\n\nSend what you have: only the English name is required, and each check runs only when\nits own input is present — a licence/registration number per register, the name forms\nfor courts and screening, the resident-ID pair for the mainland. The flow is\nasynchronous — request, then poll or receive a webhook.\n"}],"servers":[{"url":"sandbox.staging-api.fill-easy.com"}],"security":[{"ClientID":[],"ClientSecret":[]}],"components":{"securitySchemes":{"ClientID":{"type":"apiKey","description":"Client ID in x-client-id header.","name":"x-client-id","in":"header"}},"schemas":{"Token":{"type":"string","pattern":"^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$","description":"JWT token"},"KycLicenseeResult":{"type":"object","description":"Consolidated result of a licensee screening — the raw JSON response of every check that ran, keyed by check name. Also delivered as the `data` of the completion webhook.\n","required":["requestId","input","checks"],"properties":{"requestId":{"type":"string"},"externalRefId":{"type":"string","description":"Echoed from the request, if any."},"partial":{"type":"boolean","description":"`true` when the 10-minute budget expired before every check finished — the unfinished ones carry `status: timeout`.\n"},"dryRun":{"type":"boolean"},"completedTime":{"type":"number","description":"Epoch milliseconds when the checks finished."},"zipUrl":{"type":"string","format":"uri","description":"Presigned download link for the report bundle, minted fresh on every poll (valid 7 days; the file is kept 30). The zip holds `summary.pdf` (the consolidated background screening report), every file the checks produced (register page prints, screening reports, the mainland report), and a `<check>.json` with the raw response for entries that produced no file. Omitted if the bundle could not be stored — the structured result is unaffected.\n"},"zipFileName":{"type":"string","description":"Suggested file name for the report bundle."},"input":{"type":"object","additionalProperties":true,"description":"The request as parsed and normalised — render this back to a human wherever the payload was machine-authored, so extraction errors get caught. `cnIdNumber` is never echoed; `cnIdProvided: true` marks its presence.\n"},"checks":{"type":"object","description":"One entry per check that ran. A check whose inputs were missing is absent.","properties":{"ia":{"$ref":"#/components/schemas/KycLicenseeCheckResult"},"sfc":{"$ref":"#/components/schemas/KycLicenseeCheckResult"},"mpfa":{"$ref":"#/components/schemas/KycLicenseeCheckResult"},"litigation":{"type":"array","description":"One court search per name form.","items":{"$ref":"#/components/schemas/KycLicenseeCheckResult"}},"screening":{"type":"array","description":"One AML screen per name form, always with full profiles.","items":{"$ref":"#/components/schemas/KycLicenseeCheckResult"}},"cn":{"$ref":"#/components/schemas/KycLicenseeCheckResult"},"director":{"$ref":"#/components/schemas/KycLicenseeCheckResult"}}}}},"KycLicenseeCheckResult":{"type":"object","description":"The raw outcome of one underlying check — the endpoint's own HTTP status and JSON body, unchanged. A `404` (no record) or `422` (several candidates, unresolved) is a meaningful finding, not a failure.\n","required":["status"],"properties":{"status":{"description":"HTTP status the underlying endpoint returned, or `timeout` (still running when the budget expired). A dryRun carries the status a real run would.\n","oneOf":[{"type":"integer"},{"type":"string","enum":["timeout"]}]},"body":{"type":"object","additionalProperties":true,"description":"The endpoint's raw JSON response body — for a dryRun, a static sample of the same shape. Absent for `timeout`.\n"},"name":{"type":"string","description":"For per-name-form checks — the name form this call searched."},"requestId":{"type":"string","description":"The sub-request's own id, when the check runs through its own request/poll flow (`cn`, `director`).\n"}}},"KycHkRegisterError":{"type":"object","description":"Error body of all `/kyc/hk` register lookups.","required":["message","requestId"],"properties":{"message":{"type":"string"},"requestId":{"type":"string"}}}}},"paths":{"/kyc/licensee/poll":{"post":{"tags":["KYC Licensee"],"summary":"Licensee screening - Poll","description":"Returns the state of a licensee screening started with\n[`POST /kyc/licensee`](#tag/KYC-Licensee/operation/kycLicensee): `202` while checks\nare running, `200` with the consolidated result once done. Results are kept for 30\ndays; afterwards the poll returns `410`.\n","operationId":"kycLicenseePoll","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"$ref":"#/components/schemas/Token"}}}}}},"responses":{"200":{"description":"Screening finished — the consolidated result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KycLicenseeResult"}}}},"202":{"description":"Checks still running. Poll again in ~10 seconds.","content":{"application/json":{"schema":{"type":"object","required":["status","requestId"],"properties":{"status":{"type":"string","enum":["processing"]},"requestId":{"type":"string"}}}}}},"410":{"description":"The result has expired — results are kept for 30 days.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KycHkRegisterError"}}}},"503":{"description":"The screening run failed and has been flagged for follow-up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KycHkRegisterError"}}}}}}}}}
```
