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> |
||
|---|---|---|
| src | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package.json | ||
| README.md | ||
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:3456for local dev orhttps://yourserver.example.comfor 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.jsonduring setup. If you need to change it later (e.g. you added a reverse proxy), re-runnpm run setupor editdata/store.jsondirectly and updateconfig.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_urlindata/store.jsonis 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