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

# Actual Budget

> Sync transactions to a self-hosted Actual Budget instance

<Info>
  This tool uses the Redbark REST API, which is in **beta**. Behaviour may change as the API evolves.
</Info>

Actual Budget sync runs as a standalone Docker container that pulls transactions from the Redbark API and imports them directly into your Actual Budget server. It is not a dashboard destination.

<Info>
  This is a **self-hosted Docker tool**. You run it on your own infrastructure alongside your Actual Budget server.
</Info>

## Prerequisites

* A running [Actual Budget](https://actualbudget.org/) server
* Docker installed on your machine or server
* A Redbark account with connected bank accounts
* A Redbark API key

## Setup

<Steps>
  <Step title="Get a Redbark API key">
    <Info>
      **Plan required:** Developer or Professional. API access is not available on the Saver plan.
    </Info>

    Log into [Redbark](https://app.redbark.com), go to **Settings > API Keys**, and create a new key. Copy it. It is only shown once.
  </Step>

  <Step title="Find your Redbark account IDs">
    Run the tool with `--list-redbark-accounts` to see your connected accounts and their IDs:

    ```bash theme={null}
    docker run --rm \
      -e REDBARK_API_KEY=YOUR_API_KEY \
      ghcr.io/redbark-co/actual-sync:latest \
      --list-redbark-accounts
    ```
  </Step>

  <Step title="Find your Actual Budget account IDs">
    Run with `--list-actual-accounts` to see your Actual Budget accounts:

    ```bash theme={null}
    docker run --rm \
      -e ACTUAL_SERVER_URL=http://localhost:5006 \
      -e ACTUAL_PASSWORD=your-password \
      -e ACTUAL_BUDGET_ID=your-budget-sync-id \
      -v actual-sync-data:/app/data \
      ghcr.io/redbark-co/actual-sync:latest \
      --list-actual-accounts
    ```

    You can also find account IDs in the Actual Budget web UI by copying the UUID from the account URL.
  </Step>

  <Step title="Create your account mapping">
    Map each Redbark account to an Actual Budget account using the format `redbark_id:actual_id`, comma-separated:

    ```
    ACCOUNT_MAPPING=rbk-acc-1:actual-acc-1,rbk-acc-2:actual-acc-2
    ```
  </Step>

  <Step title="Configure environment variables">
    Create a `.env` file with your configuration:

    ```bash theme={null}
    REDBARK_API_KEY=YOUR_API_KEY
    ACTUAL_SERVER_URL=http://localhost:5006
    ACTUAL_PASSWORD=your-password
    ACTUAL_BUDGET_ID=1cfdbb80-6274-49bf-b0c2-737235a4c81f
    ACCOUNT_MAPPING=rbk-acc-1:actual-acc-1,rbk-acc-2:actual-acc-2
    ```
  </Step>

  <Step title="Dry run">
    Preview what would be imported without writing any changes:

    ```bash theme={null}
    docker run --rm --env-file .env \
      -v actual-sync-data:/app/data \
      ghcr.io/redbark-co/actual-sync:latest --dry-run
    ```
  </Step>

  <Step title="Sync">
    Run the sync:

    ```bash theme={null}
    docker run --rm --env-file .env \
      -v actual-sync-data:/app/data \
      ghcr.io/redbark-co/actual-sync:latest
    ```
  </Step>
</Steps>

## Configuration

### Environment variables

| Variable                     | Required | Default                   | Description                                    |
| ---------------------------- | -------- | ------------------------- | ---------------------------------------------- |
| `REDBARK_API_KEY`            | Yes      |                           | Your Redbark API key (`YOUR_API_KEY`)          |
| `ACTUAL_SERVER_URL`          | Yes      |                           | URL of your Actual Budget server               |
| `ACTUAL_PASSWORD`            | Yes      |                           | Actual Budget server password                  |
| `ACTUAL_BUDGET_ID`           | Yes      |                           | Budget sync ID (Settings > Advanced in Actual) |
| `ACCOUNT_MAPPING`            | Yes      |                           | Account mapping (`redbark_id:actual_id,...`)   |
| `REDBARK_API_URL`            | No       | `https://api.redbark.com` | Redbark API base URL                           |
| `ACTUAL_ENCRYPTION_PASSWORD` | No       |                           | E2E encryption password if enabled             |
| `ACTUAL_DATA_DIR`            | No       | `/app/data`               | Local cache directory for Actual's SQLite DB   |
| `SYNC_DAYS`                  | No       | `30`                      | Number of days of history to sync              |
| `LOG_LEVEL`                  | No       | `info`                    | `debug`, `info`, `warn`, or `error`            |
| `DRY_RUN`                    | No       | `false`                   | Set to `true` to preview without importing     |

### CLI flags

| Flag                        | Description                                    |
| --------------------------- | ---------------------------------------------- |
| `--list-redbark-accounts`   | List Redbark accounts and their IDs            |
| `--list-redbark-categories` | List Redbark transaction categories            |
| `--list-actual-accounts`    | List Actual Budget accounts and their IDs      |
| `--dry-run`                 | Preview what would be imported without writing |
| `--days <n>`                | Override number of days to sync                |
| `--help`                    | Show help message                              |

## Running with Docker

### Docker run

```bash theme={null}
docker run --rm \
  --env-file .env \
  -v actual-sync-data:/app/data \
  ghcr.io/redbark-co/actual-sync:latest
```

The `/app/data` volume caches the Actual Budget SQLite database locally. Mount a persistent volume so it doesn't re-download the full budget every run.

### Docker Compose

```yaml theme={null}
services:
  redbark-actual-sync:
    image: ghcr.io/redbark-co/actual-sync:latest
    restart: "no"
    environment:
      - REDBARK_API_KEY=YOUR_API_KEY
      - ACTUAL_SERVER_URL=http://actual-server:5006
      - ACTUAL_PASSWORD=your-actual-password
      - ACTUAL_BUDGET_ID=your-budget-sync-id
      - ACCOUNT_MAPPING=redbark-acc-id:actual-acc-id
    volumes:
      - actual-sync-data:/app/data

  actual-server:
    image: actualbudget/actual-server:latest
    ports:
      - "5006:5006"
    volumes:
      - actual-data:/data

volumes:
  actual-sync-data:
  actual-data:
```

### Kubernetes CronJob

```yaml theme={null}
apiVersion: batch/v1
kind: CronJob
metadata:
  name: redbark-actual-sync
spec:
  schedule: "0 */6 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: sync
              image: ghcr.io/redbark-co/actual-sync:latest
              envFrom:
                - secretRef:
                    name: redbark-actual-sync-secrets
              volumeMounts:
                - name: data
                  mountPath: /app/data
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: redbark-actual-sync-data
```

## Scheduling

Use cron or your orchestrator's scheduling to run syncs automatically:

```bash theme={null}
# Sync every 6 hours
0 */6 * * * docker run --rm --env-file /home/user/.redbark-sync.env -v actual-sync-data:/app/data ghcr.io/redbark-co/actual-sync:latest >> /var/log/redbark-sync.log 2>&1
```

## How deduplication works

Each transaction is imported with an `imported_id` of `redbark:<transaction_id>`. Actual Budget's `importTransactions()` uses this to detect duplicates:

1. If a transaction with the same `imported_id` exists, it updates instead of creating a duplicate
2. If no `imported_id` match, Actual falls back to fuzzy matching on amount + date + payee

You can run the sync as often as you want. Duplicates are never created.

## Exit codes

| Code | Meaning                                                 |
| ---- | ------------------------------------------------------- |
| 0    | Sync completed successfully                             |
| 1    | Sync completed with errors (some transactions failed)   |
| 2    | Configuration error (missing env vars, invalid mapping) |
| 3    | Connection error (cannot reach Redbark or Actual)       |

## Troubleshooting

**Connection refused to Actual server**
Make sure your Actual Budget server is running and reachable from the Docker container. If both services are in the same Docker Compose stack, use the service name (e.g. `http://actual-server:5006`) rather than `localhost`.

**Budget not found**
Double-check your `ACTUAL_BUDGET_ID`. This is the **sync ID** found in Actual under Settings > Advanced, not the budget name.

**Encryption password required**
If you've enabled end-to-end encryption in Actual Budget, set the `ACTUAL_ENCRYPTION_PASSWORD` environment variable to your encryption passphrase.

**Self-signed certificates**
For Actual servers behind self-signed TLS certificates, set `NODE_EXTRA_CA_CERTS=/path/to/cert.pem` in the container environment.

**Version mismatch**
The tool automatically detects your Actual server version and downloads a matching client library. If you see version errors, make sure the `/app/data` volume is mounted so the cached client persists between runs.

## Security

<Info>
  Your Redbark API key is only sent over HTTPS. Never bake secrets into Docker images. Use `--env-file`, Docker Secrets, or Kubernetes Secrets. The tool caches your Actual budget locally in `ACTUAL_DATA_DIR`, so encrypt the Docker volume on shared infrastructure.
</Info>

## Source code

The sync tool is open source: [github.com/redbark-co/actual-sync](https://github.com/redbark-co/actual-sync)
