---
title: "Cancel a project's scheduled deletion, inside the grace (owner/admin)"
method: POST
path: "/v1/projects/{project_id}/cancel-deletion"
tags: ["projects"]
---

# Cancel a project's scheduled deletion, inside the grace (owner/admin)

`POST /v1/projects/{project_id}/cancel-deletion`

## Request

- Base URL: `https://api.wavehouse.cloud`
- URL: `https://api.wavehouse.cloud/v1/projects/{project_id}/cancel-deletion`
- Auth: one of:
  - API key in cookie `whc_session`
  - HTTP bearer
  - API key in header `X-API-Key`

Counts the project back toward the plan's projects, extra-project fee and add-ons, prorated. Refused with 402 when the plan has no room for it, as a create would be, and with 409 once the status is `destroying`: the teardown has begun.

## Path parameters

- `project_id` string, required

## Response `200`

OK

- ProjectView
  - `connection` ProjectConnectionView
    - `auth_configured` boolean, required: false until the org sets a data-plane auth config
    - `auth_mode` string, required: jwks | hmac | public | unconfigured
    - `hint` string: one-line next step for the customer
    - `hmac_fingerprint` string: non-secret fingerprint (trailing checksum) of the active HMAC secret; shown as whc_hmac_…<fingerprint>
    - `url` string: Public HTTPS endpoint, https://<project_id>.<base-domain>
  - `created_at` string, date-time, required
  - `default_role` string, required: policy role for roleless requests (the 'public' access level); empty = locked
  - `deletion_grace_seconds` integer, required: how long a deletion scheduled now keeps the project's data before destroying it; cancellable until then
  - `destroy_after` string, date-time: instant a scheduled deletion becomes due; present only while status is deleting or destroying
  - `name` string, required
  - `org_id` string, required: the org that owns the project
  - `project_id` string, required
  - `provisioning_failed` boolean: setting this project up did not finish and nothing is retrying it; POST .../provision resumes it from where it stopped
  - `settings` ProjectSettingsView, required
    - `cors_allowed_origins` string[]: browser origins the data-plane allows. Empty = block all browser origins (server-side ingest/queries are unaffected by CORS); "*" = allow any origin. Otherwise each entry must be an exact scheme://host[:port] — no path, no wildcard: the engine matches origins literally, and an entry it cannot match this way is rejected with a 422 naming it. Only affects browser clients. The WaveHouse Cloud console is always allowed automatically and need not be listed
    - `dedupe_enabled` boolean: drop duplicate rows by a stable id field (idempotent ingest)
    - `dedupe_id_field` string: JSON field the dedupe key reads (engine default: event_id)
    - `dedupe_require_id` boolean: reject rows missing the dedupe id field (strict idempotency)
    - `query_default_max_rows` integer: fallback result LIMIT when a query specifies none; 0 = engine default (10000)
    - `query_timeout_seconds` integer: max seconds a read may run; 0 = engine default (30)
  - `status` string, required: pending | provisioning | active | suspended | deleting (scheduled, cancellable until destroy_after) | destroying (the teardown has begun and can no longer be cancelled)
  - `writes_paused` boolean: writes are paused for maintenance and resume on their own; reads, the id, credentials and policy are unaffected

## Other responses

- `429`: Rate limited, per client IP, API key or org; a client IP is also refused on every route for a while after repeated authentication failures. A limited operation carries RateLimit-Policy and RateLimit on every response; wait Retry-After seconds before retrying.
- `default`: Error

---

[API](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api.md) · [All operations](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api/revisions/adea029bf505?raw)
