# Purge a closed tenant, for good

POST

/v1/system/tenants/{tenantId}/purge

```sh
curl --request POST \
  --url https://example.com/v1/system/tenants/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/purge \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{ "confirm": "example" }'
```

Deletes a `closing` tenant whose 30-day export window has passed: every row of it, its artifacts’ bytes and its authorization store. Once nothing of it is left, its purge record is written, so a restore from an older backup purges it again, and it’s marked purged: its tenants row stays, and nothing of it signs in or is served. Then, once each server has seen the mark, it deletes again what work under way at the mark wrote meanwhile. Irreversible. `confirm` is the tenant’s slug, a second check on the id. It answers when done. Safe to run again: a run that stopped part-way (`complete: false`, or a request that ended before its answer) is finished by the next, and on a tenant already purged it deletes what was written after its mark, leaving its mark and its record as they were. A run again is a new request: a new Idempotency-Key, or none. Takes its own scope, `system:tenants:purge`, which no other scope includes, or `kindgi:system`.

## Authorizations

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

## Parameters

### Path Parameters

**tenantId**

required

string format: uuid

The tenant’s id.

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

## Request Bodyrequired

application/json

object

**confirm**

required

The tenant’s slug, a second check on the id.

string

\>= 1 characters

##### Examplegenerated

```json
{
  "confirm": "example"
}
```

## Responses

### 200

What it deleted, and what of it is left.

application/json

object

**tenantId**

required

string format: uuid

**complete**

required

`true`: nothing of the tenant is left, its purge record is written, and it’s marked purged. `false`: `left` and `objectsLeft` say what is; run it again.

boolean

**alreadyPurged**

required

It was marked purged before this run: what this run deleted was written after its mark. Its mark and its record stay as they were.

boolean

**purgedAt**

When it was marked purged. Absent while something of it from before the mark is left.

string format: date-time

**deleted**

required

Rows this run deleted, per table with any: table names and counts, never the rows’ content.

Array\<object>

A tenant’s rows in one table: the table’s name and a count.

object

**table**

required

string

**rows**

required

integer

\>= 1

**objectsDeleted**

required

Objects this run deleted from the artifacts’ store.

integer

**authzStoreDeleted**

required

Whether this run deleted its authorization store.

boolean

**left**

required

Rows of it still there afterwards, per table; empty when none are. A table the purge doesn’t delete from is named too: report it.

Array\<object>

A tenant’s rows in one table: the table’s name and a count.

object

**table**

required

string

**rows**

required

integer

\>= 1

**objectsLeft**

required

Objects still under its prefix in the artifacts’ store.

integer

**leftBecause**

Why what’s left wasn’t deleted, when it’s a setting the runtime lacks.

string

##### Examplegenerated

```json
{
  "tenantId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
  "complete": true,
  "alreadyPurged": true,
  "purgedAt": "2026-04-15T12:00:00Z",
  "deleted": [
    {
      "table": "example",
      "rows": 1
    }
  ],
  "objectsDeleted": 1,
  "authzStoreDeleted": true,
  "left": [
    {
      "table": "example",
      "rows": 1
    }
  ],
  "objectsLeft": 1,
  "leftBecause": "example"
}
```

### 400

No `confirm`, or one that isn’t the tenant’s slug (`tenant-slug-mismatch`). Nothing was changed.

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

A tenant’s key or session (`system-principal-required`), or a system key without `system:tenants:purge` (`system-scope-missing`).

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 tenant with that id (`tenant-not-found`). A purged one is found, for a run again.

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

Nothing was changed: the tenant isn’t closing (`tenant-not-closing`), or its export window is still open (`tenant-export-window-open`); the runtime has nowhere set to keep purge records (`purge-record-unset`), or lacks the setting that reaches what the tenant holds (`purge-setting-missing`); or an Idempotency-Key reused with another 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"
  }
}
```

### 413

The request body is over the API’s limit (`request-too-large`; `details.maxBytes` says how much).

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"
  }
}
```

### 501

This runtime doesn’t purge tenants (`tenant-purge-unsupported`).

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"
  }
}
```

### 502

Deleting the tenant’s authorization store failed (`authz-store-delete-failed`): the message says what that left. Run it again.

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"
  }
}
```

### 503

The operator’s access record can’t be written, so nothing was done (`access-record-unavailable`).

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/system/tenants`: List tenants](https://docs.kindgi.com/v0.1.10/reference/api/operations/systemtenantslist.md)
- [`POST /v1/system/tenants`: Create a tenant](https://docs.kindgi.com/v0.1.10/reference/api/operations/systemtenantscreate.md)
- [`GET /v1/system/tenants/{tenantId}`: Read a tenant](https://docs.kindgi.com/v0.1.10/reference/api/operations/systemtenantsget.md)
- [`PATCH /v1/system/tenants/{tenantId}`: Rename a tenant](https://docs.kindgi.com/v0.1.10/reference/api/operations/systemtenantsupdate.md)
- [Serve many tenants](https://docs.kindgi.com/v0.1.10/deploy/self-hosted/serve-many-tenants.md)
- [Kindgi 0.1.10](https://docs.kindgi.com/v0.1.10/releases/0.1.10.md)
- [Error code `access-record-unavailable`](https://docs.kindgi.com/v0.1.10/reference/errors.md#access-record-unavailable)
- [Error code `authz-store-delete-failed`](https://docs.kindgi.com/v0.1.10/reference/errors.md#authz-store-delete-failed)
- [Error code `purge-record-unset`](https://docs.kindgi.com/v0.1.10/reference/errors.md#purge-record-unset)
- [Error code `purge-setting-missing`](https://docs.kindgi.com/v0.1.10/reference/errors.md#purge-setting-missing)
- [Error code `request-too-large`](https://docs.kindgi.com/v0.1.10/reference/errors.md#request-too-large)
- [Error code `system-principal-required`](https://docs.kindgi.com/v0.1.10/reference/errors.md#system-principal-required)
- [Error code `system-scope-missing`](https://docs.kindgi.com/v0.1.10/reference/errors.md#system-scope-missing)
- [Error code `tenant-export-window-open`](https://docs.kindgi.com/v0.1.10/reference/errors.md#tenant-export-window-open)
- [Error code `tenant-not-closing`](https://docs.kindgi.com/v0.1.10/reference/errors.md#tenant-not-closing)
- [Error code `tenant-not-found`](https://docs.kindgi.com/v0.1.10/reference/errors.md#tenant-not-found)
- [Error code `tenant-purge-unsupported`](https://docs.kindgi.com/v0.1.10/reference/errors.md#tenant-purge-unsupported)
- [Error code `tenant-slug-mismatch`](https://docs.kindgi.com/v0.1.10/reference/errors.md#tenant-slug-mismatch)
- [Every error code](https://docs.kindgi.com/v0.1.10/reference/errors.md)
