Basic HTTP Api wrapping the Actual Budget NodeJS api.
Lightweight HTTP wrapper around the Actual Budget Node.js API. Exposes a simple REST interface so non-Node apps can interact with an Actual server.
Use the publicly published Docker image (replace the tag with the desired version):
docker run -d --name actualhttpapi \
-v "$PWD/data:/data:rw" \
-p 5007:5007 \
-e ACTUAL_SERVER_URL="http://actual-server:5006/" \
-e ACTUAL_SERVER_PASSWORD="your-actual-password" \
-e API_KEY="your-api-key" \
jhonderson/actual-http-api:26.10.0- Replace
jhonderson/actual-http-api:26.10.0with the specific tag you want. - The service exposes the Swagger UI at
http://localhost:5007/api-docs/by default (see swagger env vars below if you need to change how docs are served).
Tip: For secrets you can also mount files and use the _PATH variant of the environment variables (see API_KEY_PATH / ACTUAL_SERVER_PASSWORD_PATH).
- Run with Docker Compose
docker-compose up -dThis will start the service using the docker-compose.yml configuration in this repo. Adjust envs in the compose file or override with an .env file.
- Run directly with Node.js
npm install
npm start
# or
node server.jsCreate a .env file in the project root for local development environment variables (the project loads .env when NODE_ENV !== 'production').
The service reads several environment variables (from src/config/config.js). Defaults are shown where applicable.
API_KEY(required) orAPI_KEY_PATH— SECRET API key string used by clients to authenticate to this wrapper.- Important:
API_KEYmust be generated and kept secret by the person deploying this service (for example with a random generator). It authenticates callers of the HTTP wrapper only — it is NOT a credential from the Actual Budget server. - You can provide the key directly via
API_KEYor place it in a file and point to it withAPI_KEY_PATH(useful for Docker secrets).
- Important:
ACTUAL_SERVER_PASSWORD(required) orACTUAL_SERVER_PASSWORD_PATH— Password for the Actual server. Can be provided directly or via a file path.ACTUAL_SERVER_URL(required) — Base URL of your Actual server (e.g.http://actual-server:5006/).ACTUAL_DATA_DIR(optional) — Path to the Actual server data directory (used if you need to point at local data).PORT(optional) — Port this service listens on. Default:5007.NODE_ENV(optional) — Node environment (e.g.production,development). If notproduction,.envwill be loaded bydotenv.
Swagger / API docs configuration (defaults used to build the docs URL shown in the UI):
SWAGGER_PROTOCOL— Default:httpsSWAGGER_HOST— Default:localhostSWAGGER_PORT— Default:443SWAGGER_BASE_PATH— Default:v1
Notes:
API_KEYandACTUAL_SERVER_PASSWORDare loaded using a helper that accepts either the value itself or a path to a file by appending_PATHto the variable name (useful for Docker secrets).- If you run the container mapping port
5007to the host (common for local runs), setSWAGGER_PROTOCOL=httpandSWAGGER_PORT=5007if you want the Swagger UI links to reflect your local address.
EXPERIMENTAL_OPERATIONS_ENABLED(optional) — Toggle to enable experimental endpoints that rely on Actual internals. Defaults to enabled (true). Set tofalseto disable these endpoints; when disabled the HTTP server will respond with501 Not Implementedfor those operations and they will be hidden from the Swagger UI.
POST /v1/budgets/import accepts an Actual export or a YNAB4/YNAB5 file as the raw request body, with Content-Type: application/zip or application/octet-stream, and returns the sync id of the imported budget.
Importing a budget that already exists does not restore it in place. The Actual library clears the file's server identity on import, so the budget is uploaded to your Actual server as a new file and receives a new sync id. The original budget and its sync id are left untouched, so you end up with two budgets rather than one. Use the syncId returned in the response to address the imported budget.
curl -X POST 'http://localhost:5007/v1/budgets/import?type=actual' \
-H 'x-api-key: your-api-key' \
-H 'Content-Type: application/zip' \
--data-binary '@2026-09-06-My-Budget.zip'When running locally with default port mapping, open:
http://localhost:5007/api-docs/
- If the server fails to start due to missing secrets, ensure
API_KEYandACTUAL_SERVER_PASSWORD(or their_PATHequivalents) are provided. - For production, run with
NODE_ENV=productionand provide secrets via a secrets manager or the_PATHpattern.
- Run unit tests:
npm testSee USAGE_EXAMPLES.md for ready-to-use use cases:
- budget_backup.sh: Backup your Actual Budget using a bash script
- fly.toml: Configuration file to deploy actual-http-api to Fly.io
- update_account_balances.py: Script to update your investment account balances in Actual Budget (this script can only be used with actual-http-api version 26.4.0 and onwards)