Sandbox reference
The sandbox API endpoints, seeded data, in-memory store semantics, and the documented known simplifications.
The sandbox (app/api/sandbox/*) is a synthetic implementation of the same API contract the
real FintechLab Client Office API serves — same endpoint paths, same DTO field names, same
enums, same auth flow. It exists so the MCP tools have something real to run against before
a live credential ever enters the picture.
Endpoints
| Endpoint | Purpose |
|---|---|
POST /token | Authenticate with X-Username / X-Password; returns an API token (also echoed in the X-Auth-Token response header). |
GET /accounts | List accounts, with balances. |
GET /cards | List cards. |
GET /transactions?page=&records= | List transactions, paginated. |
GET /transactions/{id} | A single transaction's full detail. |
POST /transfer/internal | Move money between the customer's own accounts (write demo — see below). |
These are the same six operations the MCP tools call; there is nothing in the sandbox that the tools don't exercise.
Seeded data
Each sandbox instance seeds a small, fictional dataset: a handful of accounts across a few
currencies, a couple of cards, and roughly 35–40 transactions spread across a few weeks —
groceries, salary, subscriptions, transfers, an ATM withdrawal, a refund — enough variety
for satchel_financial_summary's merchant grouping and subscription detection to have
something real to find.
In-memory store semantics
Sandbox state lives entirely in server process memory. It reseeds on every restart — there is no database and nothing to migrate. A shape change to the seed data or DTOs bumps an internal store-version marker specifically so a running dev server picks up the new shape on its next restart instead of silently continuing to serve a stale one.
The one exception is sandbox API keys issued through the landing page's waitlist flow, which persist to a local JSON file (gitignored) so a key survives a server restart — keys are not yet revocable server-side.
The write demo
POST /transfer/internal is a real write within the sandbox's own state: a successful call
mutates account balances and prepends a matching pair of transactions to the ledger, so a
follow-up read reflects it immediately. This is the sandbox side of
satchel_move_money — see that page for the tool-level gating
(SATCHEL_ALLOW_WRITES) that has to be enabled before this endpoint is ever called at all.
Known simplifications
The sandbox matches the real swagger on everything that matters for building against it:
auth flow, endpoint paths, DTO field names, enums (payment_state, payment_type,
payment_role, account_type), unsigned money, and the real transfer request/response
shapes. A short list of things are deliberately simplified for the MVP — documented here,
not hidden, and each one disappears the moment you flip to live:
create_timeis served as a plain ISO-8601 string, not the real swagger's more verboseLocalDateTimeobject.- Cross-currency transfers through
satchel_move_moneysettle at a flat 1:1 rate, with no FX conversion orexchange_idvalidation. - Card locator fields use network names (
mastercard/visa) rather than the real API'sprepaid/debitproduct-type enum. - Sandbox state is in-memory and resets on restart; waitlist-issued sandbox keys are not yet revocable server-side.
Flipping to live (see Overview) means the real gateway supplies the real thing for every item above — none of these are architectural limits, only sandbox-fidelity trade-offs for the MVP.