Terminate a tenant
Permanently delete a tenant and all of its infrastructure. Final and irreversible — a missing workspace is treated as idempotent success.
https://api.swarmz.net/functions/v1/platform-terminateFinal and irreversible. Maps to WHMCS TerminateAccount. client_status is flipped to terminated first so any in-flight request fails fast, then terminateWorkspace runs the full teardown: every project is deleted — cascading the preview pods, published workers, custom domains, and managed Supabase behind them — and finally the workspace row itself is deleted.
Address the tenant by tenant_id — the id returned by create — or fall back to your external_ref. Supply exactly one identifier.
Parameters
Prop
Type
Request
curl -X POST https://api.swarmz.net/functions/v1/platform-terminate \
-H "Authorization: Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{ "tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242" }'const res = await fetch('https://api.swarmz.net/functions/v1/platform-terminate', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6',
'Content-Type': 'application/json',
},
body: JSON.stringify({ tenant_id: 'aa7d7fae-0386-4d8a-b977-72f856eac242' }),
});
const data = await res.json();import requests
res = requests.post(
"https://api.swarmz.net/functions/v1/platform-terminate",
headers={"Authorization": "Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"},
json={"tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242"},
)
data = res.json()Response
A fresh termination returns the deletion report:
{
"ok": true,
"report": {
"deletedProjects": [],
"deletedPods": [],
"deletedDomains": [],
"deletedCloud": [],
"errors": []
}
}If the tenant is already terminated — or already gone — the call short-circuits:
{ "ok": true, "already": true }| Field | Type | Description |
|---|---|---|
ok | boolean | Always true on success. |
already | boolean | Present and true when the tenant was already terminated or the workspace row no longer exists. No teardown ran. |
report | object | The deletion summary. Absent when already: true. |
report.deletedProjects | string[] | Projects that were deleted. |
report.deletedPods | string[] | Preview pods that were deleted. |
report.deletedDomains | string[] | Custom domains that were removed. |
report.deletedCloud | string[] | Managed-cloud resources that were deleted. |
report.errors | string[] | Per-step failures, if any. The status flip to terminated is authoritative even if a teardown step fails. |
Errors
| Status | error | reason | When |
|---|---|---|---|
| 400 | missing_fields | tenant_id or external_ref required | Neither identifier supplied (bearer path) |
| 400 | missing_fields | account_id required for internal terminate | Internal-path call with no account_id |
| 401 | unauthorized | missing_bearer / invalid_key / account_disabled | See Authentication |
| 405 | method_not_allowed | — | Anything other than POST |
| 429 | rate_limited | per_key / per_ip | Rate limit hit — see Rate limits |
| 500 | terminate_failed | RPC message | The status-flip RPC (platform_set_client_status) failed; safe to retry |
| 500 | internal_error | — | Unhandled server error; safe to retry |
Terminate does not return 404
A missing workspace is treated as idempotent success (already: true), not an
error — so terminate never returns 404. After termination, other endpoints
return 404 tenant_not_found for that id, because the row is deleted rather
than marked terminated. Treat 404 and 410 terminated identically: the
service is gone, do not retry.
Idempotency
Terminate is idempotent by state. An already-terminated or already-deleted tenant returns already: true. There is no idempotency key — the absence of an active workspace row is the source of truth. See Idempotency.
Notes
- Address the tenant by
tenant_idfromcreate;external_refis the fallback. - Termination deletes the workspace row, so the
tenant_idandexternal_refboth stop resolving afterward. Per the external_ref convention, never reuse thatexternal_reffor a new service. - For a reversible pause instead of permanent deletion, use suspend.
- The
account_idparameter andX-Internal-Mint-Secretpath exist for the reseller dashboard's server-to-server calls only; host integrations use the bearer key and never sendaccount_id.
Unsuspend a tenant
Reverse a suspend — flip the tenant back to active and replay its captured state, republishing projects, rebinding domains, and resuming managed cloud.
Single sign-on
Mint a short-lived redirect that lands a web-host user in their dashboard, already logged in. Send their browser to it — mint a fresh token on every click.