Skip to content

Purge a closed tenant, for good

View as Markdown
POST
/v1/system/tenants/{tenantId}/purge
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.

tenantId
required
string format: uuid

The tenant’s id.

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

Media typeapplication/json
object
confirm
required

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

string
>= 1 characters
Examplegenerated
{
"confirm": "example"
}

What it deleted, and what of it is left.

Media typeapplication/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
{
"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"
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Missing / malformed / expired / revoked bearer token.

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

No tenant with that id (tenant-not-found). A purged one is found, for a run again.

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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.

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Server error (unmapped domain code or framework crash).

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

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

Media typeapplication/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
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

See also