# Qonto Assistant Operator Runbook ## What this Phase 1 service does `qonto-assistant` is the read-only REST surface for governed Qonto access. Phase 1 ships: - policy-gated `GET /v1/accounts` - policy-gated `GET /v1/transactions` - policy-gated `GET /v1/snapshot` - structured audit events without secrets - env-backed or OpenBao-CLI-backed credential loading Spend, transfer, card, invoicing, payment-link, and other volume-cost actions remain denied by policy. ## Preferred local workflow If `make` and `python3 -m venv` are available: ```bash make install-dev make test make run ``` The API then listens on `http://127.0.0.1:8080`. ## Verified fallback on this workstation This workstation currently lacks: - `make` - `python3 -m venv` support (`ensurepip` missing) - `python3 -m pip` Use an existing fleet virtualenv that already contains FastAPI/httpx/pytest: ```bash PYTHONPATH=src ../state-hub/.venv/bin/python -m pytest python3 -m compileall src tests ``` This fallback was used to verify the current implementation. ## Credential sources ### Option A: env-injected credentials Provide either: - `API_USER` + `API_KEY` - or `QONTO_ORGANIZATION_ID` + `QONTO_API_KEY` Example: ```bash export API_USER='...' export API_KEY='...' ``` ### Option B: OpenBao CLI fetch inside the service Set: ```bash export QONTO_CREDENTIAL_SOURCE=bao-cli export QONTO_OPENBAO_PATH=tenants/binky/qonto-api export QONTO_OPENBAO_COMMAND=bao ``` The service then shells out to `bao kv get -field=...` and caches the credentials in memory for a short TTL. ## Start the API Preferred: ```bash make run ``` Fallback: ```bash PYTHONPATH=src ../state-hub/.venv/bin/python -m qonto_assistant.main ``` ## Fixture-backed local mode For local smoke work without real bank credentials: ```bash export QONTO_FIXTURE_DIR=tests/fixtures/qonto PYTHONPATH=src ../state-hub/.venv/bin/python -m qonto_assistant.main ``` In this mode the service serves canned Qonto organization and transaction payloads from `tests/fixtures/qonto/`. ## One-command HTTP smoke ```bash ../state-hub/.venv/bin/python scripts/smoke_rest_api.py \ --python ../state-hub/.venv/bin/python ``` This starts the service on a random local port against the fixture payloads, checks `/v1/health`, `/v1/accounts`, a recent `31`-day snapshot, and a wider `90`-day cost-review snapshot, then shuts the process down. ## Example calls Minimal local call: ```bash python3 - <<'PY' import json import urllib.request req = urllib.request.Request( "http://127.0.0.1:8080/v1/accounts", headers={"X-Actor-ID": "local-operator", "X-Tenant-ID": "binky"}, ) with urllib.request.urlopen(req, timeout=10) as resp: print(json.dumps(json.load(resp), indent=2)) PY ``` Transactions view: ```bash python3 - <<'PY' import json import urllib.request req = urllib.request.Request( "http://127.0.0.1:8080/v1/transactions?page_size=50&window_days=31", headers={"X-Actor-ID": "finance-steward", "X-Tenant-ID": "binky"}, ) with urllib.request.urlopen(req, timeout=10) as resp: print(json.dumps(json.load(resp), indent=2)) PY ``` Snapshot for CostRunRate refresh: ```bash python3 - <<'PY' import json import urllib.request req = urllib.request.Request( "http://127.0.0.1:8080/v1/snapshot?window_days=90&page_size=50", headers={"X-Actor-ID": "finance-steward", "X-Tenant-ID": "binky"}, ) with urllib.request.urlopen(req, timeout=10) as resp: print(json.dumps(json.load(resp), indent=2)) PY ``` Use `window_days=31` for a recent-activity view. Use `window_days=90` or `93` when recurring fixed-cost hints are required. ## MCP surface Phase 2 mounts a streamable-HTTP MCP adapter at `/mcp` on this same process, sharing the policy kernel and audit layer above. See `docs/mcp-integration.md` for the tool catalog, the auth model (`QONTO_ASSISTANT_MCP_TOKEN`), and the shared client config snippet. ## CostRunRate refresh path `binky-control` should consume `GET /v1/snapshot` and extract: - redacted organization/account summary - recent transactions - recurring debit hints for fixed-cost review The repo does not write directly into `binky-control/finance/CostRunRate.md`. That consumer-side write remains outside this repo. ## Safety notes - Never print or commit `API_KEY`. - Prefer `X-Tenant-ID: binky` explicitly even in single-tenant dogfood. - Audit output is metadata-only; account identifiers stay redacted by default. - The service supports a `bearer` auth mode for future upstream evolution, but the current dogfood path remains `legacy_api_key` because that is the proven BINKY-WP-0005 header mode.