> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myme.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Platform

> Platform-operator surface — list, inspect, suspend, set quotas, view metrics, list keys, force a pending-delete sweep — via the `my platform` CLI

The `my platform` command tree exposes the platform-operator surface for managing tenants on a hosted Marfa instance: listing tenants, suspending them, adjusting per-tenant quotas, viewing usage metrics, listing API keys, and forcing a pending-delete sweep. Every command requires a **platform-admin key** (`is_platform: true`); a non-platform key is rejected with HTTP 403, which the CLI surfaces as a clear "platform-admin key required" message.

The verb name `platform` telegraphs the authority level the commands need. `my admin` is reserved for a future tenant-admin command set.

The same routes are reachable directly via the SDK's `client.admin` namespace (TypeScript) and via raw HTTP under `/admin/*` (every other client). The SDK keeps the `admin` namespace internally; only the CLI surface uses `platform`.

## Commands

```
my platform tenants list
my platform tenants show <id>
my platform tenants suspend <id> [--yes]
my platform tenants unsuspend <id> [--yes]
my platform tenants metrics <id>
my platform tenants quotas <id> [--items N] [--webhooks N] [--blobs N] [--storage-gb N] [--rate-per-minute N] [--yes]
my platform keys list <tenant-id>
my platform account-deletion purge-now [--yes]
```

