> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Feature Status

> Approve, decline, or move a single verification step (OCR, Liveness, Face Match, AML, POA, Phone…) to review without changing the overall session decision.

export const AgentPromptAccordion = ({prompt, title = "AI Agent Integration Prompt"}) => {
  const [copied, setCopied] = React.useState(false);
  const handleCopy = e => {
    e.stopPropagation();
    if (!prompt) return;
    navigator.clipboard.writeText(prompt.trim()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };
  const agents = ["Claude Code", "Codex", "Cursor", "Devin", "Windsurf", "GitHub Copilot"];
  return <div className="didit-agent-card">
      {}
      <div className="didit-agent-titlebar">
        <div className="didit-agent-dots" aria-hidden="true">
          <span className="didit-agent-dot didit-agent-dot-red"></span>
          <span className="didit-agent-dot didit-agent-dot-yellow"></span>
          <span className="didit-agent-dot didit-agent-dot-green"></span>
        </div>
        <span className="didit-agent-filename">{title}</span>
        <button type="button" className={`didit-agent-copy ${copied ? "didit-agent-copy-copied" : ""}`} onClick={handleCopy} title="Copy prompt to clipboard" aria-label={copied ? "Copied!" : "Copy prompt to clipboard"}>
          {copied ? <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Copied</span>
            </> : <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <rect x="5" y="5" width="9" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.5" />
                <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              <span>Copy</span>
            </>}
        </button>
      </div>

      {}
      <pre className="didit-agent-body"><code>{prompt.trim()}</code></pre>

      {}
      <div className="didit-agent-footer">
        <span className="didit-agent-footer-label">Paste into</span>
        <div className="didit-agent-chips">
          {agents.map(name => <span key={name} className="didit-agent-chip">{name}</span>)}
        </div>
      </div>
    </div>;
};

<AgentPromptAccordion
  title="Update Feature Status Prompt"
  prompt={`Approve, decline, or move a SINGLE verification step (feature) of a Didit session to review — without changing the overall session decision.

Endpoint:
PATCH https://verification.didit.me/v3/session/{session_id}/features/{node_id}/update-status/

Authentication:
x-api-key (client API key) or a user-auth token. Privilege: write:sessions.

Path parameters:
- session_id (UUID) — KYC or KYB; Didit looks it up in both tables.
- node_id — the workflow graph node ID of the step (e.g. feature_ocr_1, feature_liveness_1, feature_aml_1). Use the literal "default" for non-graph (single-step) workflows where the step has no node ID.

Request body:
- new_status (string, required) — one of "Approved", "Declined", "In Review". Must differ from the step's current status.
- comment (string, optional) — note saved on the session review trail for this feature change.

Which steps this works on:
Every per-step feature record: OCR/ID, Liveness, Face Match, NFC, AML, Proof of Address (POA), Phone, Email, Database Validation, Questionnaire, and the KYB registry / documents / key-people checks.

Difference vs update-status:
- update-status changes the OVERALL session decision (Approved/Declined/Resubmitted).
- THIS endpoint changes ONE step's status only; the overall session status is left as-is.

Not allowed:
- Standalone API sessions (session_type = API) return 400.

curl example — approve the ID/OCR step:
curl -X PATCH https://verification.didit.me/v3/session/<SESSION_ID>/features/feature_ocr_1/update-status/ \\
-H "x-api-key: <API_KEY>" \\
-H "Content-Type: application/json" \\
-d '{ "new_status": "Approved", "comment": "Document manually verified" }'

Response: { session_id, node_id, feature_type, new_status }.

Side effects:
- Fires a data.updated webhook.
- Appends an activity entry (with actor attribution and your comment) to the session review trail.

Failure modes:
- 400 — new_status invalid or unchanged, or the session is a standalone API session.
- 403 — invalid credentials, or the caller lacks write:sessions.
- 404 — session not found, or no feature has the given node_id.

For end-to-end Didit integration, paste in the full prompt at /integration/integration-prompt.`}
/>

## What this does

A verification session is made up of individual **features** (steps) — ID/OCR, Liveness, Face Match, AML, Proof of Address, Phone, and so on. This endpoint lets you set the status of **one** of those steps — `Approved`, `Declined`, or `In Review` — **without** changing the overall session decision.

Use [update-status](/sessions-api/update-status) when you want to approve, decline, or re-open the whole session. Use **this** endpoint when you only want to record a decision on a single step (for example, mark the Face Match step as `Declined` for your own review workflow while leaving the session in its current state).

## Targeting a step with `node_id`

In graph-based workflows each step has a `node_id` (for example `feature_ocr_1`, `feature_liveness_1`, `feature_aml_1`). You can find these in the [session decision](/sessions-api/retrieve-session) — each feature in a V3 decision carries its `node_id`.

For **non-graph (single-step) workflows** the underlying feature has no node ID. Pass the literal value `default` as the `nodeId` to target it.

## KYC and KYB support

Works identically for **User Verification (KYC)** and **Business Verification (KYB)** sessions — Didit resolves the `sessionId` across both. Supported step types include ID/OCR, Liveness, Face Match, NFC, AML, Proof of Address, Phone, Email, Database Validation, Questionnaire, and the KYB registry / documents / key-people checks.

<Note>
  Standalone API sessions (those created through the standalone verification APIs, `session_type = API`) cannot have individual feature statuses changed — the endpoint returns `400`.
</Note>

## Examples

<Tabs>
  <Tab title="Approve a step">
    ```bash theme={null}
    curl -X PATCH https://verification.didit.me/v3/session/4c5c7f3a-.../features/feature_ocr_1/update-status/ \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "new_status": "Approved",
        "comment": "Document manually verified by compliance"
      }'
    ```
  </Tab>

  <Tab title="Decline the Face Match step">
    ```bash theme={null}
    curl -X PATCH https://verification.didit.me/v3/session/4c5c7f3a-.../features/feature_face_match/update-status/ \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "new_status": "Declined"
      }'
    ```
  </Tab>

  <Tab title="Single-step workflow (default node)">
    ```bash theme={null}
    curl -X PATCH https://verification.didit.me/v3/session/4c5c7f3a-.../features/default/update-status/ \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "new_status": "In Review"
      }'
    ```
  </Tab>
</Tabs>

## What happens after an update

* **Webhook** — a `data.updated` event fires on the session so your systems and analytics stay in sync.
* **Audit trail** — the change is recorded on the session's review trail with the actor (API key or user) and your optional `comment`, visible in the console's activity timeline.
* **Overall session status is untouched** — to also change the final decision, call [update-status](/sessions-api/update-status) separately.

## Permission

Requires the `write:sessions` privilege, with either a client API key (`x-api-key`) or a user authorization header.

## Related

* [Update session status](/sessions-api/update-status) — change the overall session decision.
* [Update AML hit status](/sessions-api/update-aml-hit-status) — review individual AML matches.
* [Retrieve session](/sessions-api/retrieve-session) — fetch the decision (and each feature's `node_id`).
* [Webhooks](/integration/webhooks) — subscribe to `data.updated`.


## OpenAPI

````yaml PATCH /v3/session/{sessionId}/features/{nodeId}/update-status/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/session/{sessionId}/features/{nodeId}/update-status/:
    patch:
      tags:
        - Sessions
      summary: Update an individual feature (step) status
      description: >-
        Set the status of a single verification feature (step) within a session
        **without changing the overall session decision**. Target the feature by
        its workflow graph `nodeId` (use `default` for non-graph workflows where
        the step has no node).


        Works for both User Verification (KYC) and Business Verification (KYB)
        sessions and every step type — ID/OCR, Liveness, Face Match, NFC, AML,
        Proof of Address, Phone, Email, Database Validation, Questionnaire, and
        the KYB registry / documents / key-people checks.


        `new_status` must be one of `Approved`, `Declined`, or `In Review`, and
        must differ from the feature's current status. A successful call fires a
        `data.updated` webhook and appends an activity entry (with actor
        attribution) to the session's review trail. This endpoint is **not**
        available for standalone API sessions (`session_type = API`).


        Authenticate with your API key (`x-api-key`) or a user authorization
        header — either must carry the `write:sessions` privilege.
      operationId: patch_v3_session_update_feature_status
      parameters:
        - in: path
          name: sessionId
          required: true
          description: >-
            UUID of the verification session. Accepts both user (KYC) and
            business (KYB) session IDs — the service resolves the ID across both
            session types.
          schema:
            type: string
            format: uuid
            example: 11111111-2222-3333-4444-555555555555
        - in: path
          name: nodeId
          required: true
          description: >-
            Workflow graph node ID of the feature to update (for example
            `feature_ocr_1`). Use the literal value `default` for non-graph
            (single-step) workflows where the feature has no node ID.
          schema:
            type: string
            example: feature_ocr_1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - new_status
              properties:
                new_status:
                  type: string
                  description: >-
                    Target status for this feature. Must differ from the current
                    value.
                  enum:
                    - Approved
                    - Declined
                    - In Review
                  example: Approved
                comment:
                  type: string
                  description: >-
                    Optional free-text note recorded on the session's review
                    trail for this feature change.
                  example: Document manually verified by compliance.
      responses:
        '200':
          description: >-
            Feature status updated. Returns the targeted feature, its node ID,
            and the new status.
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                    format: uuid
                  node_id:
                    type: string
                    example: feature_ocr_1
                  feature_type:
                    type: string
                    description: >-
                      Model name of the updated feature (e.g. `KYC`, `Face`,
                      `FaceMatch`, `AML`, `POA`).
                    example: KYC
                  new_status:
                    type: string
                    example: Approved
              example:
                session_id: 11111111-2222-3333-4444-555555555555
                node_id: feature_ocr_1
                feature_type: KYC
                new_status: Approved
        '400':
          description: >-
            Validation error. Returned when `new_status` is invalid or
            unchanged, or when the session is a standalone API session.
          content:
            application/json:
              examples:
                Same Status:
                  summary: new_status equals the current status
                  value:
                    new_status: The new status is the same as the current status.
                API Session:
                  summary: Feature status cannot be changed on standalone API sessions
                  value:
                    detail: Cannot change feature status for API sessions.
        '403':
          description: >-
            Missing/invalid credentials or insufficient permissions. This API
            returns `403` for authentication failures — never `401`.
          content:
            application/json:
              examples:
                Invalid Credentials:
                  summary: Missing or invalid x-api-key
                  value:
                    detail: >-
                      Authentication credentials were not provided or are
                      invalid.
                Missing Privilege:
                  summary: API key lacks write:sessions
                  value:
                    detail: You do not have permission to perform this action.
        '404':
          description: >-
            The session was not found, or it has no feature with the given
            `nodeId`.
          content:
            application/json:
              examples:
                Session Not Found:
                  summary: Unknown session_id
                  value:
                    detail: Session not found.
                Feature Not Found:
                  summary: No feature for this node_id
                  value:
                    detail: >-
                      No feature found with node_id 'feature_ocr_1' in this
                      session.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: |-
            curl -X PATCH \
              https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/features/feature_ocr_1/update-status/ \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "new_status": "Approved",
                "comment": "Document manually verified by compliance."
              }'
        - lang: python
          label: Python
          source: |-
            import requests

            response = requests.patch(
                "https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/features/feature_ocr_1/update-status/",
                headers={"x-api-key": "YOUR_API_KEY", "Content-Type": "application/json"},
                json={"new_status": "Approved", "comment": "Document manually verified by compliance."},
            )
            print(response.json())
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````