Purge a closed tenant, for good
const url = 'https://example.com/v1/system/tenants/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/purge';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"confirm":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The tenant’s id.
Header Parameters
Section titled “Header Parameters”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
Section titled “Request Bodyrequired”object
The tenant’s slug, a second check on the id.
Examplegenerated
{ "confirm": "example"}Responses
Section titled “Responses”What it deleted, and what of it is left.
object
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.
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.
When it was marked purged. Absent while something of it from before the mark is left.
Rows this run deleted, per table with any: table names and counts, never the rows’ content.
A tenant’s rows in one table: the table’s name and a count.
object
Objects this run deleted from the artifacts’ store.
Whether this run deleted its authorization store.
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.
A tenant’s rows in one table: the table’s name and a count.
object
Objects still under its prefix in the artifacts’ store.
Why what’s left wasn’t deleted, when it’s a setting the runtime lacks.
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.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Missing / malformed / expired / revoked bearer token.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Server error (unmapped domain code or framework crash).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}This runtime doesn’t purge tenants (tenant-purge-unsupported).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
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).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}See also
GET /v1/system/tenants: List tenantsPOST /v1/system/tenants: Create a tenantGET /v1/system/tenants/{tenantId}: Read a tenantPATCH /v1/system/tenants/{tenantId}: Rename a tenant- Serve many tenants
- Kindgi 0.1.10
- Error code
access-record-unavailable - Error code
authz-store-delete-failed - Error code
purge-record-unset - Error code
purge-setting-missing - Error code
request-too-large - Error code
system-principal-required - Error code
system-scope-missing - Error code
tenant-export-window-open - Error code
tenant-not-closing - Error code
tenant-not-found - Error code
tenant-purge-unsupported - Error code
tenant-slug-mismatch - Every error code