Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

Agent-safe banking control plane for infrastructure and AI agents.

`@hasna/banking` is the public OSS package for a provider-capability model,
typed SDK, `banking` CLI, and `banking-mcp` entrypoint. It is request-oriented:
agents can inspect banking state and request payment/card actions, but live
money movement must pass policy, idempotency, approval, audit, and
reconciliation gates.
`@hasna/banking` provides a provider-capability model, typed SDK, `banking`
CLI, and `banking-mcp` descriptor entrypoint. It is request-oriented: Mercury
state can be read through the explicit live-read adapter, while payment and
card commands create local intent envelopes. No provider-side mutation path is
enabled.

## Target Surfaces

| Surface | Target |
| --- | --- |
| Local folder | `open-banking` |
| GitHub repo | `hasna/banking` |
| npm package | `@hasna/banking` |
| CLI | `banking` |
Expand Down Expand Up @@ -44,14 +43,17 @@ provider conformance task.
| Mercury mutations | Descriptor and request-envelope only. Payments, internal transfers, card lifecycle, webhooks, recipients, attachments, categories, customers, invoices, onboarding, and metadata writes do not execute provider side effects. |
| Erste BCR PSD2 AIS/PIS | Descriptor and conformance-fixture only. Consent, SCA, account, transaction, payment, cancellation, and creditor-confirmation flows are modeled but not executed against sandbox or production. |
| Erste BCR non-PSD2 extras | Unsupported. Direct card control, card-account AIS, funds confirmation, signing baskets, party verification, sensitive card data, and Mercury-style webhooks fail closed. |
| MCP tools | Local descriptors and request envelopes only. Generic card MCP helpers deny unsupported providers such as Erste BCR through policy. |
| Generic SDK reads | Return `provider_backed_pending`; use `createMercuryReadClient` or the live CLI commands for implemented Mercury reads. |
| MCP tools | Callable as local library helpers for descriptors and request envelopes. The binary lists tools but does not implement the MCP wire protocol. |

## Install

```bash
bun add @hasna/banking
```

Runtime and source-development commands require Bun 1.3 or newer.

## State and paths

The package currently owns no persistent user-level state, and installation
Expand Down Expand Up @@ -80,7 +82,10 @@ banking cards list --provider mercury --account acct_123 --live true --environme
banking transactions list --provider mercury --live true --environment sandbox --limit 10 --order desc --json
banking transactions list --provider mercury --account acct_123 --live true --environment sandbox --limit 10 --order desc --json
banking payments request --provider mercury --account acct_123 --amount 10.00 --currency USD --to "Vendor" --recipient recipient_123 --rail ach --json
banking payments status --provider mercury --request req_123 --provider-payment mercury_123 --json
banking cards request --provider mercury --account acct_123 --label "Ops" --limit-month 250.00 --currency USD --json
banking cards update --provider mercury --card card_123 --label "Travel" --json
banking cards freeze --provider mercury --card card_123 --json
```

Mercury live reads are available for accounts, balances, transactions, and
Expand All @@ -104,6 +109,9 @@ For source checkouts:
BANKING_MERCURY_LIVE_SMOKE=true BANKING_MERCURY_ENVIRONMENT=sandbox BANKING_MERCURY_LIVE_SMOKE_LIMIT=1 bun run smoke:mercury:live
```

See the [CLI reference](docs/CLI.md) for the complete command, option,
credential, output, and exit-status contract.

