> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK: snapshots and backups

> List, create and restore app and database snapshots, list every snapshot of the account, and download a snapshot file with client.download_snapshot().

Snapshots are backups of an app's or database's storage. Apps and databases share the same three methods:

* `client.apps.snapshots`: `list(app_id)`, `create(app_id)`, `restore(app_id, name, version_id)`
* `client.databases.snapshots`: `list(database_id)`, `create(database_id)`, `restore(database_id, name, version_id)`

How many snapshots you can create per day depends on your plan (see [Limits](#limits)).

Examples use the `client` from [Creating the client](/en/sdks/py/client#creating-the-client). `app_id` is the id of one of your apps: [`client.account.me()`](/en/sdks/py/client#account) lists them.

## Listing snapshots

```python theme={"system"}
for snapshot in client.apps.snapshots.list(app_id):
    print(snapshot["name"], snapshot["version_id"], snapshot["size"], snapshot["modified"])
```

| Field | Description |
| - | - |
| `name` | The snapshot id that `restore` takes |
| `version_id` | The version that `restore` takes |
| `size` | Size in bytes |
| `modified` | When it was taken |
| `url` | Signed download URL, **valid for 30 days** |
| `key` | Signed query string of the URL |
| `runtime` | Database engine or app language (`None` on old snapshots) |
| `origin` | `"automatic"`, `"manual"` or `None` |

## Creating a snapshot

`create()` waits for the snapshot (at least 120 s before timing out). A large snapshot may not finish in time: the API then answers 202 and the SDK returns `{'pending': True}`. The snapshot keeps generating and shows up in `list()` on its own, usually within 2 minutes. Otherwise it returns `{'pending': False, 'url': ..., 'key': ...}`.

```python theme={"system"}
result = client.apps.snapshots.create(app_id)

if result["pending"]:
    # Poll list() later. Do not call create() again: that starts a new snapshot.
    pass
else:
    print(result["url"])  # signed download URL, valid 30 days
```

<Warning>
  Never call `create()` again to check on a pending snapshot: it starts a new one and counts against the plan's daily snapshot quota. Poll `list()` instead.
</Warning>

## Restoring a snapshot

`restore(id, name, version_id)` takes the `name` and `version_id` of a listed snapshot.

```python theme={"system"}
latest = client.apps.snapshots.list(app_id)[0]

client.apps.snapshots.restore(app_id, latest["name"], latest["version_id"])
```

| Status | Code | When |
| - | - | - |
| 400 | `MISSING_PARAMETERS` | `name` or `version_id` is missing |
| 400 | `INVALID_SNAPSHOT_ID`, `INVALID_VERSION_ID` | Not a `name`/`version_id` from the listing |
| 400 | `SNAPSHOT_DATABASE_MISMATCH` | The snapshot's engine does not match the database's type (databases only) |
| 404 | `SNAPSHOT_NOT_FOUND` | No snapshot with that name and version |
| 404 | `SNAPSHOT_RESTORE_FAILED` | The restore could not be dispatched (the usual failure) |
| 413 | `PAYLOAD_TOO_LARGE` | The snapshot is too large to restore |

## Downloading a snapshot

`client.download_snapshot(url, dest)` streams a snapshot file from its signed `url` (from `list()` or `create()`) to disk and returns the path it wrote. It does **not** call the API: the API key is never sent to the storage host. Nothing is buffered in memory.

* `dest` is a file path, or a directory to keep the remote file name. A path ending in `/` is created as a directory.
* The data goes to a `.part` file that is renamed when complete, so a failed download never overwrites an earlier file.
* There is no timeout for the whole download: `timeout` bounds each read.

```python theme={"system"}
latest = client.apps.snapshots.list(app_id)[0]

path = client.download_snapshot(latest["url"], "backup.zip")
print("saved to", path)

# Or into a directory, keeping the remote name
client.download_snapshot(latest["url"], "backups/")
```

With `AsyncSquareCloud`, it is `await client.download_snapshot(url, dest)`.

An expired or invalid URL raises a `SquareCloudAPIError` with the storage host's HTTP status and `UNKNOWN_ERROR`. A destination that cannot be written raises an `OSError`.

## Account snapshots

`client.account.snapshots(scope=None)` lists every snapshot of the account, optionally only `"applications"` or `"databases"` (keyword-only). It needs an active plan and shares the network endpoints' rate limit (429 `RATE_LIMITED`).

```python theme={"system"}
everything = client.account.snapshots()
databases = client.account.snapshots(scope="databases")
```

| Status | Code | When |
| - | - | - |
| 400 | `INVALID_SCOPE` | `scope` is not `applications` or `databases` |
| 402 | `UPGRADE_REQUIRED` | The account has no active plan |
| 429 | `RATE_LIMITED` | Rate limit reached |

## Limits

* `create()` is limited to one call per 180 seconds and to a daily quota that depends on the plan: going over the quota is 429 `DAILY_SNAPSHOTS_LIMIT_REACHED`.
* While a restore runs, deleting the app or starting the database is 403 `RESTORE_IN_PROGRESS`.

## Next steps

<CardGroup cols={3}>
  <Card title="Databases" icon="database" href="/en/sdks/py/databases">
    Create and manage databases.
  </Card>

  <Card title="Snapshot API reference" icon="code" href="/en/api-reference/endpoint/apps/snapshots/list">
    The REST endpoints behind these methods.
  </Card>

  <Card title="Snapshots from the CLI" icon="terminal" href="/en/cli-reference/snapshots">
    The same actions from the terminal.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.