> ## 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.

# User Operations

> Create, read, update, change status, and delete Didit vendor User entities via the Management API. Pay-per-call from $0.30, no contracts.

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="User Operations Prompt"
  prompt={`# Goal — full CRUD over Didit User entities

Core CRUD operations sit under \`https://verification.didit.me/v3/users/\` authenticated with \`x-api-key: $DIDIT_API_KEY\`. Profile attachment endpoints use the organization/application path and the User's \`didit_internal_id\`. Each User is keyed by \`vendor_data\` (case-sensitive, unique per application).

## Endpoint catalog

| Action | Method + path |
|---|---|
| List users | \`GET /v3/users/\` |
| Get one user | \`GET /v3/users/{vendor_data}/\` |
| Create user | \`POST /v3/users/create/\` |
| Upload profile face | \`POST /v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/\` |
| Update profile | \`PATCH /v3/users/{vendor_data}/\` |
| Change status | \`PATCH /v3/users/{vendor_data}/update-status/\` |
| Batch delete | \`POST /v3/users/delete/\` |

## List (with filters)

\`\`\`bash
curl -G https://verification.didit.me/v3/users/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
--data-urlencode "status=ACTIVE" \\
--data-urlencode "search=jane" \\
--data-urlencode "page_size=50"
\`\`\`

## Get one user

\`\`\`bash
curl https://verification.didit.me/v3/users/user-42/ \\
-H "x-api-key: $DIDIT_API_KEY"
\`\`\`

## Create

\`\`\`bash
curl -X POST https://verification.didit.me/v3/users/create/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"vendor_data": "user-42",
"display_name": "Jane Doe",
"metadata": {"tier": "premium", "signup_source": "web"}
}'
\`\`\`

Not idempotent — retrying with the same \`vendor_data\` returns conflict. \`GET\` first or PATCH instead.

## Upload an imported profile face

\`\`\`bash
# First read didit_internal_id from GET /v3/users/{vendor_data}/
curl -X POST https://verification.didit.me/v3/organization/$ORGANIZATION_ID/application/$APPLICATION_ID/vendor-users/by-id/$DIDIT_INTERNAL_ID/faces/upload/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"image": "<base64-encoded-jpg-or-png>", "comment": "Imported from previous KYC provider"}'
\`\`\`

This attaches a trusted face image to the User profile and enrolls it for duplicate detection and face search. It does not add the face to a blocklist.

## Update profile

\`\`\`bash
curl -X PATCH https://verification.didit.me/v3/users/user-42/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"metadata": {"tier": "enterprise"}}'
\`\`\`

Mutable: \`display_name\`, \`metadata\`, \`tags\`. Read-only (verified): \`full_name\`, \`date_of_birth\`, \`portrait_image\`, all aggregate counters, \`features\` map.

## Change status

\`\`\`bash
curl -X PATCH https://verification.didit.me/v3/users/user-42/update-status/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"status": "BLOCKED", "reason": "Chargeback fraud pattern"}'
\`\`\`

Valid statuses: \`ACTIVE\`, \`FLAGGED\`, \`BLOCKED\`. \`BLOCKED\` users have new sessions auto-declined.

## Batch delete

\`\`\`bash
curl -X POST https://verification.didit.me/v3/users/delete/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"vendor_data": ["user-42", "user-43", "user-44"]}'
\`\`\`

Idempotent — already-deleted is a no-op. Returns a per-item result. History is retained for the configured retention window, then hard-deleted.

## Webhooks fired

| Operation | Event |
|---|---|
| create | \`user.data.updated\` |
| update (PATCH) | \`user.data.updated\` with \`changed_fields\` |
| update-status | \`user.status.updated\` |
| delete | \`user.data.updated\` with \`deleted_at\` set |

## Failure modes

- \`401\` — missing / invalid \`x-api-key\`.
- \`403\` — your role lacks the permission (see /console/roles-permissions; DEVELOPER cannot PATCH).
- \`409\` on create — \`vendor_data\` already exists; switch to PATCH.
- \`404\` — no entity for that \`vendor_data\` (case-sensitive!).
- \`429\` — rate-limited; back off using \`Retry-After\`.

## Response shape

See /reference/data-models and /entities/users/data-model for the full User schema.

## Sources of truth

- /management-api/users/list, /management-api/users/get, /management-api/users/create — per-endpoint reference
- /entities/users/data-model — field-by-field schema
- /entities/webhooks — entity event payloads
- /integration/integration-prompt — canonical end-to-end prompt
`}
/>

Core User entity management happens through public endpoints under `/v3/users/`. Profile attachments, such as imported face upload, use the organization/application path with `didit_internal_id`. This page gives you the conceptual walkthrough — see the [API reference](/management-api/users/list) for full request / response schemas.

## List users

**`GET /v3/users/`**

Returns a paginated list of users for your application. Supports filters on status, search, date range, and more.

```bash theme={null}
curl -G https://verification.didit.me/v3/users/ \
  -H "x-api-key: YOUR_API_KEY" \
  --data-urlencode "status=ACTIVE" \
  --data-urlencode "search=jane" \
  --data-urlencode "page_size=50"
```

Use-cases:

* Sync a subset of users to your data warehouse each day.
* Find flagged users for an analyst queue.
* Search users by display name.

## Get a user

**`GET /v3/users/{vendor_data}/`**

Retrieve a single user by `vendor_data`. Returns the full [data model](/entities/users/data-model) including aggregated counters.

