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

# Revert to Operator-Managed Key

> Off-board BYOK: return the tenant to a KnoxCall-managed master key and remove the customer KMS configuration.

## POST /admin/tenant-kms/revert

Revert the tenant from BYOK back to a KnoxCall-managed (operator) master key. The inverse of onboarding: a new operator-wrapped master key is provisioned and activated, existing data is re-encrypted under it, and the customer KMS configuration is removed. Your KMS key itself is never modified — you can re-onboard BYOK at any time.

**Auth**: `Authorization: Bearer <session jwt>` + **`X-Tenant-ID`**. Requires an owner/admin session.

This endpoint requires a **recent step-up verification** (re-authentication) performed within the last **2 minutes** by the signed-in user (the same tight window as unseal — reverting removes your KMS revocation control over data-at-rest). No step-up header or token is sent on this request — the server checks for a recent, unused verification tied to your session. To create one, re-authenticate via `POST /auth/2fa/verify-step-up` (TOTP), `POST /auth/passkey/verify-step-up` (passkey), or the email fallback (`POST /auth/step-up/email-challenge` then `POST /auth/step-up/verify-email`); check `GET /auth/step-up/status` to confirm a valid step-up exists.

The behavior depends on whether your KMS is reachable, which the server verifies with a live wrap/unwrap probe:

### KMS reachable — lossless revert

The new operator-managed key is activated immediately and a background rewrap job re-encrypts all existing data under it. Your KMS configuration stays in place until the last row wrapped under your key has been migrated (it is needed to decrypt them), then is removed automatically.

```json theme={"dark"}
{
  "reverted": true,
  "path": "rewrap",
  "new_key_version": 5,
  "rewrap_lease_id": 42,
  "note": "Re-encryption under the operator-managed key is queued. The customer KMS config will be removed automatically once it completes."
}
```

### KMS unreachable — forced revert (data loss)

If the probe fails (revoked IAM grant, deleted role trust, disabled key), secrets written while BYOK was active **cannot be re-encrypted and become permanently unreadable**. The server refuses with `409`:

```json theme={"dark"}
{
  "error": "kms_unreachable_data_loss",
  "probe_reason": "access_denied: KMS access denied by aws: ...",
  "message": "The customer KMS is unreachable, so secrets wrapped under it cannot be re-encrypted — reverting now makes them permanently unreadable. Either restore KMS access first (then revert re-encrypts everything losslessly), or retry with { \"acknowledge_data_loss\": true } to revert anyway."
}
```

Retry with an explicit acknowledgement to proceed:

```json theme={"dark"}
{ "acknowledge_data_loss": true }
```

The response then has `"path": "forced_data_loss"` and `"rewrap_lease_id": null`. The KMS configuration is removed immediately and a snapshot of it is written to the tamper-evident audit trail — if you later restore KMS access, KnoxCall support can re-attach the configuration to recover secrets wrapped under the old key versions.

<Warning>
  Prefer restoring KMS access before reverting. A forced revert orphans every secret value written while BYOK was active — you will need to re-enter them. Restoring access first makes the revert completely lossless.
</Warning>

The tenant owner receives a security notification email, and a `byok.kms.revert` entry is written to the hash-chained critical audit log.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl -X POST https://admin.knoxcall.com/admin/tenant-kms/revert \
    -H "Authorization: Bearer $KC_ADMIN_JWT" \
    -H "X-Tenant-ID: $KC_TENANT_ID" \
    -H "Content-Type: application/json" \
    -d '{}'
  ```

  ```python Python theme={"dark"}
  resp = requests.post(
      "https://admin.knoxcall.com/admin/tenant-kms/revert",
      headers={
          "Authorization": f"Bearer {KC_ADMIN_JWT}",
          "X-Tenant-ID": KC_TENANT_ID,
      },
      json={},
  )
  resp.raise_for_status()
  print(resp.json()["path"])  # "rewrap"
  ```

  ```javascript Node.js theme={"dark"}
  const resp = await fetch("https://admin.knoxcall.com/admin/tenant-kms/revert", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${KC_ADMIN_JWT}`,
      "X-Tenant-ID": KC_TENANT_ID,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({}),
  });
  const { reverted, path, new_key_version } = await resp.json();
  ```
</CodeGroup>
