Scheduled deletion
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:
- Dispatches the standard delete job for any application whose
scheduled_deletion_athas passed - Sends 1-day warnings for applications inside the 24-hour window that have not yet been warned at that level
- 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.