# App recovery

Choose the correct operation. There is no single restore-everything operation.

## Roll back code — all plans with deploy access

List releases, select a known working release, then call `restore_release {appId, releaseId, requestId}` or `POST /api/v1/apps/{appId}/releases/{releaseId}/restore` with a stable requestId. This builds and deploys that release's source as a new release using current environment variables. It does not revert SQL migrations, database records, file contents or external payments. Check that the old code is compatible with the current database schema. Poll the returned deployment and read build/runtime logs; verify real app workflows.

## Restore database — Grow ($79) and Scale ($199)

Read `get_recovery {appId}` or `GET /api/v1/apps/{appId}/recovery`. Only offer backups returned by this request. Managed Supabase databases have daily backups, but their creation can be delayed; do not invent a backup or guarantee a timestamp that is not listed. Historical logical backups that the native restore API cannot handle are not listed.

Agents may execute database recovery directly with database:write access. No owner browser approval is required. First explain the selected time and that newer records, schema changes and user-account changes will be replaced. Set acknowledgeDataLoss:true to explicitly acknowledge that impact, then use:

```json
{"appId":"APP_ID","kind":"backup","backupId":123,"requestId":"recovery-unique-001","acknowledgeDataLoss":true}
```

MCP: `restore_database`. HTTP: `POST /api/v1/apps/{appId}/recovery/database`, omitting appId from the body. The app's hosting, CDN and background tasks are suspended while the database restores. Files are not rolled back; restored database references may point to files that have since been deleted. Stripe payments, emails and other external effects are not undone. Existing connected clients should be told to stop writing during maintenance.

Poll the returned jobId with get_job or GET /api/v1/jobs/{jobId}. Reuse the same requestId when retrying the original HTTP request; never create a new one merely because recovery is slow. An uncertain provider response must be investigated, not replayed. Follow the returned error and contact support when the outcome cannot be verified. Do not clear maintenance flags or alter managed resources to bypass the workflow.

For a failed monitoring or app-restart job, use `continue_database_restore {appId,restoreId}` or POST `/api/v1/apps/{appId}/recovery/{restoreId}/continue`. This continues the recorded request. It refuses an uncertain submission; contact support for that case. The UI offers Continue recovery for retryable phases.

After completion, test login, user permissions, representative data, and code/schema compatibility. Check affected integrations for reconciliation; never re-charge payments or blindly replay email jobs from restored rows. A successful database connection check is not proof that every business workflow works.

## Point-in-time recovery — Scale

Scale offers an optional seven-day PITR add-on at **$129/month per app**, in addition to the $199 plan ($328/month total). It is off by default. The owner enables it in Services → Recovery and confirms checkout. Agents call configure_recovery_addon {appId,enabled:true} or PUT /api/v1/apps/{appId}/recovery/addon with {"enabled":true}; open or give the returned approval URL to the owner. The agent never purchases directly. An active paid add-on is required for point-in-time restores; Scale alone still includes available backup restores. Disabling stops renewal and retains access until the paid period ends. Leaving Scale ends the add-on. Billing cycles are separate from the base app plan. Failed add-on renewal suspends PITR, not the base app. The window builds after enablement; upgrading cannot recover a time before capture began. GET recovery returns pointInTimeRange.from and .to, or null while preparing/unavailable. Only restore inside that range; the newest recoverable point can lag the present.

Use restore_database with `kind:"point_in_time"`, `time:"2026-09-15T12:00:00Z"`, requestId and acknowledgeDataLoss:true. Omit backupId. The same maintenance and verification requirements apply.

This is database recovery, not whole-app time travel. Recovery points disappear when the underlying managed database is retired. Follow the app's data-retention policy and export data before leaving.
