# Manual verification

> Without a registry integration, PAN, bank, GST, company and Udyam checks are verified by a reviewer against a document the applicant uploads.

Source: https://docs.okyc.stream/concepts/manual-verification

Some checks normally ask an official registry (the income-tax PAN service, a penny-drop bank check, the GST
portal, MCA, Udyam). Until a registry provider is connected, OKYC routes these checks to the &#x2A;*`manual`**
provider: the applicant enters the number **and** uploads a supporting document, and a reviewer confirms it.

| Check                           | Applicant uploads                  | Compared with the typed details      |
| ------------------------------- | ---------------------------------- | ------------------------------------ |
| `in.pan.verify` (PAN)           | PAN card                           | PAN, name, date of birth             |
| `in.bank.verify` (bank account) | Cancelled cheque or bank statement | Account number, IFSC, account holder |
| `in.gstin.verify` (GST)         | GST registration certificate       | GSTIN                                |
| `in.mca.company` (company)      | Certificate of incorporation       | CIN / LLPIN                          |
| `in.udyam.verify` (Udyam)       | Udyam registration certificate     | Udyam number                         |

Everything else needs no external service and runs automatically: Aadhaar Secure QR and Offline XML (signature
verified), selfie liveness, face match, document reading, sanctions screening, name and date-of-birth matching.

## What the applicant sees

The step shows the usual fields plus an upload. When several documents are accepted (bank account), the
applicant picks one first. The document is read automatically so the reviewer doesn't have to type anything.

After submitting, the step shows **Submitted for review** and the applicant continues with the next step: a check
waiting for a reviewer never fails the step or uses up attempts. The same applies when an uploaded document can't
be read automatically — a reviewer looks at it.

## What happens to the session

* A manual check stays `inconclusive` with `provider: "manual"` until a reviewer decides. The session goes to
  `review` with the reason `manual_verification` — it is **never approved automatically**.
* Rules are evaluated as if the pending manual checks were confirmed. So a session is still **declined
  automatically** for things a reviewer's confirmation can't fix (a face mismatch, a failed Aadhaar check), and
  a rule like "PAN not passed → decline" does not decline a session only because the PAN is waiting for review.
* A workflow without manual checks (for example Aadhaar + selfie + sanctions) is still decided automatically.

## Reviewing

On the session page, **Manual verification** lists each check with the uploaded document and a side-by-side
comparison: what the applicant entered, what the document says, and whether they match. The name printed on
the document is also compared with the identity verified from Aadhaar. Values are shown masked, as everywhere
else.

* **Confirm** marks the check `passed`. The values printed on the (possibly corrected) document become the
  check's result — the name and date of birth on a PAN card, the account holder on a cheque — so matching and
  rules treat it like a registry answer.
* **Reject** marks it `failed`, with a reason: document doesn't match, unreadable, wrong or invalid document,
  suspected fraud, or other.
* A misread value can be fixed first with a [reviewer correction](https://docs.okyc.stream/concepts/reviewer-corrections.md).
* **Approve** is disabled until every manual check is confirmed or rejected; the API refuses it with
  `manual_checks_pending`. Decline and "request resubmission" are always available.
* Like corrections, reviews are allowed only **before a final decision**, and are recorded in the audit log
  (`check.manual_confirmed` / `check.manual_rejected`) without any values.

## In the API and webhooks

Every check has `verified_by`:

| `verified_by` | Meaning                                                       |
| ------------- | ------------------------------------------------------------- |
| `source`      | The issuing registry or a cryptographic check answered.       |
| `reviewer`    | Provider `manual`: a reviewer compared the uploaded document. |
| `null`        | Not decided yet.                                              |

Use it if your own policy treats reviewer-verified data differently from registry-verified data.

## Adding a registry integration later

This is a configuration change on your account, not a code change. A check can be routed to a registry first,
with `manual` as the fallback — for example PAN through your aggregator. Ask us at
[support@okyc.stream](mailto:support@okyc.stream) to set one up. From then on:

* the step no longer asks for the document;
* the registry answers the check (`verified_by: "source"`);
* if the registry is down, the check falls back to manual review instead of failing.

Live mode never uses the `mock` provider, whatever the routing says. Test mode behaves like live: checks routed
to `manual` are manual in test sessions too; checks routed to a registry use the
[magic values](https://docs.okyc.stream/get-started/sandbox.md) instead. To try the reviewer's side, use **Use test data** on the step: it
submits the value with a sample document (e.g. a sandbox PAN card) whose fields are read back for the
side-by-side view.

## Integrations that live sessions need

| Step                   | Needs                             | Without it                                                                    |
| ---------------------- | --------------------------------- | ----------------------------------------------------------------------------- |
| Phone OTP              | A WhatsApp/SMS provider           | Live sessions are refused (`integration_not_configured`); test sessions work. |
| Aadhaar via DigiLocker | DigiLocker (API Setu) credentials | Live sessions offer Secure QR and Offline XML only.                           |

The workflow builder shows a warning on these steps, and a **Manual review** badge on steps that will be
verified manually.

## Errors

| Code                         | When                                                                              |
| ---------------------------- | --------------------------------------------------------------------------------- |
| `manual_checks_pending`      | Approving while a manual check is still waiting for review.                       |
| `decision_final`             | Reviewing a check after the session was approved, declined, expired or cancelled. |
| `session_processing`         | Checks are still running; try again shortly.                                      |
| `not_manual`                 | The check was answered by a registry; its result is locked.                       |
| `reason_required`            | Rejecting without a reason.                                                       |
| `integration_not_configured` | Creating a live session for a workflow that needs a missing integration.          |
