# Remove a person

POST

/v1/identity/users/{userId}/unregister

```sh
curl --request POST \
  --url https://example.com/v1/identity/users/example/unregister \
  --header 'Authorization: Bearer <token>'
```

Removes a person from the tenant, in one step: they’re marked removed (`unregisteredAt`; their record stays, so their history still says who they were), every API key and session of theirs is revoked, and every grant and membership they hold is taken away, all before it answers. Their keys get `401` at once. Their email is free again: adding it makes a new person. Removing someone already removed changes nothing. Refused for yourself and the deployment’s seed user (`identity-user-unregister-refused`), and for the only tenant admin (`last-tenant-admin`). Tenant admins only. Mounted when the identity directory can remove people.

## Authorizations

- **[bearerAuth](https://docs.kindgi.com/v0.1.8/reference/api.md#bearerauth)**

## Parameters

### Path Parameters

**userId**

required

string

\>= 1 characters

### Header Parameters

**Idempotency-Key**

string

\>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per `docs/API-ROUTE-CONVENTIONS.md` §3.1). A retry sent while the first request still runs is answered `409 idempotency-key-in-flight` with `Retry-After`, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets `409 idempotency-key-replay-withheld`, with the first request’s status and when it succeeded (from 0.1.5).

## Responses

### 200

The removed person, and what removing them took away.

application/json

A removed person, and what removing them took away (each 0 when they were already removed).

object

**user**

required

Tenant-scoped user record (admin plane). `primaryEmail` may be redacted on the wire based on tenant policy (the routes treat it as opaque). `metadata` is free-form JSON — deployments carry IdP claims / provisioning source / roles here.

object

**userId**

required

string

**tenantId**

required

string format: uuid

**primaryEmail**

string

**displayName**

string

**createdAt**

required

string format: date-time

**lastActiveAt**

string format: date-time

**unregisteredAt**

When they were removed from the tenant (`POST /v1/identity/users/{userId}/unregister`); absent while they are here.

string format: date-time

**metadata**

object

**_key_**

additional properties

any

**grants**

The person’s grants: only on `GET /v1/identity/users?include=grants`, and only from a runtime that reads grants.

object

**userId**

required

string

**tenantAdmin**

Whether the person is a tenant admin. Absent when the runtime has no authorization store: nothing grants it then.

boolean

**tenantMember**

Whether the person is a tenant member: they read the tenant’s settings (providers, policies, adapters, signing keys, deployments), not its projects. A person is one from being added. Absent when the runtime has no authorization store, or doesn’t report it.

boolean

**projects**

required

Direct project memberships.

Array\<object>

A person’s direct role on a project.

object

**projectId**

required

string

**role**

required

Role on a project, as read. `member` is only read, on a role given before it was retired: it grants what `viewer` does, and writes refuse it.

string

Allowed values: viewer editor owner admin member

**teams**

required

Team memberships.

Array\<object>

A person’s role in a team.

object

**teamId**

required

string

**role**

required

Role on a team membership.

string

Allowed values: member admin

**reviewer**

A person’s active entry on the reviewer roster.

object

**role**

required

Reviewer role class. Hierarchy: standard < senior < admin.

string

Allowed values: standard senior admin

**keysRevoked**

required

integer

**sessionsRevoked**

required

integer

**grantsRemoved**

required

integer

##### Example

```json
{
  "user": {
    "grants": {
      "projects": [
        {
          "role": "viewer"
        }
      ],
      "teams": [
        {
          "role": "member"
        }
      ],
      "reviewer": {
        "role": "standard"
      }
    }
  }
}
```

### 400

Malformed request body.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 401

Missing / malformed / expired / revoked bearer token.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 403

Not a tenant admin.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 404

No user with that id under this tenant (`identity-user-not-found`).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 409

Yourself or the seed user (`identity-user-unregister-refused`, `details.reason`), the only tenant admin (`last-tenant-admin`), or an idempotency conflict.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 500

Server error (unmapped domain code or framework crash).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

## See also

- [`GET /v1/identity/users`: List users in the tenant](https://docs.kindgi.com/v0.1.8/reference/api/operations/identityuserslist.md)
- [`POST /v1/identity/users`: Add a person](https://docs.kindgi.com/v0.1.8/reference/api/operations/identityuserscreate.md)
- [`GET /v1/identity/users/{userId}`: Get a user by id](https://docs.kindgi.com/v0.1.8/reference/api/operations/identityusersget.md)
- [`GET /v1/identity/users/{userId}/sessions`: List active sessions for a user](https://docs.kindgi.com/v0.1.8/reference/api/operations/identityuserslistsessions.md)
- [Error code `identity-user-not-found`](https://docs.kindgi.com/v0.1.8/reference/errors.md#identity-user-not-found)
- [Error code `identity-user-unregister-refused`](https://docs.kindgi.com/v0.1.8/reference/errors.md#identity-user-unregister-refused)
- [Error code `last-tenant-admin`](https://docs.kindgi.com/v0.1.8/reference/errors.md#last-tenant-admin)
- [Every error code](https://docs.kindgi.com/v0.1.8/reference/errors.md)
