# Scheduled deletion

> Schedule applications for automatic, permanent deletion. Useful for preview environments and short-lived test apps that should clean themselves up.

Scheduled deletion
==================

Mark an application for automatic, permanent deletion at a future date. When the timestamp passes, the application and every resource attached to it is removed without manual intervention.

This is intended for short-lived environments such as pull-request previews, demo deployments, or capacity tests, where teams routinely lose track of test apps and pay for resources nobody is using.

What gets deleted
-----------------

When the schedule fires, the platform removes:

- The application itself
- All databases and persistent files
- Secrets and environment configuration
- Domains and SSL certificates
- Deployment history and logs
- The container images built for the application

This is the same cleanup that runs when you delete an application from the dashboard. It cannot be undone.

How to schedule a deletion
--------------------------

Scheduling can only be enabled via the REST API or your `ploi.yaml`. The dashboard does not expose a way to enable a schedule on an application that does not already have one. This is intentional: the field belongs to your IaC source of truth, and the dashboard reflects it.

<h3>Via ploi.yaml</h3>

Add `scheduled_deletion_at` under the application's `settings` block. Use an ISO 8601 timestamp.

```yaml
spec:
  application:
    name: preview-pr-1234
    type: laravel
    settings:
      scheduled_deletion_at: "2026-05-15T03:00:00Z"
```

Apply the YAML in the usual way:

```bash
curl -X POST https://api.ploi.cloud/api/v1/infrastructure/apply \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/yaml" \
  --data-binary @ploi.yaml
```

Removing the `scheduled_deletion_at` key from your YAML clears the schedule on the next apply. This differs from most other YAML fields, which are preserved on removal for safety.

<h3>Via the REST API</h3>

Set the field at creation:

```bash
curl -X POST https://api.ploi.cloud/api/v1/applications \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "preview-pr-1234",
    "application_type": "laravel",
    "scheduled_deletion_at": "2026-05-15T03:00:00Z"
  }'
```

Update or extend an existing schedule:

```bash
curl -X PATCH https://api.ploi.cloud/api/v1/applications/{id} \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_deletion_at":"2026-06-01T00:00:00Z"}'
```

Cancel a schedule by setting it to null:

```bash
curl -X PATCH https://api.ploi.cloud/api/v1/applications/{id} \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_deletion_at":null}'
```

Updating from the dashboard
---------------------------

Once a schedule is set, the application's panel page shows a banner across the top listing the deletion date. The Settings tab gains a "Scheduled deletion" card inside the danger zone, where you can:

- pick a new date
- cancel the schedule outright

The dashboard cannot create a schedule from scratch. To start scheduling on an application that has no current schedule, use the API or `ploi.yaml`.

Warning emails
--------------

The team owner receives two warning emails before the deletion fires:

- **7 days before** — heads up email with the deletion date and the three ways to cancel (ploi.yaml, API, dashboard)
- **1 day before** — urgent email with the same information

Each warning is sent at most once per scheduled date. If you push the date out (extend the schedule), the warning markers are reset and you will receive fresh warnings as the new date approaches. The same applies if you cancel and re-schedule.

If a schedule is created with less than 24 hours remaining, only the 1-day warning is sent.

How the timing works
--------------------

A background job runs every 15 minutes. On each run it:

1. Dispatches the standard delete job for any application whose `scheduled_deletion_at` has passed
2. Sends 1-day warnings for applications inside the 24-hour window that have not yet been warned at that level
3. Sends 7-day warnings for applications inside the 7-day window that have not yet been warned at that level

Worst-case delay between the timestamp passing and the deletion job firing is around 15 minutes.

Limitations
-----------

- Inactivity-based deletion (delete after N days without a deployment) is not supported. The schedule is always an explicit timestamp.
- Past dates are rejected by validation. To delete an app immediately, delete it from the dashboard or the API.
- Once the deletion job has been dispatched, cancellation in the dashboard does not unschedule the queued job. Cancel before the timestamp passes.
