actual-gocardless-proxy/README.md
jeanGaston 2487d8a2f9 docs: README with full setup guide
Covers: Enable Banking signup, RSA key generation, running setup script,
docker-compose wiring, OAuth redirect flow diagram, supported French banks,
and troubleshooting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 10:34:52 +02:00

7.5 KiB

actual-gocardless-proxy

A drop-in GoCardless Bank Account Data API proxy server that lets Actual Budget sync with French (and other European) bank accounts via Enable Banking — a free PSD2 aggregator.

Zero modifications to actual-server. The only change is setting one environment variable:

GOCARDLESS_BASE_URL=http://gocardless-proxy:3456

How it works

Actual Budget (browser)
    │  GoCardless API calls
    ▼
actual-server
    │  GOCARDLESS_BASE_URL → http://gocardless-proxy:3456
    ▼
gocardless-proxy   ◄── this repo
    │  Enable Banking PSD2 API
    ▼
Enable Banking → French banks (BNP, SG, CA, LCL, BP, …)

The proxy translates GoCardless API shapes ↔ Enable Banking shapes on the fly and persists all state (tokens, requisitions, account mappings) in ./data/store.json so Docker restarts don't break existing account links.


Setup

1. Sign up for Enable Banking

Go to enablebanking.com and create a free personal account. Under your app settings, note your Application ID.

2. Generate an RSA key pair

Enable Banking uses RS256 JWT auth. You need to provide your public key in the Enable Banking dashboard and keep the private key on your server.

# Generate a 2048-bit RSA private key in PKCS8 format
openssl genpkey -algorithm RSA -pkcs8 -out private_key.pem -pkeyopt rsa_keygen_bits:2048

# Extract the public key (upload this to Enable Banking)
openssl pkey -in private_key.pem -pubout -out public_key.pem

Upload public_key.pem in the Enable Banking dashboard under your application's API settings.

Keep private_key.pem somewhere safe — you'll need it in the next step.

3. Run the setup script

Clone this repo and install dependencies:

git clone https://github.com/yourname/actual-gocardless-proxy
cd actual-gocardless-proxy
npm install

Run the interactive setup:

npm run setup

The script will ask for:

  • Your Enable Banking Application ID
  • Path to your private key PEM file
  • The proxy base URL (the URL that Enable Banking will redirect to after OAuth — must be reachable from your browser; e.g. http://localhost:3456 for local dev or https://yourserver.example.com for production)

It will generate a random secret_id and secret_key pair and print them:

──────────────────────────────────────────────────────────
Enter these values in Actual Budget → Settings → GoCardless:

  Secret ID:  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

And set this environment variable on actual-server:

  GOCARDLESS_BASE_URL=http://gocardless-proxy:3456
──────────────────────────────────────────────────────────

All credentials are stored in ./data/store.json.

4. Add the proxy to your docker-compose.yml

In your existing actual-server docker-compose.yml, add the proxy service and wire it to actual-server:

services:
  actual-server:
    image: actualbudget/actual-server:latest
    # ... your existing config ...
    environment:
      GOCARDLESS_BASE_URL: http://gocardless-proxy:3456
      # ... your other env vars ...
    depends_on:
      - gocardless-proxy

  gocardless-proxy:
    build: /path/to/actual-gocardless-proxy
    # or: image: ghcr.io/yourname/actual-gocardless-proxy:latest
    container_name: gocardless-proxy
    restart: unless-stopped
    volumes:
      - /path/to/actual-gocardless-proxy/data:/app/data
    environment:
      PORT: 3456

Note on PROXY_BASE_URL: The proxy base URL is saved in data/store.json during setup. If you need to change it later (e.g. you added a reverse proxy), re-run npm run setup or edit data/store.json directly and update config.proxy_base_url.

5. Start the services

docker compose up -d

Verify the proxy is running:

curl http://localhost:3456/health
# → {"status":"ok","configured":true}

6. Configure Actual Budget

In Actual Budget, go to Settings → GoCardless and enter the secret_id and secret_key printed in step 3.

You can now go to Accounts → Link account and search for your French bank.


OAuth redirect flow

1. actual-server  POST /api/v2/requisitions/  { redirect: "http://actual:5006/..." }
                  ↓
2. proxy          POST https://api.enablebanking.com/auth
                    { aspsp: { name, country }, redirect_url: "http://proxy/callback",
                      state: <requisition_id> }
                  ← { url: "https://tilisy.enablebanking.com/..." }
                  ↓
3. proxy          returns requisition with link = EB auth URL
                  ↓
4. User           visits the link, authenticates at their bank
                  ↓
5. Enable Banking redirects → http://proxy/callback?code=xxx&state=<req_id>
                  ↓
6. proxy          POST https://api.enablebanking.com/sessions  { code }
                  ← { session_id, accounts: [uid, ...] }
                  → fetches account details, stores GC account IDs
                  → marks requisition status "LN" (linked)
                  → redirects → http://actual:5006/...?requisition_id=<req_id>
                  ↓
7. actual-server  GET /api/v2/requisitions/<req_id>/
                  ← { status: "LN", accounts: ["gc-acc-id-1", ...] }
                  ↓
8. actual-server  GET /api/v2/accounts/<id>/details/
                  GET /api/v2/accounts/<id>/balances/
                  GET /api/v2/accounts/<id>/transactions/

Supported banks

All French banks supported by Enable Banking, including:

Bank BIC
BNP Paribas BNPAFRPP
Société Générale SOGEFRPP
Crédit Agricole AGRIFRPP
LCL CRLYFRPP
Banque Populaire various
Caisse d'Épargne various
La Banque Postale PSSTFRPPPAR
Crédit Mutuel CMCIFRPP
CIC CMCIFRPP
Boursorama BOUSFRPPXXX
Fortuneo FTNOFRP1
Hello bank! BNPAFRPP

See enablebanking.com/docs/markets/fr/ for the full list.


Troubleshooting

"Proxy not configured" error

Run npm run setup and restart the container.

"Unknown institution_id" when creating a requisition

actual-server caches institutions. Go to Settings → GoCardless → Reset and re-fetch banks.

OAuth callback fails with "Enable Banking error"

  • Make sure proxy_base_url in data/store.json is reachable from your browser (not just from Docker).
  • Check that the redirect URL is whitelisted in your Enable Banking application settings.

Transactions not appearing

Enable Banking may return an empty transactions array for accounts with no activity in the requested date range. Try widening the date range.

Private key errors

Make sure the key is PKCS8 format. To convert from traditional RSA format:

openssl pkcs8 -topk8 -nocrypt -in old_key.pem -out private_key.pem

Data & privacy

All bank credentials and tokens stay on your server inside ./data/store.json. Nothing is sent to any third party except Enable Banking (which is the PSD2 provider) and your bank.

The data/ directory is git-ignored and should not be committed.


License

MIT