```bash theme={null}
curl https://verification.didit.me/v3/users/user-42/ \
  -H "x-api-key: YOUR_API_KEY"
```

<Note>
  `vendor_data` in the URL is case-sensitive. Always pass the exact value you used on session creation.
</Note>

## Create a user

**`POST /v3/users/create/`**

Create a User entity before any session runs. Useful for:

* Seeding metadata or custom fields before the customer verifies.
* Setting an initial status (e.g. `FLAGGED` while your onboarding team reviews manual documents).
* Pre-loading users from an existing database so you have a complete roster from day one.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/users/create/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_data": "user-42",
    "display_name": "Jane Doe",
    "metadata": { "tier": "premium", "signup_source": "web" }
  }'
```

If a user with that `vendor_data` already exists, the call returns a conflict error — use `PATCH` to update instead.

## Upload an imported face

**`POST /v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/`**

Attach a trusted face image to an existing User profile. This is the right follow-up when you import users from another provider and want Didit to carry their face evidence before the first Didit session.

```bash theme={null}
# First create or retrieve the User and read didit_internal_id from the response.
curl -X POST https://verification.didit.me/v3/organization/$ORGANIZATION_ID/application/$APPLICATION_ID/vendor-users/by-id/$DIDIT_INTERNAL_ID/faces/upload/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "<base64-encoded-jpg-or-png>",
    "comment": "Imported from previous KYC provider"
  }'
```

See [Upload User Face](/management-api/users/upload-face) for request fields, limits, list/delete endpoints, and the blocklist distinction.

## Update a user

**`PATCH /v3/users/{vendor_data}/`**

Update mutable profile fields. Most fields derived from verified sessions are read-only — attempting to change them via PATCH will either be ignored or flagged in the audit log.

**Mutable fields:** `display_name`, `metadata`, `tags`.
**Read-only after verification:** `full_name`, `date_of_birth`, `portrait_image`, all aggregate counters, `features` map.

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/users/user-42/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "tier": "enterprise" } }'
```

Emits a `user.data.updated` webhook with the `changed_fields` array.

## Change status

**`PATCH /v3/users/{vendor_data}/update-status/`**

Move a user between `ACTIVE`, `FLAGGED`, and `BLOCKED`. Status changes propagate to future sessions and transactions.

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/users/user-42/update-status/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "BLOCKED",
    "reason": "Chargeback fraud pattern detected"
  }'
```

| From → to            | Common trigger                                                     |
| -------------------- | ------------------------------------------------------------------ |
| `ACTIVE` → `FLAGGED` | Transaction rule, analyst review, ongoing AML hit                  |
| `ACTIVE` → `BLOCKED` | Confirmed fraud, session declined with auto-block, blocklist match |
| `FLAGGED` → `ACTIVE` | Analyst cleared review                                             |
| `BLOCKED` → `ACTIVE` | Manual unblock by an analyst                                       |

Emits a `user.status.updated` webhook.

## Delete users (batch)

**`POST /v3/users/delete/`**

Delete one or more users. History (sessions, transactions, audit trail) is retained for your configured [data retention](/console/data-retention) period, then hard-deleted.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/users/delete/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_data": ["user-42", "user-43", "user-44"]
  }'
```

Returns a per-item result so you can detect which items did not exist or could not be deleted.

## Permission model

All `/v3/users/*` endpoints are scoped by the `users` permission resource. Your API key's role determines which operations are allowed:

| Role                | list | get | create | update | update-status | delete |
| ------------------- | :--: | :-: | :----: | :----: | :-----------: | :----: |
| OWNER               |   ✅  |  ✅  |    ✅   |    ✅   |       ✅       |    ✅   |
| ADMIN               |   ✅  |  ✅  |    ✅   |    ✅   |       ✅       |    ✅   |
| COMPLIANCE\_OFFICER |   ✅  |  ✅  |    ❌   |    ✅   |       ✅       |    ❌   |
| DEVELOPER           |   ✅  |  ✅  |    ✅   |    ❌   |       ❌       |    ❌   |
| READER              |   ✅  |  ✅  |    ❌   |    ❌   |       ❌       |    ❌   |

See [Roles & permissions](/console/roles-permissions) for the full matrix.

## Rate limits and idempotency

* All `/v3/users/*` endpoints are subject to the standard [rate limits](/integration/rate-limiting).
* `create` is **not** idempotent — retrying with the same `vendor_data` returns a conflict. De-dupe on your side, or always `GET` first.
* `delete` is idempotent — deleting an already-deleted user is a no-op.

## Webhooks fired by these operations

| Operation       | Webhook                                     |
| --------------- | ------------------------------------------- |
| `create`        | `user.data.updated`                         |
| `update`        | `user.data.updated` (with `changed_fields`) |
| `update-status` | `user.status.updated`                       |
| `delete`        | `user.data.updated` (with `deleted_at` set) |

## Next steps

<CardGroup cols={3}>
  <Card title="Data model" icon="database" href="/entities/users/data-model">
    Full field reference.
  </Card>

  <Card title="List API" icon="list" href="/management-api/users/list">
    GET /v3/users/ schema.
  </Card>

  <Card title="Create API" icon="plus" href="/management-api/users/create">
    POST /v3/users/create/ schema.
  </Card>

  <Card title="Upload face" icon="face-viewfinder" href="/management-api/users/upload-face">
    Attach imported face images to User profiles.
  </Card>
</CardGroup>