`banking ops list`, `banking ops describe`, and `banking ops plan` expose the
shared provider operation registry used to expand CLI, SDK, and MCP surfaces.
The Mercury registry covers the current official API families: accounts,
Expand Down Expand Up @@ -143,7 +151,9 @@ const banking = createBankingClient();
console.log(banking.listProviders());
```

The SDK exports provider capability cards and provider-agnostic primitives for:
See the [SDK reference](docs/SDK.md) for the current exported surfaces and
execution boundaries. The SDK exports provider capability cards and
provider-agnostic primitives for:

- exact minor-unit money values;
- request-oriented payment and card intents;
Expand All @@ -165,13 +175,18 @@ See [`docs/migration/iapp-payments-to-banking.md`](docs/migration/iapp-payments-
for the migration checklist from existing payment integrations to the
provider-operation model.

For all current and historical pages, see the [documentation index](docs/README.md).

## MCP

```bash
banking-mcp --help
banking-mcp --list-tools
```

The MCP entrypoint exposes stable tool descriptors and local request-envelope
dispatch helpers. The full MCP protocol server lands after the store and
provider adapter nodes.
See the [MCP reference](docs/MCP.md) for every tool and dispatch input. The
MCP module exposes stable tool descriptors and local request-envelope
dispatch helpers. `banking-mcp --list-tools` prints descriptors and provider
cards as JSON. Invoking `banking-mcp` without one of the implemented flags
prints an error and exits with status 1 because the MCP protocol server is not
implemented.
97 changes: 97 additions & 0 deletions docs/CLI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# CLI reference

The `banking` binary exposes provider descriptors, four Mercury live-read
operations, and local payment/card intent builders. It does not execute
provider-side mutations.

```bash
banking --help
banking --version
```

`-h` and `-v` are aliases. Options accept either `--key value` or
`--key=value`. `--json` requests JSON output where a command can otherwise emit
plain text.

## Provider operation registry

| Command | Required input | Optional input | Result |
| --- | --- | --- | --- |
| `ops list` | none | `--provider`, `--safety`, `--include-unsupported true`, `--json` | Matching operation descriptors. Unsupported descriptors are omitted by default. |
| `ops describe <provider.operation>` | operation id | `--json` | One operation descriptor or an invalid-request error. |
| `ops plan <provider.operation>` | operation id, `--environment` | `--scopes <scope,...>`, `--env-keys <KEY,...>`, `--json` | A non-executing environment, credential, scope, and conformance plan. |
| `providers list` | none | `--json` | All provider capability cards. |
| `providers show <provider>` | provider id | `--json` | One provider capability card. |

Valid providers are `mercury`, `bunq`, `revolut-business`, and `erste-bcr`.
Valid environments are `sandbox` and `production`. Valid `--safety` values are
`read`, `metadata_write`, `money_movement`, `card_lifecycle`,
`sensitive_read`, `webhook_mutation`, and `auth_flow`.

`--scopes` and `--env-keys` are comma-separated. The singular aliases
`--scope` and `--env-key` are also accepted. Supplying environment key names to
`ops plan` marks them present for preflight; never put credential values on the
command line.

## Live reads

Live reads require `--live true`, `--provider mercury`, and an explicit
`--environment sandbox|production`. Without `--live true`, read commands fail
closed with exit status 2. Other providers also fail closed with status 2.

| Command | Required input | Pagination and filters |
| --- | --- | --- |
| `accounts list` | `--provider` | `--limit 1..1000`, `--order asc|desc`, one of `--start-after` or `--end-before` |
| `balances get` | `--provider`, `--account` | none |
| `transactions list` | `--provider` | optional `--account`, `--limit 1..1000`, `--order asc|desc`, one of `--start-after`, `--end-before`, or `--start-at` |
| `cards list` | `--provider` | optional `--account`, `--limit 1..1000`, `--order asc|desc`, one of `--start-after` or `--end-before` |

Credentials resolve in this order: the environment-specific
`MERCURY_SANDBOX_API_KEY` or `MERCURY_PRODUCTION_API_KEY`, then
`MERCURY_API_KEY`, then the optional `--secret-key <reference>`. A secret
reference is resolved by running `secrets get <reference>` locally; it is not a
raw token argument.

The client sends Bearer authentication to the environment-specific Mercury API
base URL. Responses are normalized and sensitive account/routing/card fields
are reduced to summaries; raw credentials are never returned.

## Local intent envelopes

These commands return an intent, its idempotency fingerprint, and a policy
decision. They never submit the intent to a provider.

| Command | Required input | Optional input |
| --- | --- | --- |
| `payments quote` | `--provider`, `--account`, `--amount`, `--currency`, `--to` | `--recipient`, `--rail` |
| `payments request` | `--provider`, `--account`, `--amount`, `--currency`, `--to` | `--recipient`, `--rail` |
| `payments status` | `--provider`, `--request` | `--provider-payment` |
| `cards request` | `--provider`, `--account`, `--label` | `--limit-month` with required `--currency` |
| `cards update` | `--provider`, `--card` | `--label` |
| `cards freeze` | `--provider`, `--card` | none |
| `cards unfreeze` | `--provider`, `--card` | none |
| `cards terminate` | `--provider`, `--card` | none |

All envelope commands accept `--actor <id>` (default `agent-cli`),
`--reason <text>` (a command-specific default), `--live true`, and
`--environment sandbox|production` (default `sandbox`). `--live true` changes
policy evaluation only; it does not enable provider submission. Payment rails
default to `ach`. Currency codes are uppercased before money parsing.

## Admin gate

`banking admin --help` reports the planned administrative surface. Any other
`admin` command returns `admin_approval_required`; provider verification is not
implemented.

## Output and exit status

| Status | Meaning |
| --- | --- |
| `0` | Help/version or a command completed successfully. A successful local envelope may still contain a denied policy decision. |
| `1` | Unknown command, missing/invalid input, invalid provider/environment, or provider/API error caught as `invalid_request`. |
| `2` | A requested read adapter is not implemented, live mode was omitted, or the provider has no live adapter. |
| `3` | An administrative command is gated. |

Structured errors are written to stderr. Unknown commands are plain text unless
`--json` is set; validation and adapter errors are JSON objects in either mode.
59 changes: 59 additions & 0 deletions docs/MCP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# MCP reference

The package contains an MCP-shaped descriptor and local dispatch module, not an
MCP protocol server.

## Binary

```bash
banking-mcp --help
banking-mcp --version
banking-mcp --list-tools
```

`-h` and `-v` are aliases. These commands exit with status 0.
`--list-tools` prints tool descriptors and provider capability cards as JSON.
Invoking the binary without an implemented flag prints an error and exits 1;
it does not start a stdio, HTTP, or SSE MCP transport.

## Library dispatch

The MCP module exports `listMcpTools`, `listMcpToolDescriptors`,
`listPlannedMcpTools`, and `runMcpTool`. `runMcpTool(name, input)` is a local
function call and does not perform MCP transport or schema negotiation.

| Tool | Status | Input |
| --- | --- | --- |
| `banking_ops_list` | implemented | optional `providerId`, `includeUnsupported` |
| `banking_ops_describe` | implemented | `operationId` |
| `banking_ops_plan` | implemented | `operationId`, `environment`; optional `grantedScopes`, `envKeys` |
| `banking_providers_list` | implemented | none |
| `banking_provider_get` | implemented | `providerId` |
| `banking_accounts_list` | provider-backed pending | `providerId` |
| `banking_balance_get` | provider-backed pending | `providerId`, `accountId` |
| `banking_transactions_list` | provider-backed pending | `providerId`, `accountId` |
| `banking_cards_list` | provider-backed pending | `providerId` |
| `banking_payment_quote` | implemented locally | payment input |
| `banking_payment_request` | implemented locally | payment input |
| `banking_payment_status` | implemented locally | `providerId`, `paymentRequestId`; optional `providerPaymentId` |
| `banking_card_request` | implemented locally | `providerId`, `accountId`, `label` |
| `banking_card_update_request` | implemented locally | `providerId`, `cardId`; optional `label` |
| `banking_card_freeze_request` | implemented locally | `providerId`, `cardId` |
| `banking_card_unfreeze_request` | implemented locally | `providerId`, `cardId` |
| `banking_card_terminate_request` | implemented locally | `providerId`, `cardId` |
| `banking_admin_provider_verify_operation` | admin gated | none |

Payment input requires `providerId`, `sourceAccountId`, `counterpartyName`,
`amount`, and `currency`; `providerRecipientId`, `rail`, `actorId`, `reason`,
`liveMode`, and `environment` are optional. The default rail is `ach`, actor is
`agent-mcp`, and environment is `sandbox`.

Card and payment tools create local intent envelopes only. `liveMode: true`
changes policy evaluation but does not submit the intent. Generic read tools
return `provider_backed_pending` and do not use the Mercury network adapter.
The admin tool returns `admin_approval_required`. Unknown names return
`not_implemented` rather than throwing.

`grantedScopes` and `envKeys` accept either a comma-separated string or a string
array. Provider ids and environments are validated. Missing required string
fields throw an error to the direct caller.
19 changes: 19 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Documentation

Current behavior is documented here:

- [CLI reference](CLI.md): commands, options, credentials, output, and exit status.
- [SDK reference](SDK.md): exported surfaces, execution boundaries, workflow, and stores.
- [MCP reference](MCP.md): binary behavior, tool descriptors, dispatch inputs, and limitations.
- [State layout](STATE_LAYOUT.md): package-owned and caller-owned paths.
- [Postgres schema](schema/postgres.sql): production-store reference schema and transaction boundary.
- [Migration guide](migration/iapp-payments-to-banking.md): moving direct integrations to the provider-operation model.

Dated research and evidence are retained separately:

- [Provider API inventory (2026-06-29)](providers/api-inventory-2026-06-29.md)
- [0.0.2 release evidence](releases/0.0.2.md)
- [0.0.7 release evidence](releases/0.0.7.md)

Dated pages describe what was checked or released at that time. Use the current
references above for the package's present command and API behavior.
91 changes: 91 additions & 0 deletions docs/SDK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# SDK reference

The package root exports the core model, provider model and contracts, Mercury
read adapter, and Bun SQLite development store.

```ts
import {
createBankingClient,
createMercuryReadClient,
createSqliteDevStore,
moneyFromDecimal,
} from "@hasna/banking";
```

## Client boundary

`createBankingClient()` provides provider capability lookup and local intent
envelope builders. Its generic read methods validate the provider and return a
`provider_backed_pending` result; they do not call provider APIs.

| Method | Current result |
| --- | --- |
| `listProviders`, `getProvider` | Provider capability cards. |
| `listAccounts`, `getBalance`, `listTransactions`, `listCards` | `provider_backed_pending`; no network call. |
| `createPaymentQuote`, `createPaymentRequest`, `createPaymentStatus` | Local intent, idempotency fingerprint, and policy decision. |
| `createCardRequest`, `createCardUpdate`, `createCardLifecycle` | Local intent, idempotency fingerprint, and policy decision. Unsupported provider/card combinations are denied by policy. |

Creating an envelope never submits it. The default policy is dry-run sandbox
mode, requires approval for provider side effects, and denies sensitive card
data. Callers can supply a `BankingPolicy` to the envelope methods.

## Mercury live reads

`createMercuryReadClient` is the only network-backed SDK adapter. It requires an
explicit `sandbox` or `production` environment and resolves credentials from an
`apiKey`, the matching environment variable, `MERCURY_API_KEY`, or an optional
secret reference callback/CLI.

The adapter implements:

- `listAccounts`;
- `getBalance`;
- `listCards`, optionally account-filtered;
- `listTransactions`, optionally account-filtered.

List methods accept limit, order, and cursor input. Limits must be between 1
and 1000. Only transactions accept `startAt`. Responses are normalized into
summary types; account/routing numbers and card details are not exposed as raw
provider payloads. `MercuryCredentialError` reports credential failures and
`MercuryApiError` reports sanitized transport, response, and validation errors.

## Provider registry and contracts

Use `listOperationDescriptors`, `getOperationDescriptor`, or
`requireOperationDescriptor` to inspect provider operations. `planProviderOperation`
combines the descriptor with environment, scope, credential-key, and provider
security preflights. A plan describes readiness; it does not execute an
operation.

Provider contract helpers validate request shape and build provider-safe
request descriptors. Conformance exports pin the Mercury live-read allowlist
and the Erste BCR AIS/PIS fixture surface. A documented provider capability is
not proof of implemented execution: check descriptor `executionMode`,
`liveReadEnabled`, `providerSideEffectsEnabled`, and conformance fields.

## Core workflow

The core exports exact minor-unit money helpers, typed payment/card intents,
policy evaluation, deterministic idempotency fingerprints, maker-checker
approvals, redacted hash-chained audit events, reconciliation, and execution
workflow helpers.

`submitExecutionRequest` reserves idempotency, saves the intent, appends audit
evidence, and returns one of the workflow states. Approved requests enqueue a
`provider.dry_run` outbox entry with `providerSideEffectsEnabled: false`; the
workflow does not perform a provider mutation. Approval execution verifies the
intent binding, payload hash, expiry, human approver, maker-checker separation,
and policy snapshot.

## Stores

`BankingCoreStore` is the asynchronous storage contract. `createSqliteDevStore`
implements it with `bun:sqlite`, uses `:memory:` by default, and is explicitly
`mode: "dev"`. A supplied file path is caller-owned. The store supports
idempotency reservations, intents, approvals, audit events, reconciliation,
and outbox transitions, plus a development-only `reset()`.

Production implementations should follow the [Postgres reference
schema](schema/postgres.sql) and perform reservation, intent persistence,
approval validation, audit append, and outbox enqueue in one serializable
transaction before any future provider side effect.
6 changes: 3 additions & 3 deletions docs/migration/iapp-payments-to-banking.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
Date: 2026-06-29

This note is for moving existing payment or bank-integration code, including
`iapp-payments`-style flows, onto the public `hasna/banking` OSS package while
keeping the local checkout folder named `open-banking`.
`iapp-payments`-style flows, onto the public `hasna/banking` OSS package.

## Naming

Expand All @@ -14,7 +13,6 @@ keeping the local checkout folder named `open-banking`.
| npm package | `@hasna/banking` |
| CLI binary | `banking` |
| MCP binary | `banking-mcp` |
| Local folder | `open-banking` |

Do not keep a separate plain-provider integration path. Provider behavior should
flow through the operation registry, SDK policy primitives, CLI commands, and
Expand Down Expand Up @@ -50,6 +48,8 @@ MCP descriptors.
6. Keep provider execution behind conformance, approval, idempotency, audit,
reconciliation, and adversarial review gates.

See the [CLI reference](../CLI.md) for the complete current command contract.

## Smoke And Verification

```bash
Expand Down
Loading
Loading