For agents

Give an AI agent the BankSync CLI and an API key: a stable JSON contract, machine-readable errors and exit codes, runtime command and schema discovery, and a raw API escape hatch.

5 min read

On this page

The BankSync CLI is a first-class tool for AI agents, not only for humans. A shell tool plus an API key gives an agent everything it needs to read financial data, manage feeds, and trigger syncs, with a contract stable enough to build on. In practice, a well-designed CLI is often a better agent surface than a bespoke API integration: the output is structured, the errors are machine-readable, and the whole command surface is discoverable at runtime.

Give your agent the CLI and a key#

Wire it up

  1. Install the CLI

    Drop the standalone binary into the agent's environment with the one-line installer (curl -fsSL https://banksync.io/install.sh | sh). It is self-contained, so the environment needs no Node or other runtime. See installation.
  2. Provide a scoped API key

    Set BANKSYNC_API_KEY in the agent's environment with a least-privilege key created in Settings > Developers. No interactive login is needed.
  3. Let the agent discover the surface

    The agent runs banksync commands --json and banksync schema --json to learn every command, flag, entity, and exit code, then calls commands with --json.

The contract an agent can rely on#

Stable JSON envelope

Every read returns { "data": ..., "meta": ... }. The agent can always read .data and page with meta.cursor and meta.has_more.

Machine-readable errors

Failures print one JSON object on stderr and set a stable exit code, so the agent branches on failure without parsing prose.

No blocking

In any non-interactive context the CLI never prompts. A missing argument is an error, not a hang.

Runtime discovery

commands --json and schema --json expose the entire surface, so an agent needs no out-of-band docs to act.

The JSON envelope#

Ask for JSON with --json (any pipe also triggers it). Every read has the same top-level shape regardless of the command:

JSON
{  "data": [    {      "id": "txn_1",      "date": "2026-03-01",      "description": "UBER",      "amount": -24.5,      "currency": "USD"    }  ],  "meta": {    "count": 1,    "cursor": "eyJvIjoxMDB9",    "has_more": true,    "schema_version": "1",    "api_version": "v1"  }}
  • data holds raw entity fields (ISO dates, unformatted numbers), never humanized strings.
  • meta.cursor and meta.has_more drive pagination; when they are null the endpoint does not paginate.
  • meta.schema_version is the output-contract version. It is also emitted by commands --json, so an agent can assert the contract it was built against.

Errors and exit codes#

In JSON mode, an error is a single object on stderr while stdout stays empty:

JSON
{  "error": {    "code": "rate_limited",    "message": "Too many requests.",    "status": 429,    "hint": "Rate limited. Retrying automatically; slow down or pass --no-retry.",    "retry_after": 60  }}

The process exit code classifies the failure so an agent can react programmatically:

CodeMeaning
0Success
1Generic or unexpected error (including 5xx)
2Invalid usage or bad request (400)
3Unauthenticated or forbidden (401 or 403)
4Resource not found (404)
5Conflict (409)
6Semantic validation failed (422)
7Rate limited (429)
8Provider does not support this capability (501)
9Backend unavailable or consent required (503)

An agent that gets exit code 3 knows to check the credential; a 5 on a sync means it should retry with --force; a 7 means back off.

Discover the whole surface at runtime#

An agent does not need to read documentation to act. Two commands expose everything, and neither emits telemetry.

Command catalog#

banksync commands --json returns the entire command tree, plus the exit-code map and the output-contract version:

Shell
banksync commands --json
JSON
{  "cli": "banksync",  "output_contract_version": "1",  "api_version": "v1",  "exit_codes": {    "0": "Success",    "3": "Unauthenticated or forbidden (401/403)",    "5": "Conflict (409)"  },  "commands": [    {      "id": "transactions list",      "summary": "List transactions for a bank or a single account, resolving names or partial ids.",      "aliases": ["tx"],      "args": [{ "name": "bid", "required": false, "description": "Bank id or name." }],      "flags": [        {          "name": "from",          "type": "option",          "required": false,          "description": "Start date YYYY-MM-DD."        },        {          "name": "all",          "type": "boolean",          "required": false,          "description": "Fetch all pages (follows the cursor)."        }      ]    }  ]}

The agent enumerates command ids, required args, flag names, types, and enum options directly from this output, then constructs a call.

Entity schema#

banksync schema --json lists the entities, and banksync schema <entity> --json returns the default columns (the selectable dot-paths for --fields):

Shell
banksync schema --jsonbanksync schema transaction --json
JSON
{  "data": {    "entity": "transaction",    "default_columns": ["date", "description", "amount", "currency", "category", "pending"]  },  "meta": { "count": 1 }}

Known entities include bank, account, balance, transaction, trade, holding, order, loan, feed, job, enrichment, integration, and institution.

Stream large reads with NDJSON#

For a large pull, -o ndjson emits one raw entity per line, which an agent can consume incrementally without buffering the whole response:

Shell
banksync tx list --bank amex --all -o ndjson

Each line is a complete JSON object, ideal for streaming into a processing loop.

The raw API escape hatch#

Any endpoint that does not yet have a dedicated command is reachable through banksync api, which reuses the same auth, retries, and output path. It takes an HTTP method and path, an optional body (inline JSON, @file, or - for stdin), and repeatable --query params:

Shell
banksync api GET /v1/banksbanksync api GET /v1/feeds --query dataType=transactionsecho '{"name":"My rule"}' | banksync api POST /v1/enrichments --data -

In a machine format, the raw response body is echoed verbatim, so an agent sees exactly what the API returned. This future-proofs the surface: an agent is never blocked by a missing command.

Non-interactive guarantees#

Deterministic and quiet by default

When stdout is not a terminal, the CLI emits JSON, never prompts, disables color and spinners, and sends any notice to stderr, so stdout is byte-clean for parsing. You can force this posture explicitly with --no-input, --json, and --quiet. Destructive commands still require --yes, which prevents an agent from deleting or cancelling by accident.

A worked example#

An agent asked to summarize spending would typically:

Shell
# 1. Confirm the credential and workspacebanksync whoami --json
# 2. Find the bank by namebanksync banks list --json | jq -r '.data[] | select(.name|test("Amex";"i")) | .id'
# 3. Pull the quarter's transactions as a streambanksync tx list --bank amex --from 2026-01-01 --to 2026-03-31 --all -o ndjson
# 4. On exit code 3, stop and report an auth problem; on 7, back off and retry

Each step is structured input and structured output, with a clear exit code, so the agent can chain steps and recover from failure on its own.

Next steps#

Use this page with your AI assistant

Every BankSync doc is available as plain Markdown for agents and LLMs.