> 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/facial-and-id-scan.md).

# Facial & ID Scan

Identity verification that bundles **ID document verification**, **face match**, and **passive liveness** into a single hosted flow. The user completes capture on a Fill Easy-hosted page; you receive the decision via webhook or polling.

***

#### Flow

1. Call `POST /ocr/auth` with a `redirect` URL → receive a `token` and a hosted `sessionUrl`
2. Redirect the user to `sessionUrl` to complete ID capture, liveness, and face match
3. Receive the result via **webhook** or **poll** `/ocr/poll`

***

#### Result Delivery

**Webhook (recommended)** — Pass a `callbackUrl` in the `/ocr/auth` body. When verification completes, a `POST` is sent to that URL with the decision wrapped in a `WebhookPayload` envelope. Polling remains available as a fallback.

**Polling** — Call `/ocr/poll` with the returned `token` until a `200` response is returned.

## Start session

> Creates an OCR verification session bundling ID Verification, Face Match,\
> and Passive Liveness. Returns a hosted \`sessionUrl\` to redirect the user to,\
> plus a JWT \`token\` used later with \`/ocr/poll\` to retrieve the decision.\
> \
> \*\*Webhook Delivery:\*\* Provide \`callbackUrl\` to receive a \`POST\` when verification\
> completes. The webhook body is a \[\`WebhookPayload\`]\(#/components/schemas/WebhookPayload)\
> envelope whose \`data\` is an \[\`OcrResult\`]\(#/components/schemas/OcrResult) — the\
> same shape returned by \`/ocr/poll\` on \`200\`. The request also carries an\
> \`X-Webhook-Event: ocr.verification.completed\` header plus any custom headers\
> supplied via \`callbackHeaders\`. Polling remains available regardless of whether\
> a \`callbackUrl\` is provided.

```json
{"openapi":"3.1.0","info":{"title":"Fill Easy Services","version":"1.0.0"},"tags":[{"name":"Facial & ID Scan","description":"Identity verification that bundles **ID document verification**, **face match**, and\n**passive liveness** into a single hosted flow. The user completes capture on a\nFill Easy-hosted page; you receive the decision via webhook or polling.\n\n---\n\n### Flow\n\n1. Call [`POST /ocr/auth`](#tag/OCR/operation/ocrAuth) with a `redirect` URL → receive a\n   `token` and a hosted `sessionUrl`\n\n2. Redirect the user to `sessionUrl` to complete ID capture, liveness, and face match\n\n3. Receive the result via **webhook** or **poll** [`/ocr/poll`](#tag/OCR/operation/ocrPoll)\n\n---\n\n### Result Delivery\n\n**Webhook (recommended)** — Pass a `callbackUrl` in the `/ocr/auth` body. When verification\ncompletes, a `POST` is sent to that URL with the decision wrapped in a\n[`WebhookPayload`](#/components/schemas/WebhookPayload) envelope. Polling remains available\nas a fallback.\n\n**Polling** — Call `/ocr/poll` with the returned `token` until a `200` response is returned.\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":{"RedirectUri":{"type":"string","description":"Redirect URI after user authorization.\n\nBrowser: HTTPS URL to your website.\n\niOS: HTTPS Universal link\n\nAndroid: Package name (com.filleasy.app)\n"},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/ocr/auth":{"post":{"tags":["Facial & ID Scan"],"summary":"Start session","description":"Creates an OCR verification session bundling ID Verification, Face Match,\nand Passive Liveness. Returns a hosted `sessionUrl` to redirect the user to,\nplus a JWT `token` used later with `/ocr/poll` to retrieve the decision.\n\n**Webhook Delivery:** Provide `callbackUrl` to receive a `POST` when verification\ncompletes. The webhook body is a [`WebhookPayload`](#/components/schemas/WebhookPayload)\nenvelope whose `data` is an [`OcrResult`](#/components/schemas/OcrResult) — the\nsame shape returned by `/ocr/poll` on `200`. The request also carries an\n`X-Webhook-Event: ocr.verification.completed` header plus any custom headers\nsupplied via `callbackHeaders`. Polling remains available regardless of whether\na `callbackUrl` is provided.","operationId":"ocrAuth","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect"],"properties":{"redirect":{"$ref":"#/components/schemas/RedirectUri"},"vendorData":{"type":"string","description":"Optional identifier of your own (e.g. user id) stored with the session and returned in the webhook payload."},"metadata":{"type":"object","description":"Arbitrary JSON stored with the session, returned in the webhook payload.","additionalProperties":true},"callbackUrl":{"type":"string","format":"uri","pattern":"^https://.+","description":"HTTPS URL to receive a webhook POST when verification completes.\nWhen provided, the webhook `data` is the same payload as a `200` response\nfrom `/ocr/poll`. Polling remains available as a fallback.\n"},"callbackHeaders":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom HTTP headers to include in the webhook request.\nUse this to pass authentication or any other headers your endpoint requires\n(e.g. `{\"Authorization\": \"Bearer <token>\", \"X-Api-Key\": \"...\"}`).\n"}}}}}},"responses":{"200":{"description":"Session created","content":{"application/json":{"schema":{"type":"object","required":["token","sessionUrl"],"properties":{"token":{"type":"string","description":"JWT to pass to /ocr/poll"},"sessionUrl":{"type":"string","format":"uri","description":"Hosted OCR verification URL to redirect the user to"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"description":"Upstream verification provider unavailable - retry later"}}}}}}
```

## Poll result

> Poll with the \`token\` returned from \`/ocr/auth\` to get the verification decision.\
> Returns 202 while still pending, 200 once the upstream webhook has delivered the\
> result. The \`status\` field doubles as the pending flag and the terminal verdict.

```json
{"openapi":"3.1.0","info":{"title":"Fill Easy Services","version":"1.0.0"},"tags":[{"name":"Facial & ID Scan","description":"Identity verification that bundles **ID document verification**, **face match**, and\n**passive liveness** into a single hosted flow. The user completes capture on a\nFill Easy-hosted page; you receive the decision via webhook or polling.\n\n---\n\n### Flow\n\n1. Call [`POST /ocr/auth`](#tag/OCR/operation/ocrAuth) with a `redirect` URL → receive a\n   `token` and a hosted `sessionUrl`\n\n2. Redirect the user to `sessionUrl` to complete ID capture, liveness, and face match\n\n3. Receive the result via **webhook** or **poll** [`/ocr/poll`](#tag/OCR/operation/ocrPoll)\n\n---\n\n### Result Delivery\n\n**Webhook (recommended)** — Pass a `callbackUrl` in the `/ocr/auth` body. When verification\ncompletes, a `POST` is sent to that URL with the decision wrapped in a\n[`WebhookPayload`](#/components/schemas/WebhookPayload) envelope. Polling remains available\nas a fallback.\n\n**Polling** — Call `/ocr/poll` with the returned `token` until a `200` response is returned.\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"},"OcrResult":{"type":"object","description":"Verification decision returned by `/ocr/poll` (200) and as the `data` field of\nthe `ocr.verification.completed` webhook. `status` carries the terminal verdict.\n`identity`, `faceMatch`, and `liveness` are present only when the upstream\ncheck produced data — for example, a `Declined` outcome with no captured\ndocument may return only `status`.\n","required":["status"],"properties":{"status":{"type":"string","enum":["Approved","Declined","In Review","Kyc Expired"],"description":"Terminal verdict from the verification provider."},"identity":{"type":"object","description":"Extracted ID document fields.","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"fullName":{"type":"string"},"dateOfBirth":{"type":"string"},"documentNumber":{"type":"string"},"documentType":{"type":"string"},"issuingCountry":{"type":"string","description":"ISO 3166-1 alpha-3 code."},"gender":{"type":"string"},"dateOfIssue":{"type":"string"},"expirationDate":{"type":"string"}}},"faceMatch":{"type":"object","description":"1:1 face match between the selfie capture and the ID portrait.","properties":{"score":{"type":"number","description":"Similarity 0-100 (higher is a closer match)."}}},"liveness":{"type":"object","description":"Passive liveness check on the selfie capture.","properties":{"score":{"type":"number","description":"Confidence 0-100 that the subject is a live person."},"method":{"type":"string"}}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Bad Request - Invalid input parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Unauthorized - Token is missing, invalid, or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/ocr/poll":{"post":{"tags":["Facial & ID Scan"],"summary":"Poll result","description":"Poll with the `token` returned from `/ocr/auth` to get the verification decision.\nReturns 202 while still pending, 200 once the upstream webhook has delivered the\nresult. The `status` field doubles as the pending flag and the terminal verdict.","operationId":"ocrPoll","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"$ref":"#/components/schemas/Token"}}}}}},"responses":{"200":{"description":"Verification complete - decision returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OcrResult"}}}},"202":{"description":"Pending - user has not completed verification yet","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["pending"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"410":{"description":"Token is valid but the session result has expired (TTL) or is unknown"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fill-easy.com/facial-and-id-scan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
