Changelog
The spec and the Python library version independently. This page tracks notable changes for each.
For the authoritative version field, see specs/bank2ai.json.
Specification
0.14.0, Draft
- Breaking,
get-transactionsverbositycollapsed to two levels. The middlestandardtier is removed andminimalbecomes the default.minimalcarriesid,accountId,description,amount,date,categoryId, andoriginalCurrency/originalAmount(populated only on FX entries) — the fields an LLM typically needs to answer everyday questions, with the merchant / counterparty name read offdescription.fullallows every optional ISO 20022 / Open Finance audit field on top. Servers MAY still omit any optional field even atfullwhen they don't have it. - Migration. Callers passing
verbosity="standard"or relying on the previousstandarddefault need to pick a tier: stay on the newminimaldefault for list rendering, or passverbosity="full"when the agent actually needs ISO 20022 / SEPA / card metadata. Theget-transaction(singular) tool is unchanged and remains the canonical audit / reconciliation entry point.
0.13.0, Draft
- Breaking,
Transaction.bookingDaterenamed toTransaction.date. The field carries the booking date whenstatusisBooked(formerlybookingDate; profile of ISO 20022 / Berlin GroupbookingDate) and the authorisation / point-of-sale date whenstatusisPending. Previously, pending entries had to either fabricate abookingDateor be dropped — neither is correct.dateis always populated, so clients can sort and chart by it without branching onstatus. The spec narrative documents the deliberate divergence from ISO 20022 naming. transactionDatesemantics tightened. Still optional, still the Open FinancetransactionDate(card swipe / authorisation date), but populated only onBookedcard entries where it differs from the postingdate. OnPendingentries the authorisation date lives ondateitself, sotransactionDateMUST be omitted there. Servers MUST also omit it when equal todate, as before.- Migration. Rename every wire-level
bookingDatetodate(request handlers, fixtures, sort keys, filters); rename every reference in handler code that constructsTransaction(...)frombookingDate=todate=. The drift test catches anything missed on the server side; clients readingtx['bookingDate']need a one-line rename.
0.12.0, Draft
- Transaction overhauled to cover account and card transactions in one shape, aligned with Open Finance / Berlin Group
cardTransactions. New optional fields:transactionDate(when the swipe / authorisation happened, distinct frombookingDateposting),maskedPan(which card was used),proprietaryBankTransactionCode(bank-proprietary code when the ISO 20022transactionCodeisn't exposed). New SEPA / audit fields:mandateId,creditorId,purposeCode(ISO 20022 ExternalPurposeCode),entryReference(Berlin Group stable booking-system reference),additionalInformation(free-form bank text not fitting the typed fields). - New
PostalAddresscomponent (profile of ISO 20022PostalAddress24):streetName,buildingNumber,postCode,townName,countrySubDivision,country,addressLine. Hung offParty.postalAddress, so for card transactions the Open FinancecardAcceptorAddress(townName,country,postCode,streetName) flows in onTransaction.counterparty.postalAddress. - Verbosity ladder rebalanced so the standard payload carries the fields an LLM typically needs to answer everyday questions —
transactionDate,maskedPan,merchantCategoryCode,originalCurrency/originalAmount, and the typedcounterparty(with merchant address) — without forcing afullfollow-up call. Deep ISO 20022 / SEPA metadata (valueDate,transactionCode,remittanceInformation,endToEndId,mandateId,creditorId,purposeCode,entryReference,additionalInformation,proprietaryBankTransactionCode,categoryRaw) stays atfull. - Breaking,
Transaction.counterpartyNameremoved. The merchant / counterparty display name lives onTransaction.counterparty.namefromstandardverbosity onwards. Atminimalverbosity the merchant name is read offTransaction.description, which for most bank entries already embeds it; servers that want to expose only the name keep usingdescriptionand omit the typed counterparty.
0.11.0, Draft
- Breaking, vocabulary alignment. The whole spec migrates to camelCase model field names, matching the PSD2 / ISO 20022 conventions the spec profiles.
Transaction.transaction_datebecomesbookingDate,category_idbecomescategoryId, thecurrency/amount_in_currencyFX pair becomesoriginalCurrency/originalAmount. TheTransactionsSummary*models migrate in the same pass (total_amount→totalAmount, etc.). Tool input parameter names stay snake_case (Python kwargs; bridged to wire byregister_tools). See Migrating from 0.10. - Breaking, Transaction shape.
idis now required (previously optional). New requiredaccountIdlinks each transaction to itsAccount. New optionalstatus(Booked|Pending|Information; defaults toBookedwhen omitted) profiles Berlin GroupbookingStatus. New optionalcounterpartyName. Seven new optional ISO 20022 metadata fields:valueDate,categoryRaw,counterparty(typedParty),transactionCode(ISO 20022BankTransactionCode),remittanceInformation,endToEndId,merchantCategoryCode. Servers populate what they have; the None-omitting serializer drops the rest. get-transactionsgains averbosityparameter (minimal|standard|full, defaultstandard) capping how many optional fields each Transaction may carry. Servers MAY omit any optional field even atfullif they don't have it.- New
get-transaction(singular) tool for the audit / reconciliation entry point: returns a single Transaction at full verbosity, including all ISO 20022 metadata the server can populate. - Canonical
Category.idtaxonomy published. Servers SHOULD use one of the 14 canonical ids (Income,Transfer,Groceries,DiningAndEntertainment,Transport,Housing,Utilities,Shopping,Health,Travel,Subscriptions,Fees,Cash,Other) when a transaction maps cleanly. Non-canonical ids remain valid for server-specific extensions. - Breaking, Recipient rebuilt on the typed
AccountIdentifierdiscriminated union (iban/bban/accountNumber/aliasvariants, profiled from ISO 20022AccountIdentification4Choice) and the typednationalIdsub-object. Dropped:accountNumber+accountNumberTypepair, requiredsocialSecurityNumber,bankInfo,paymentType,address,description, and the unusedRecipientInfobase class. Added:nickname,bic,defaultDescription,lastUsedAt. - Breaking,
create-recipientmigrated to typed inputs:account_identifier,national_id(typed object with opaquetypelabel),nickname,bic,default_description. Replaces the previousaccount_number+kennitalakwargs. - New polymorphic
prepare-transfertool for transfers on any supported rail (Railenum:domestic-IS,sepa,sepa-instant,swift, plus vendor extensions). Inputs take a typed creditorParty, instructed amount + currency, the rail, and optional rail-specific bits (local_instrument,requested_execution_date,remittance_information,end_to_end_id,description). Returns aPreparedTransferwithtransferIntentId,expiresAt, and slots for fees / FX / Confirmation of Payee / warnings / estimated settlement plus a validatedsummaryecho. - Breaking,
execute-transfertakes onlytransfer_intent_id(and an optionalidempotency_key). The intent's amount, creditor, debtor, and rail are immutable: any change requires a freshprepare-transfercall. NewExecutedTransfershape (transactionIdlinking back toTransaction.id,TransferExecutionStatusenum, optionalrejectionReason,executedAt). prepare-transfer-icelandicis removed. Useprepare-transferwithrail=domestic-ISinstead. The polymorphic tool covers the same flow with a single shape.- Safety contract documented in §5a. Idempotency keys (optional, ≤128 chars, per-
(tool, caller)scoping with ≥24h dedup window) accepted on every mutating tool. Intent expiry contract (5 min default) with structuredcode: "intent_expired"on execute against expired intent. Immutable amount / recipient / debtor / rail binding between prepare and execute. Structured Confirmation of Payee on rails that support payee verification. - Recoverable-error envelopes carry a structured
codefield. Canonical values:intent_not_found,intent_expiredonexecute-transfer;missing_creditor_identifier,insufficient_funds,invalid_account,invalid_recipienton the prepare paths. Unknown codes MUST be treated as opaque. Account.balancestyped array added for servers that expose multiple balance types (ClosingBooked,Expected,InterimAvailable,ForwardAvailable,NonInvoiced). Top-levelbalance/availableBalanceremain required as derived shortcuts; servers MUST keep them consistent with the correspondingbalancesentries when both are present.- Field omission rule promoted to the spec preamble and the "Profile of:" convention introduced in §3. Servers SHOULD omit optional fields whose values are null, empty, or equal to a documented default; clients MUST tolerate missing optional fields and unknown additional fields.
0.10.0, Draft
Accountoverhauled with the standard banking properties most issuers expose, with field names following Berlin Group PSD2accountDetailswhere they overlap. New optional fields: typed identifiersiban/bban/bic/maskedPan, plusownerName,product,status,usage,openedDate,balanceUpdatedAt. Credit accounts may also carrystatementBalance,minimumPaymentDue,paymentDueDate, andstatementClosingDateso an agent can answer "what do I owe and when?" without a second call.AccountTypeextended withLoanandOther. Debit and prepaid cards live underCurrent; their attached card is signalled byAccount.maskedPan.get-accountsgains optionalstatusandusagefilters;account_typeaccepts the new enum values.
0.9.0, Draft
- Breaking: categories are referenced by id, not name.
Transaction.category(string name) becomesTransaction.category_id;TransactionsSummaryGroup.categorybecomescategory_id. Thecategoriesinput onget-transactionsandget-transactions-summaryis renamed tocategory_idsand now takesCategory.idvalues fromget-categories.Category.nameis unchanged and remains the only place a category's localized name lives.
0.7.0, Draft
- Breaking: tool names overhauled for consistency.
transactions-summary→get-transactions-summary,recipients-by-name→get-recipients,transfer-money-icelandic→prepare-transfer-icelandic. Reads now useget-<plural>; writes stay verb-noun. Handler kwargs match:search_recipients→get_recipients,prepare_transfer→prepare_transfer_icelandic.
0.6.0, Draft
- Breaking:
transactions-summaryreworked its grouping.group_byacceptsnone,category,month, orboth(replacingcategory/group/month/merchant).TransactionsSummaryGroupdrops the opaquegroupfield in favour of explicit nullablecategoryandmonthfields, populated according to the requestedgroup_by.
0.5.0, Draft
- Breaking:
transactions-summaryis always scoped to a single direction. Thedirectioninput is now required and acceptsIncomeorExpenses; theBothoption has been removed. Callers that need both sides should call the tool twice.
0.4.0, Draft
- Breaking:
spending-summaryrenamed totransactions-summary. Inputs now includedirection(Income/Expenses/Both),account_ids,min_amount, andmax_amount, mirroring theget-transactionsfilter set. TheSpendingSummary*models are renamed toTransactionsSummary*.
0.3.0, Draft
- Breaking: dropped the
type(Income/Expenses/Savings) input fromget-transactions; income/expenses scoping now goes through the signedmin_amount/max_amountbounds.
0.2.0, Draft
- Added optional
min_amountandmax_amountinputs toget-transactions. Bounds are applied against the signed transaction amount (negative = expense, positive = income).
0.1.0, Draft
- Initial draft, derived from the Python reference implementation.
- Tools:
get-accounts,get-transactions,get-categories,spending-summary,recipients-by-name,create-recipient,transfer-money-icelandic,execute-transfer. - Four shared models:
Account,Transaction,Category,Recipient. - Authentication declared out of scope.
- A previously specified bank2ai-defined
authenticatetool was removed.
Python library (bank2ai)
0.6.1
- Repository housekeeping: the Meniga reference server moved out of this repo into a standalone
meniga-mcpproject. No changes to thebank2ailibrary surface, models, tools, or spec; the published wheel is functionally identical to0.6.0.
0.6.0
- Breaking: tracks spec 0.15.0–0.19.0.
Transaction.status(enumBooked/Pending/Information) is replaced byTransaction.isPending— now an optional boolean (servers SHOULD settrueonly for pending authorisations and omit the field on booked entries; clients MUST treat absence asfalse). Reduces wire bloat on the booked-row common case. - Breaking: the rarely-used ISO 20022 / Open Finance audit fields (
remittanceInformation,creditorReference,endToEndId,maskedPan,merchantCategoryCode,categoryRaw,transactionCode,proprietaryBankTransactionCode,mandateId,creditorId,purposeCode,entryReference,additionalInformation, …) collapse into a single optionalproperties: dict[str, str]bag onTransaction. Servers SHOULD use the known keys when populating; clients MUST tolerate any subset and unknown keys. - Breaking:
get-transactionsrenames thedescriptionfilter parameter tosearch_text, and auto-picks verbosity from the request when the caller doesn't pass one explicitly.minimalis redefined as "all fields exceptcounterpartyandproperties" so list-rendering payloads stay compact without dropping useful per-row metadata. Partygains optionallatitude,longitude, andbrandName. For card transactions these carry the merchant outlet's WGS-84 coordinates and the parent chain name (e.g.name="Starbucks Reserve Roastery",brandName="Starbucks"), so clients can group by chain and render the outlet location without a second lookup.Transaction.originalDescriptionadded — the raw, unparsed merchant / counterparty string from the rail, populated only when it differs from the cleaneddescriptionso clients don't have to dedupe.- Internal: the generated JSON Schema no longer leaks the
_Bank2aiModelbase class into the spec.
0.5.0
- Breaking: tracks spec 0.12.0–0.14.0.
Transaction.bookingDateis renamed toTransaction.dateand always populated (booking date whenBooked, authorisation date whenPending).Transaction.counterpartyNameis removed — read the merchant / counterparty name offTransaction.descriptionatminimalverbosity, orTransaction.counterparty.namefromfull. - Breaking:
get-transactionsverbosityis nowLiteral["minimal", "full"]withminimalas the default. The previousstandardtier is gone; callers relying on the standard payload should passverbosity="full"when they actually need ISO 20022 / SEPA / card metadata. - Transaction expanded to cover card transactions in one shape: new optional fields
transactionDate,maskedPan,proprietaryBankTransactionCode,mandateId,creditorId,purposeCode,entryReference,additionalInformation. NewPostalAddresscomponent hung offParty.postalAddress, so card-transactioncardAcceptorAddressflows in onTransaction.counterparty.postalAddress. register_toolsgains anoutput_schemas: Literal["inline", "discovery", "off"]keyword (default"inline"). In"discovery"mode the bank2ai tools omitoutputSchemafromtools/listand a companiondescribe-toolstool is registered so clients can fetch schemas on demand. In"off"mode schemas are suppressed without the companion tool.- Internal:
bank2ai.modelsandbank2ai.toolsare reorganized into domain submodules (accounts,transactions,recipients,transfers,identity). Public imports (from bank2ai import …andfrom bank2ai.models import …) are unchanged.
0.4.0
- Breaking: tracks spec 0.11.0. Tool handler kwargs change shape on the mutating tools:
create-recipienttakesaccount_identifierandnational_id(replacingaccount_numberandkennitala),prepare-transferis new with a typedcreditorParty,execute-transfertakes onlytransfer_intent_id(replacingwithdrawal_account_id,recipient_account_number,amount,description). Every mutating tool also accepts an optionalidempotency_key. - Breaking: Pydantic model field names migrate to camelCase across
Transaction,TransactionsSummaryGroup,TransactionsSummaryPeriod,TransferActionetc. Renamed models:TransferPreparedItem→PreparedTransfer,ExecuteTransferDetail→ExecutedTransfer. New envelopePrepareTransferResponsereplaces the previousTransferPreparedResponseand gains acodefield;CreateRecipientResponseandExecuteTransferResponselikewise gaincode. - Breaking: dropped the unused
RecipientInfobase class. - New public types:
AccountIdentifier(discriminated union) and its four variants (IbanIdentifier,BbanIdentifier,AccountNumberIdentifier,AliasIdentifier),AliasType,NationalId,NationalIdType,Party,TransactionCode,TransactionStatus,RemittanceInformation,Rail,TransferFee,TransferFx,ConfirmationOfPayee,ConfirmationOfPayeeStatus,TransferWarning,TransferWarningSeverity,TransferSummary,TransferExecutionStatus,Balance,BalanceType,GetTransactionResponse, and theCANONICAL_CATEGORY_IDSconstant. - New
register_toolshandler kwargs:get_transaction(singular) andprepare_transfer(polymorphic).
0.3.0
- Breaking: the wire-level tool name
transactionswas renamed toget-transactionsto align withget-accountsandget-categories. Theregister_toolshandler keyword (get_transactions=) is unchanged; only MCP clients calling the tool by name need to update.
0.2.0
- Breaking: the MCP tool surface moved from
bank2ai.mcptobank2ai.tools. Update imports accordingly. - Every
register_toolshandler keyword argument is now optional, tools whose handler is omitted are not registered, so a server can expose only the subset of the spec it implements. - Tool outputs follow the MCP convention of wrapping list results under an
itemskey (AccountList,CategoryList,RecipientList,TransactionList). get-transactionsgains pagination viacursorplus anext_cursoronTransactionList.get-transactionsaccepts anaccount_idslist (replacing the earlier singleaccount_id) so callers can filter across multiple accounts in one call.
0.1.0
- Initial release.
- Pydantic models for every bank2ai shape.
register_tools(app, ...)wiring the spec's tools onto a FastMCP app.
Versioning policy
bank2ai.json follows SemVer:
- Major, breaking changes (removing tools, renaming inputs/outputs, tightening required fields, changing semantic meaning).
- Minor, additive changes (new tools, new optional inputs, new optional output fields).
- Patch, description / metadata edits with no behavioural impact.
The Python package version moves independently of the spec version.