Scheduled deletion

4 min read Updated 1 day ago

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.

Via ploi.yaml

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

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

Apply the YAML in the usual way:

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.

Via the REST API

Set the field at creation:

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:

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:

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.