> For the complete documentation index, see [llms.txt](https://finext.gitbook.io/one-kyc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://finext.gitbook.io/one-kyc/api/review.md).

# Review tasks

Tenant API methods for **server-side manual review**: list the queue, inspect a task, assign it to the calling API key, approve or reject, comment, change priority, request a step resubmit, and fetch document URLs.

These endpoints are intended for **integrators** that run review outside the admin console (their own back-office or automation). Admin-panel operators use the console UI; see [Admin → Review](/one-kyc/admin/review.md).

Base paths:

| Product | Base                          |
| ------- | ----------------------------- |
| KYC     | `/tenant/v1/kyc/review-tasks` |
| KYB     | `/tenant/v1/kyb/review-tasks` |

Authentication: HMAC-SHA256 with a KYC or KYB API key. See [Authentication](/one-kyc/api/authentication.md).

## Required scopes

| Scope               | Access                                                                   |
| ------------------- | ------------------------------------------------------------------------ |
| `reviews:read`      | KYC: list queue, stats, reject reasons, task detail, comments, resubmits |
| `reviews:write`     | KYC: assign, approve, reject, comment, priority, request resubmit        |
| `media:read`        | KYC: document presigned URLs (together with `reviews:read`)              |
| `kyb.reviews:read`  | KYB read surface                                                         |
| `kyb.reviews:write` | KYB write surface                                                        |
| `kyb.media:read`    | KYB document URLs (together with `kyb.reviews:read`)                     |

KYC keys cannot call `/kyb/review-tasks/*` (HTTP 403). KYB keys cannot call `/kyc/review-tasks/*`.

Mutations are attributed to the **API key** (`actor_type=api_key`): assignment, comments, and final decisions store the key id and display name.

Response fields for actor identity (when present):

| Resource                   | Fields                                                                                                      |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Queue item / task detail   | `assigned_to`, `assigned_to_type` (`admin_user` \| `superadmin_user` \| `api_key`), `assigned_display_name` |
| Task detail after decision | `decision_by`, `decision_by_type`, `decision_display_name`                                                  |
| Comment                    | `author_id`, `author_type`, `author_display_name`                                                           |

## Typical flow

1. Subscribe to `verification.needs_review` (and related webhooks) — see [Webhooks](/one-kyc/api/webhooks.md).
2. `GET .../review-tasks` — pull the queue (`status=pending` or `in_progress`).
3. `GET .../review-tasks/{task_id}` — load detail and `review_reasons`.
4. `POST .../assign` — claim the task for this API key.
5. Inspect media via `GET .../documents/{document_id}/url` when needed.
6. Decide:
   * `POST .../approve`
   * `POST .../reject` with a **canonical** `reason_code` from `GET .../reject-reasons`
   * or `POST .../request-resubmit` for a single step (limits apply)

After a final decision, webhooks emit the terminal verification outcome (`verification.approved` / `verification.declined` / session completed).

## List queue

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks`

KYB equivalent: `GET /tenant/v1/kyb/review-tasks` (same filters; search is company/external id oriented).

### Status filter aliases

| Query value   | Stored statuses                                    |
| ------------- | -------------------------------------------------- |
| `in_progress` | `assigned`                                         |
| `completed`   | `approved`, `rejected`                             |
| other values  | passed through (`pending`, `awaiting_resubmit`, …) |

### Priority values

| Wire value | Numeric priority |
| ---------- | ---------------- |
| `low`      | 1                |
| `medium`   | 2                |
| `high`     | 3                |
| `urgent`   | 4                |

## Stats and reject reasons

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/stats`

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/reject-reasons`

Canonical rejection codes (must be used on `POST .../reject`):

| Code                  | Category  |
| --------------------- | --------- |
| `blurry_document`     | document  |
| `expired_document`    | document  |
| `wrong_document_type` | document  |
| `document_mismatch`   | document  |
| `unreadable_document` | document  |
| `face_not_matching`   | biometric |
| `poor_selfie_quality` | biometric |
| `liveness_failed`     | biometric |
| `face_obscured`       | biometric |
| `sanctions_match`     | aml       |
| `pep_match`           | aml       |
| `adverse_media`       | aml       |
| `suspected_fraud`     | general   |
| `duplicate_account`   | general   |
| `incomplete_data`     | general   |
| `other`               | general   |

Invalid `reason_code` → HTTP 400.

## Task detail, comments, documents

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/{task_id}`

Unassigned tasks omit `assigned_to` / `assigned_to_type` / `assigned_display_name` (they are not defaulted to `admin_user`). After assign or decision, type is one of `admin_user` | `superadmin_user` | `api_key`.

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/{task_id}/comments`

<mark style="color:green;">`POST`</mark> `undefined/v1/kyc/review-tasks/{task_id}/comments`

Comment body field is **`content`** (JSON string). Example: `{"content":"Needs a clearer passport photo"}`. Response includes `author_id`, `author_type` (`api_key` for HMAC callers), and `author_display_name`.

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/{task_id}/documents/{document_id}/url`

`document_id` may be a full storage key or a suffix under the session documents prefix. Path traversal (`..`, `\`) is rejected.

## Mutations: assign, priority, decide

<mark style="color:green;">`POST`</mark> `undefined/v1/kyc/review-tasks/{task_id}/assign`

Assign only succeeds for tasks in `pending` or `awaiting_resubmit`. The task is assigned to the **current API key** (not an admin user).

<mark style="color:purple;">`PATCH`</mark> `undefined/v1/kyc/review-tasks/{task_id}/priority`

<mark style="color:green;">`POST`</mark> `undefined/v1/kyc/review-tasks/{task_id}/approve`

<mark style="color:green;">`POST`</mark> `undefined/v1/kyc/review-tasks/{task_id}/reject`

Optional optimistic concurrency: send `if_unmodified_since` (RFC3339) with the last known `updated_at` / task timestamp when available.

## Resubmit

<mark style="color:green;">`POST`</mark> `undefined/v1/kyc/review-tasks/{task_id}/request-resubmit`

<mark style="color:blue;">`GET`</mark> `undefined/v1/kyc/review-tasks/{task_id}/resubmits`

Resubmit **reason codes** (step quality) are separate from final rejection codes:

| Code               | Meaning            |
| ------------------ | ------------------ |
| `illegible`        | Text unreadable    |
| `blurry`           | Image blurred      |
| `cropped`          | Document cropped   |
| `glare`            | Glare              |
| `wrong_document`   | Wrong type         |
| `expired_document` | Expired            |
| `partial`          | Incomplete capture |

Limits: ≤ 3 resubmits per session, 7-day TTL, one active request per `(session, step)`. See webhooks [Manual Review Resubmit events](/one-kyc/api/webhooks.md#manual-review-resubmit-events-verificationresubmit_).

## KYB

All operations are mirrored under `/tenant/v1/kyb/review-tasks` with `kyb.reviews:*` and `kyb.media:read`. Interactive reference: [KYB API reference](/one-kyc/kyb/api-reference.md#review-tasks) and [OpenAPI](/one-kyc/api/api-reference.md).

## What is admin-only

Not exposed on the Tenant API (admin console / JWT only):

* reassign / unassign to another human reviewer
* delegate to the OneKYC manual-review team
* cancel a resubmit request
* list resubmittable steps helper endpoints used by the console UI

## Related

* [Webhooks](/one-kyc/api/webhooks.md) — `verification.needs_review`, resubmit events, terminal outcomes
* [Authentication](/one-kyc/api/authentication.md) — HMAC and scopes
* [Admin → Review](/one-kyc/admin/review.md) — operator UI workflow
* [OpenAPI](/one-kyc/api/api-reference.md) — full machine-readable spec