| Command                      | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tenants list`               | List every tenant in the instance with current status (`active` / `suspended`).                                                                                                                                                                                                                                                                                                                                             |
| `tenants show <id>`          | Full tenant row + current per-tenant quota overrides + the 10 most-recent `system.activity` rows for the tenant.                                                                                                                                                                                                                                                                                                            |
| `tenants suspend <id>`       | Flip the tenant's `status` to `suspended`. Future non-GET requests from credentials in this tenant return HTTP 403 `tenant_suspended` at the auth-middleware layer. Reads pass through; platform-admin keys bypass. Idempotent — re-suspending a suspended tenant is a no-op. Emits a `tenant.suspend` audit row stamped with the **target** tenant id, so the suspended tenant's own `GET /audit` feed surfaces the event. |
| `tenants unsuspend <id>`     | Reverse of `suspend`. Idempotent. Emits a `tenant.unsuspend` audit row.                                                                                                                                                                                                                                                                                                                                                     |
| `tenants metrics <id>`       | Per-tenant usage snapshot — item count by lifecycle state, blob count + total bytes, recent activity.                                                                                                                                                                                                                                                                                                                       |
| `tenants quotas <id>`        | Flag-less invocation reads; passing any of `--items / --webhooks / --blobs / --storage-gb / --rate-per-minute` sets. `--storage-gb` is converted to bytes for the wire shape. `0` on any limit means "clear this override; revert to env default".                                                                                                                                                                          |
| `keys list <tenant-id>`      | Active (non-revoked) API keys for the named tenant — id, label, source, role, platform flag, last-used timestamp. Pair with `my keys revoke <id>` for emergency revocation.                                                                                                                                                                                                                                                 |
| `account-deletion purge-now` | Force a one-shot run of the pending-delete purger. Returns the count of accounts purged + the run timestamp. Useful when an account just passed its grace window and the operator doesn't want to wait for the next 1-hour cadence sweep. Idempotent — re-running with no eligible rows returns 0. Does not bypass the grace window.                                                                                        |

## Confirmation prompts on destructive verbs

`suspend`, `unsuspend`, `quotas` (write path), and `account-deletion purge-now` prompt for typed-token confirmation by default — operator types the literal verb (`suspend`, `unsuspend`, `set quotas`, `purge`) to authorise the action. Pass `--yes` / `-y` to skip the prompt for scripting. Read-only verbs (`list`, `show`, `metrics`, `keys list`) never prompt.

The CLI errors cleanly in non-TTY contexts (CI, piped output) when the prompt would otherwise hang on stdin that can never arrive — pass `--yes` explicitly in scripts.

## Suspension semantics

When a tenant is suspended:

* Every non-GET request from a credential whose `tenant_id` matches the suspended tenant returns HTTP 403 `tenant_suspended`.
* Reads (GET / HEAD / OPTIONS) pass through unchanged.
* Platform-admin keys (`is_platform: true`) bypass the gate — operators can still write to quotas, unsuspend, etc.
* Runtime-credential connector keys are **not** exempt. Suspending a tenant stops their connectors from writing upstream, which is the desired blast radius.

The gate sits at the auth-middleware layer, so every present **and** future mutation route is covered without per-route opt-in. A per-instance 5-second cache keys the lookup on `tenant_id`, evicted immediately on suspend/unsuspend so operator changes feel instant on the local instance. Multi-instance deployments tolerate up to 5 seconds of cross-instance staleness.

## Bootstrap admin key

Platform-admin keys (`is_platform: true`) are minted on instance bootstrap. The seed credential is created by your first `POST /keys` against a fresh deployment (the bootstrapped flag persists once stamped). Subsequent platform-admin keys can be minted by an existing platform admin via `my keys create --is-platform`.

If you've lost access to your bootstrap admin key on a self-hosted instance, the recovery path is to delete the `bootstrapped: true` row from the `settings` table directly, which re-opens the bootstrap window. See the operator notes in your deployment's runbook.

## Quotas

Per-tenant quota ceilings apply on top of the instance defaults (`MARFA_DEFAULT_QUOTA_ITEMS`, `_WEBHOOKS`, `_BLOBS`, `_STORAGE_BYTES`, `_RATE_PER_MINUTE`). A per-tenant override on a field takes precedence; a `null` (or `0` from the CLI) reverts that field to the env default.

When a tenant hits a cap, writes targeting the capped resource fail with HTTP 429 `quota_exceeded`, with `details` carrying `{ resource, limit, current }`. The CLI surfaces this verbatim.

## Forcing a pending-delete sweep

`my platform account-deletion purge-now` forces a one-shot run of the server-side `PendingDeletePurger`. The purger normally runs on a 1-hour cadence; this verb is the operator's escape hatch when an account has just passed its grace window and the cleanup needs to happen now (stuck-deletion remediation, support-driven flows, end-to-end deletion verification).

The route only sweeps accounts already past their `pending_deletion_at + grace_days` threshold — it does **not** bypass the grace window. To force-purge an account ahead of schedule, the user has to wait out their own grace window or cancel and reinitiate. Idempotent: re-running with no eligible rows returns `purged_count: 0`.

The action emits a `system.activity` audit row with `action: admin.account_deletion.purge_now`, `tenant_id: null` (instance-wide sweep), and `details` carrying the purged count + run timestamp. Prompts for typed `purge` by default; pass `--yes` to skip in scripts. When `MARFA_ACCOUNT_DELETION_GRACE_DAYS=0` (purger disabled), the route returns `purged_count: 0` cleanly rather than throwing.

## Limitations

* **Metrics is read-only.** The endpoint computes counts on-demand from the underlying tables; there's no eager counter / reconcile machinery yet (a follow-on once per-tenant cardinality justifies the complexity). Cost is `O(items_in_tenant)` per call.
* **`tenants quotas` is the only quota-mutation surface today.** Suspend/unsuspend are flag-flips; `account-deletion purge-now` triggers a sweep but doesn't bypass grace. Account deletion is **user-initiated**, not admin-initiated — see [Account lifecycle](/self-hosting/account-lifecycle).
* **No bulk operations.** Each command targets a single tenant.

## Related

* [Self-hosting → Configuration](/self-hosting/configuration) — env defaults that the per-tenant quotas override.
* [Self-hosting → Deployment modes](/self-hosting/deployment-modes) — single-tenant vs hosted multi-tenant; the platform surface is most useful in hosted mode.
* [Self-hosting → Account lifecycle](/self-hosting/account-lifecycle) — user-initiated account deletion. The platform surface gives an operator visibility during the grace window plus `account-deletion purge-now` to force the next sweep, but cannot purge ahead of the grace window.
