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

# Pre-Deploy Backups

> Take a confirmed backup before every deployment — block your pipeline until the backup is safely stored.

## Overview

Pre-deploy backups let your CI/CD pipeline take a snapshot of your database **before** a deployment runs, and **block until the backup is confirmed stored** in the cloud. If the backup fails, your pipeline fails — the deploy never happens.

```bash theme={null}
curl -s -X POST "https://api.trycapsule.xyz/v1/agent/backups/pre-deploy" \
  -H "Authorization: Bearer $CAPSULE_LICENSE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"connection_label": "prod-postgres", "note": "before v2.4 rollout"}' \
  --max-time 360   # must exceed the API timeout (default 300s)
```

The request blocks until the backup is stored or the timeout elapses. A `200` means the backup is safely in the cloud — it will appear in your dashboard under **Backups**. Any other status means it failed — your deploy script can handle it however you want.

***

## How it works

1. The API receives your request and creates a backup job
2. It sends a signal to the Capsule daemon running on your server
3. The daemon runs a full backup (dump → encrypt → upload to cloud storage)
4. Once stored, the daemon reports completion back to the API
5. The API returns `200` with the `backup_id` to your pipeline

The HTTP connection stays open the whole time — you get a single blocking call, not a polling loop.

***

## Request

```
POST https://api.trycapsule.xyz/v1/agent/backups/pre-deploy
Authorization: Bearer <your-license-key>
Content-Type: application/json
```

**Body**

```json theme={null}
{
  "connection_label": "prod-postgres",
  "note": "before v2.4 rollout"
}
```

`connection_label` must match a connection configured in your Capsule CLI.

`note` is optional (max 1000 characters) — a free-text note recorded against the resulting backup, useful for tying a backup to a deploy, ticket, or commit. It's write-once: set only when the backup is triggered, and cannot be edited afterward. It shows up in the dashboard's Backups table and in `capsule backup list`.

**Query parameters**

| Parameter | Type              | Default | Description                                              |
| --------- | ----------------- | ------- | -------------------------------------------------------- |
| `timeout` | integer (seconds) | `300`   | How long to wait for the backup to complete. Max `3600`. |

***

## Response

**200 — backup completed**

```json theme={null}
{
  "success": true,
  "message": "pre-deploy backup completed",
  "data": {
    "job_id": "3f8a1c2e-...",
    "backup_id": "b91d4f7a-..."
  }
}
```

**409 — no CLI connected**

```json theme={null}
{
  "success": false,
  "message": "no CLI connected — make sure the daemon is running on your server"
}
```

This is the most common failure. The Capsule daemon must be running **on the same server as your database** when the request arrives. SSH in and run `capsule daemon` (or check `systemctl status capsule`).

**502 — backup failed on the server**

```json theme={null}
{
  "success": false,
  "message": "disk full: no space left on device"
}
```

**504 — timed out**

```json theme={null}
{
  "success": false,
  "message": "backup did not complete within 300 seconds — check the CLI daemon logs"
}
```

***

## GitHub Actions

The easiest way to wire this into a GitHub Actions pipeline is [`capsule-infra/backup-action`](https://github.com/capsule-infra/backup-action), which wraps the same API call below as a reusable, versioned step:

```yaml theme={null}
- name: Pre-deploy backup
  uses: capsule-infra/backup-action@v1
  with:
    license-key: ${{ secrets.CAPSULE_LICENSE_KEY }}
    connection-label: prod-postgres
    note: ${{ github.sha }}
```

Store your license key as a GitHub secret named `CAPSULE_LICENSE_KEY`. The action fails the step (and stops the job) automatically on any non-200 response, and exposes `backup-id` / `job-id` as step outputs — see the [action's README](https://github.com/capsule-infra/backup-action#readme) for the full input/output reference, timeout tuning, and a complete example workflow.

### Prefer raw curl instead of the action?

```yaml theme={null}
- name: Pre-deploy backup
  run: |
    response=$(curl -s -w "\n%{http_code}" -X POST \
      "https://api.trycapsule.xyz/v1/agent/backups/pre-deploy" \
      -H "Authorization: Bearer ${{ secrets.CAPSULE_LICENSE_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{"connection_label": "prod-postgres", "note": "'"${{ github.sha }}"'"}' \
      --max-time 360)

    http_code=$(echo "$response" | tail -1)
    body=$(echo "$response" | head -1)

    if [ "$http_code" != "200" ]; then
      echo "Pre-deploy backup failed (HTTP $http_code): $body"
      exit 1
    fi

    backup_id=$(echo "$body" | jq -r '.data.backup_id')
    echo "Backup secured: $backup_id"
```

Store your license key as a GitHub secret named `CAPSULE_LICENSE_KEY`. Functionally identical to the action above — useful if you'd rather not depend on a third-party action, or need custom logic the action doesn't expose. `note` is optional — drop it from the payload entirely if you don't want one.

***

## Shell / bash deploy scripts

```bash theme={null}
#!/bin/bash
set -e

echo "Taking pre-deploy backup..."
RESULT=$(curl -sf -X POST \
  "https://api.trycapsule.xyz/v1/agent/backups/pre-deploy?timeout=120" \
  -H "Authorization: Bearer $CAPSULE_LICENSE_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"connection_label\": \"$DB_CONNECTION_LABEL\"}")

BACKUP_ID=$(echo "$RESULT" | jq -r '.data.backup_id')
echo "Backup stored: $BACKUP_ID"

# Now deploy
./deploy.sh
```

The `-sf` flags make `curl` exit with a non-zero code on HTTP errors, so `set -e` will stop the script automatically if the backup fails.

***

## Custom timeout

For large databases that take more than 5 minutes to dump and upload, pass `?timeout=<seconds>`:

```bash theme={null}
curl -X POST \
  "https://api.trycapsule.xyz/v1/agent/backups/pre-deploy?timeout=900" \
  -H "Authorization: Bearer $CAPSULE_LICENSE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"connection_label": "prod-postgres"}' \
  --max-time 960   # slightly longer than the API timeout
```

<Info>
  Set `--max-time` on your `curl` call to slightly more than the `?timeout=` value so `curl` doesn't give up before the API does.
</Info>

Maximum `timeout` value is `3600` (1 hour). Values above this are clamped to `3600`.

***

## Requirements

* Capsule daemon must be running on the server that hosts the connection (`capsule daemon` or the systemd service)
* The connection label must match exactly what's configured in the CLI
* Your license key must be for the account that owns the connection

<Tip>
  Run `capsule doctor` on your server to verify the daemon is healthy and the connection is reachable before wiring this into a pipeline.
</Tip>
