Database restores API
Read the recovery window, start a point-in-time database restore, follow its progress and undo the latest completed restore.
These routes recover a project's PostgreSQL database. They do not roll back its application release or restore files, KV data or account settings. Read Backups and restore before starting a recovery.
/ projects/ {name}/ restoresRecovery window, eligibility and the 20 newest restores/ projects/ {name}/ restoresQueue a restore to a Unix timestamp/ projects/ {name}/ restores/ {id}/ undoSwitch back to the database the latest restore replacedUse an account API token. Project members can read status; only the owner or an admin can start or undo recovery. Use the full project name from List projects.
Read the recovery window
curl https://api.fortly.com/projects/my-app-ada/restores \
-H "Authorization: Bearer $FORTLY_TOKEN"| Field | Meaning |
|---|---|
database | Whether the project has a managed database. |
eligible | Whether the owning account's plan or current Free offer permits restores. |
can_restore | Whether the caller is the owner or an admin. Check this separately from eligibility. |
service_ok | Whether the recovery service's catalogue is fresh. Do not start while false. |
retention_days | The recovery retention, currently 7 days. |
window | { "from": ..., "to": ... } in Unix seconds, or null before a recovery window exists. Both bounds are inclusive. |
points | Daily backup timestamps inside the window. Targets are not restricted to these timestamps. |
offer_until | Free offer's exclusive cutoff, or null for paid accounts or an inactive offer. |
restores_left_today | Remaining Free allowance in the preceding 24 hours, or null when no Free offer applies. The field name does not imply a midnight reset. |
restores | Up to 20 restores, newest first. |
undoable | The latest restore id that can still be undone, or null. |
The Free offer includes December 1, 2026, UTC: its cutoff is December 2 at 00:00 UTC (1796169600). It allows one non-failed restore per project in a rolling 24-hour window. Pro and Max remove that allowance. Undo does not consume an additional restore or refund the first one.
Start a restore
Choose target_at from the server's current window. Convert the intended date and timezone to Unix seconds, review the project and target, then submit:
# Set TARGET_AT to the Unix timestamp you reviewed, within window.from and window.to.
curl -X POST https://api.fortly.com/projects/my-app-ada/restores \
-H "Authorization: Bearer $FORTLY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"target_at\":$TARGET_AT}"Answers 202 with the restore record. This means accepted, not complete. Poll the GET route and find the returned id; the console checks every three seconds while a restore is active.
| State | What is happening |
|---|---|
queued | Waiting for the recovery service. |
restoring | Rebuilding the database from its backups. |
staged | Rebuilt; waiting for the project to switch to it. |
done | The project is using the restored database. |
failed | Recovery failed; detail explains why. The current database remains in use. |
undone | Undo switched the project back to its previous database. |
Records include id, target_at, state, detail, created_at, started_at, finished_at and undone_at. Nullable timestamps have not occurred yet. Internal database names and the requesting account's id are not returned.
At switch-over, data written after the selected moment is replaced, including writes made while recovery was running. Pause writers first if necessary. A database restore does not change the deployed code; verify schema compatibility afterwards.
Undo the latest restore
Read undoable again before submitting. Review the loss of access to writes made since the restore, then call:
curl -X POST https://api.fortly.com/projects/my-app-ada/restores/$RESTORE_ID/undo \
-H "Authorization: Bearer $FORTLY_TOKEN"The previous database is retained for seven days after completion. Undo normally returns 200 with the updated record; it can return 204 if the switch completed but the record could not be read back. Refresh status after either response. Undo is available for an eligible retained restore even after the Free offer expires; it does not require a new paid-plan entitlement.
Only the latest completed restore can be undone, and Undo itself is not a repeatable toggle. Check the current undoable value instead of retrying an old id blindly.
Handle errors and retries
| Status | What to do |
|---|---|
400 | Send an integer target_at within the current server window. |
402 | Upgrade: the Free offer has ended for this account. |
403 | Ask the owner or an admin to perform the operation. |
404 | Verify project access and whether it has a database. |
409 | A restore is already active, no recovery window exists yet, or the requested Undo is no longer eligible. Refresh status. |
429 | The Free project's rolling 24-hour allowance is used. Wait or upgrade. |
503 | The recovery catalogue is unavailable or stale. Wait and refresh status. |
There is no idempotency key. If a POST response is lost, read the restore list before starting another request. A second active restore is refused, rather than put behind the first one in a queue.