---
title: "Set Identity Status Endpoint"
method: POST
path: "/api/v1/identities/{identity_id}/status"
tags: ["identities"]
---

# Set Identity Status Endpoint

`POST /api/v1/identities/{identity_id}/status`

## Request

- Base URL: `https://api.withverifa.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.withverifa.com/api/v1/identities/{identity_id}/status`
- Auth: none declared

Manually set an identity's lifecycle status.

Distinct from the case path (case approve / reject, which carries a
reviewer decision on a specific session) and from the workflow path
(the engine writes status at session completion under the
``_resolve_identity_status_transition`` guard). Use this endpoint for:

  - Bulk-import / migration ("we already KYC'd these elsewhere").
  - Reviewer override without a session in flight.
  - Post-acquisition mark-as-verified for existing customers.
  - Fraud freeze before the user attempts a verification.

Status values:
  - ``pending`` — record exists, no verification yet (or reset).
  - ``verified`` — the person is approved.
  - ``rejected`` — the person is declined. ``reason`` (if given) is
    captured in the audit log; the identity row itself does not store
    a rejection reason (those live on the case / session_result).
  - ``under_review`` — manually parked for reviewer attention.

``merged`` and ``redacted`` are owned by the merge and GDPR-redaction
flows and are rejected here.

Returns the updated identity (same shape as GET /identities/{id}).
Dispatches the ``identity.status_changed`` webhook with the
``from``/``to`` transition. Also dispatches the legacy
``identity.updated`` event for backward compatibility.

Errors:
  - 404 — identity not found in this org / environment.
  - 409 — ``expected_current_status`` was provided and didn't match;
    the response body includes the actual current status so a UI can
    re-prompt the reviewer.
  - 422 — invalid status value, or the identity is in a terminal state
    (``merged`` / ``redacted``), or the body status is owned by another
    flow.

## Path parameters

- `identity_id` string, required

## Request body

- SetIdentityStatusRequest: Request body for POST /api/v1/identities/{id}/status. Verb-shaped sibling of the generic PATCH /identities/{id} for the one field — status — that needs a dedicated audit action and webhook event. The generic PATCH no longer accepts ``status``.
  - `status` string, required: Target status. One of: ``pending``, ``verified``, ``rejected``, ``under_review``. ``merged`` and ``redacted`` are owned by the merge and GDPR-redaction flows and are not accepted here.
  - `reason` string, nullable: Optional human-readable reason. Captured in the audit log metadata and the ``identity.status_changed`` webhook payload; the identity row itself no longer stores a reason column. Required by convention when ``status='rejected'`` so downstream consumers have context, though the API does not enforce this.
  - `expected_current_status` string, nullable: Optional optimistic-concurrency guard. When supplied and the row's current status doesn't match, the API returns 409 with the actual current status — letting a UI re-prompt with fresh data instead of silently overwriting another reviewer's change.

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/withverifa/apis/verifa.md) · [All operations](https://skmtc.dev/withverifa/apis/verifa/llms.txt) · [OpenAPI document](https://skmtc.dev/withverifa/apis/verifa/revisions/7288c82c9e33?raw)
