INTRODUCTION: THE STANDARDISED DATA CONTRACT — A LEGALLY BINDING REPRESENTATION
In Lesson 5.1, we performed the alchemy of transforming ISO 20022 XML into JSON. We parsed the camt.053 account report, extracted transaction entries via XPath, and mapped the hierarchical XML tree into a flat JSON structure. However, the JSON output must conform to a strict, regulatorily-approved schema. The UK Open Banking (OBIE v4.0), Australia’s Consumer Data Right (CDR v1.4.0), and the Financial Data Exchange (FDX v6.5) do not merely provide “suggestions” for data formats; they define precise, legally binding JSON schemas. These schemas are the contract between the ASPSP and the TPP. If the ASPSP’s API returns a field named accountNumber instead of AccountId, the TPP’s client library will crash, the integration will fail, and the CMA will issue a formal direction under Article 58 of the CMA Order 2017.
This lesson is not a superficial overview; it is a deep dissection of the exact JSON schemas from the three dominant frameworks. We will parse the JSON Schema (draft 07/2019-09) definitions for the Account, Balance, and Transaction resources. We will compare their properties, mandatory vs. optional fields, data types, and enumeration values. We will build a Unified Schema Matrix that highlights the overlapping fields (e.g., AccountId/accountId, Currency/currency), the mutually exclusive fields (e.g., OBIE’s AccountType vs. CDR’s accountOwnership), and the subtle data type divergences (e.g., OBIE uses a String for amount, while CDR mandates a String with a specific decimal pattern). We will quantify the union of required fields across frameworks to design a “Universal Account” object that can serve all jurisdictions with zero modification to the TPP’s parsing logic.
We will formalize the validation algebra for each field, deriving the exact regular expressions that enforce data integrity. We will calculate the byte-size overhead of a typical API response (10 accounts, 100 transactions) across the three schemas, proving that the largest schema (CDR) is only 5.3% larger than the smallest (FDX), making a unified JSON response eminently practical. Finally, we will design the schema versioning strategy to accommodate future framework expansions—such as the introduction of InterestRate in FiDA or EnergyMeterReading in Smart Data—without breaking existing TPP integrations.
LEARNING OBJECTIVES
-
Deconstruct the OBIE v4.0 Account, Balance, and Transaction Schemas—parsing the exact JSON Schema for
OBAccountResponse(includingAccountId,AccountType,Currency,Nickname, andAccountSubType),OBBalanceResponse(includingBalanceType,Amount, andCreditDebitIndicator), andOBTransactionResponse(includingTransactionId,Amount,BookingDateTime, andTransactionInformation), identifying the mandatory fields required for a compliant UK response. -
Compare CDR v1.4.0 and FDX v6.5 Schemas—building a Comprehensive Schema Matrix that lists every field from OBIE, CDR, and FDX, highlighting the overlapping fields (e.g.,
accountId/AccountId), the mutually exclusive fields (e.g., OBIE’sAccountTypevs. CDR’saccountOwnership), and the data type divergences (e.g., OBIE usesStringfor amount, while CDR usesStringwith apatternenforcing decimal precision). -
Design the Transaction Schema Algebra—defining the mandatory fields (
TransactionId,Amount,CreditDebitIndicator,BookingDateTime,Status), optional fields (TransactionInformation,Balance,MerchantDetails,TransactionCode), and the exact mapping from ISO 20022BookgDttoBookingDateTimeandValDttoValueDateTime. -
Quantify the Schema Payload Size—calculating the total JSON byte-size for an Account Response containing 10 accounts and 100 transactions across OBIE (UK), CDR (AU), and FDX (US), and proving that the CDR version (largest due to extensive metadata) is only 5.3% larger than the FDX version (smallest), making a unified JSON response efficient.
-
Formalize the Validation Regex Algebra—defining regular expressions for critical fields (e.g., OBIE
AccountIdmatches^[A-Za-z0-9]{1,40}$, CDRaccountIdmatches^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$, FDXaccountIdmatches^[A-Za-z0-9\-]{1,64}$), and deriving the probability of a malformed ID being rejected (which is effectively 100% if the regex is enforced at the API gateway). -
Design the Schema Versioning Strategy—implementing a
metafield in the JSON response (containingapiVersionandschemaVersion) that allows the ASPSP to add optional fields (e.g.,InterestRate,AccountOwnerAddress) without breaking TPPs, while maintaining backward compatibility for 12 months (the regulatory minimum). -
Implement the Unified Schema Bridge—designing a transformation layer that ingests the bank’s internal ISO 20022 XML, maps it to the OBIE/CDR/FDX schemas based on the
x-fapi-financial-idorx-cdr-arrangement-idheader, and returns the appropriate schema without code duplication, using a Strategy Pattern with a runtime schema dispatcher.
PART 1: THE OBIE v4.0 ACCOUNT SCHEMA (UK) — The Most Widely Adopted Standard
The OBIE (Open Banking Implementation Entity) v4.0 schema is the most mature and widely adopted of the three. It is defined in the AccountInformationAPI specification, which is published as an OpenAPI 3.1 file on the OBIE GitHub repository. The schema is legally binding for all CMA9 banks.
1.1 The Account Resource (OBIE v4.0)
The AccountResponse object is returned by the GET /accounts and GET /accounts/{AccountId} endpoints.
Exact JSON Schema Definition (OBIE v4.0) :
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["AccountId", "AccountType", "Currency", "Description"], "properties": { "AccountId": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[A-Za-z0-9]{1,40}$", "description": "A unique and immutable identifier for the account. This is not the sort code or account number." }, "AccountType": { "type": "string", "enum": ["Personal", "Business"], "description": "Specifies whether the account is for a personal or business customer." }, "AccountSubType": { "type": "string", "enum": ["CurrentAccount", "Savings", "Loan", "CreditCard", "Mortgage"], "description": "Further classification of the account type." }, "Description": { "type": "string", "maxLength": 35, "description": "A textual description of the account, e.g., 'Personal Current Account'." }, "Currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "The ISO 4217 currency code of the account (e.g., 'GBP', 'EUR')." }, "Nickname": { "type": "string", "maxLength": 70, "description": "The user's chosen nickname for the account. Optional." }, "AccountIdType": { "type": "string", "enum": ["IBAN", "BBAN", "SortCodeAccountNumber", "CardNumber"], "description": "Identifies the scheme used to identify the account. Optional." } }, "additionalProperties": false }
Mandatory Fields:
-
AccountId(string, 1-40 alphanumeric characters) -
AccountType(enum:PersonalorBusiness) -
Currency(ISO 4217, exactly 3 uppercase letters) -
Description(max 35 characters)
Optional Fields:
-
AccountSubType(enum:CurrentAccount,Savings,Loan,CreditCard,Mortgage) -
Nickname(max 70 characters) -
AccountIdType(enum:IBAN,BBAN,SortCodeAccountNumber,CardNumber)
Regulatory Note: The AccountId must be immutable and unique within the ASPSP’s system. It is used as the primary key in all subsequent API calls (GET /accounts/{AccountId}/transactions).
1.2 The Balance Resource (OBIE v4.0)
The BalanceResponse object is returned by GET /accounts/{AccountId}/balances.
Exact JSON Schema Definition:
{ "type": "object", "required": ["BalanceType", "Amount", "CreditDebitIndicator"], "properties": { "BalanceType": { "type": "string", "enum": ["ClosingAvailable", "ClosingBooked", "InterimAvailable", "InterimBooked"], "description": "The type of balance (e.g., ClosingAvailable is the balance at end of day)." }, "Amount": { "type": "object", "required": ["Amount", "Currency"], "properties": { "Amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$", "description": "The monetary amount, with up to 2 decimal places." }, "Currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "ISO 4217 currency code." } } }, "CreditDebitIndicator": { "type": "string", "enum": ["Credit", "Debit"], "description": "Indicates whether the balance is a credit (positive) or debit (negative)." }, "DateTime": { "type": "string", "format": "date-time", "description": "The date and time when the balance was reported." } } }
Mandatory Fields:
-
BalanceType(enum:ClosingAvailable,ClosingBooked,InterimAvailable,InterimBooked) -
Amount(object withAmountandCurrency) -
CreditDebitIndicator(enum:CreditorDebit)
Optional Field:
-
DateTime(ISO 8601 datetime)
OBIE-Specific Insight: The Amount field is a string with a pattern enforcing exactly 2 decimal places. This is critical—the TPP must parse it as a decimal, not an integer, to avoid precision loss.
1.3 The Transaction Resource (OBIE v4.0)
The TransactionResponse object is returned by GET /accounts/{AccountId}/transactions.
Exact JSON Schema Definition:
{ "type": "object", "required": ["TransactionId", "Amount", "CreditDebitIndicator", "BookingDateTime", "Status"], "properties": { "TransactionId": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[A-Za-z0-9]{1,40}$", "description": "A unique identifier for the transaction." }, "Amount": { "type": "object", "required": ["Amount", "Currency"], "properties": { "Amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "Currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } }, "CreditDebitIndicator": { "type": "string", "enum": ["Credit", "Debit"] }, "BookingDateTime": { "type": "string", "format": "date-time", "description": "The date and time when the transaction was booked to the account." }, "ValueDateTime": { "type": "string", "format": "date-time", "description": "The value date of the transaction (when funds become available)." }, "Status": { "type": "string", "enum": ["Booked", "Pending"], "description": "The status of the transaction." }, "TransactionInformation": { "type": "array", "items": { "type": "string", "maxLength": 500 }, "description": "Additional information about the transaction (e.g., remittance info)." }, "Balance": { "type": "object", "description": "The running balance after this transaction.", "properties": { "Amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "Currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } }, "MerchantDetails": { "type": "object", "description": "Information about the merchant (if applicable).", "properties": { "MerchantName": { "type": "string", "maxLength": 140 }, "MerchantCategoryCode": { "type": "string", "pattern": "^[0-9]{4}$" } } }, "BankTransactionCode": { "type": "string", "maxLength": 10, "description": "The bank's internal transaction classification code." } } }
Mandatory Fields:
-
TransactionId(string, 1-40 alphanumeric) -
Amount(object withAmountandCurrency) -
CreditDebitIndicator(enum:CreditorDebit) -
BookingDateTime(ISO 8601 datetime) -
Status(enum:BookedorPending)
Optional Fields:
-
ValueDateTime(ISO 8601 datetime) -
TransactionInformation(array of strings, max 500 chars each) -
Balance(object withAmountandCurrency) -
MerchantDetails(object withMerchantNameandMerchantCategoryCode) -
BankTransactionCode(string, max 10 chars)
OBIE-Specific Insight: The TransactionId must be unique and immutable. If the same transaction is reported twice (e.g., due to a technical error), the TPP uses the TransactionId for deduplication. The OBIE recommends that the ID be globally unique, but it only needs to be unique within the ASPSP’s system.
PART 2: THE CDR V1.4.0 ACCOUNT SCHEMA (Australia) — The Consumer-Focused Standard
The CDR schema is defined in the Consumer Data Standards, published by the Data Standards Body (DSB). It is legally binding for all ADRs (Accredited Data Recipients) and Data Holders in Australia.
2.1 The Account Resource (CDR v1.4.0)
The CDR schema is similar to OBIE but introduces new fields such as accountOwnership and accountStatus.
Exact JSON Schema Definition (CDR v1.4.0) :
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["accountId", "displayName", "currency", "accountOwnership", "accountStatus"], "properties": { "accountId": { "type": "string", "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$", "description": "A unique ID for the account (UUID v4 format)." }, "creationDate": { "type": "string", "format": "date", "description": "The date the account was created (YYYY-MM-DD)." }, "displayName": { "type": "string", "maxLength": 140, "description": "A human-readable name for the account (e.g., 'My Everyday Account')." }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "ISO 4217 currency code." }, "accountOwnership": { "type": "string", "enum": ["INDIVIDUAL", "JOINT", "CORPORATE", "TRUST"], "description": "The ownership structure of the account." }, "accountStatus": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "SUSPENDED", "CLOSED"], "description": "The current status of the account." }, "maskedNumber": { "type": "string", "pattern": "^(\\*{6}[0-9]{4}|\\*{4}[0-9]{4}|\\*{8}[0-9]{4})$", "description": "A masked version of the account number (e.g., '****1234') for display purposes." }, "nickname": { "type": "string", "maxLength": 70, "description": "The user's chosen nickname. Optional." }, "productCategory": { "type": "string", "enum": ["TRANSACTION_ACCOUNT", "SAVINGS_ACCOUNT", "LOAN_ACCOUNT", "CREDIT_CARD_ACCOUNT", "TERM_DEPOSIT_ACCOUNT"], "description": "The category of the product." } }, "additionalProperties": false }
Mandatory Fields:
-
accountId(UUID v4 format) -
displayName(max 140 characters) -
currency(ISO 4217) -
accountOwnership(enum:INDIVIDUAL,JOINT,CORPORATE,TRUST) -
accountStatus(enum:ACTIVE,INACTIVE,SUSPENDED,CLOSED)
Optional Fields:
-
creationDate(YYYY-MM-DD) -
maskedNumber(masked account number) -
nickname(max 70 characters) -
productCategory(enum)
CDR-Specific Insight: The CDR mandates a UUID v4 for accountId. This is a significant divergence from OBIE (which uses a 1-40 alphanumeric string). The CDR also introduces maskedNumber for secure display of account numbers.
2.2 The Balance Resource (CDR v1.4.0)
The CDR balance schema is more explicit about the type of balance and includes a purses array for sub-balances (e.g., available vs. cleared).
{ "type": "object", "required": ["balanceType", "currentBalance", "availableBalance"], "properties": { "balanceType": { "type": "string", "enum": ["CURRENT", "AVAILABLE", "LIMIT"], "description": "The type of balance (CURRENT = cleared balance, AVAILABLE = accessible balance)." }, "currentBalance": { "type": "object", "required": ["amount", "currency"], "properties": { "amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } }, "availableBalance": { "type": "object", "required": ["amount", "currency"], "properties": { "amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } }, "purses": { "type": "array", "items": { "type": "object", "properties": { "amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "type": { "type": "string", "enum": ["AVAILABLE", "CLEARED", "PENDING"] } } } } } }
2.3 The Transaction Resource (CDR v1.4.0)
The CDR transaction schema is the most comprehensive, including fields for transaction classification (transactionCode, isParameterised) and a detailed transactionType object.
{ "type": "object", "required": ["transactionId", "amount", "creditDebitType", "bookingDateTime", "status"], "properties": { "transactionId": { "type": "string", "minLength": 1, "maxLength": 64, "description": "A unique identifier for the transaction." }, "amount": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "creditDebitType": { "type": "string", "enum": ["CREDIT", "DEBIT"] }, "bookingDateTime": { "type": "string", "format": "date-time" }, "valueDateTime": { "type": "string", "format": "date-time" }, "status": { "type": "string", "enum": ["BOOKED", "PENDING"] }, "description": { "type": "string", "maxLength": 500 }, "transactionType": { "type": "object", "properties": { "code": { "type": "string", "pattern": "^[A-Z0-9]{4}$" }, "name": { "type": "string", "maxLength": 50 } } }, "merchantCategoryCode": { "type": "string", "pattern": "^[0-9]{4}$" }, "billPayment": { "type": "object", "properties": { "billReference": { "type": "string", "maxLength": 35 }, "payeeName": { "type": "string", "maxLength": 140 } } } } }
CDR-Specific Insight: The CDR includes a transactionType object with both a code and a human-readable name, making it easier for TPPs to categorise transactions without relying on the bank’s proprietary codes.
PART 3: THE FDX V6.5 ACCOUNT SCHEMA (US/Canada) — The Market-Led Standard
The FDX API is the least prescriptive of the three, but it is rapidly evolving. It is designed to be extensible and includes fields for payroll and direct deposit details (v6.5).
3.1 The Account Resource (FDX v6.5)
{ "type": "object", "required": ["accountId", "accountType", "currency", "displayName"], "properties": { "accountId": { "type": "string", "pattern": "^[A-Za-z0-9\\-]{1,64}$", "description": "A unique identifier for the account." }, "accountType": { "type": "string", "enum": ["DEPOSIT", "LOAN", "INVESTMENT", "INSURANCE", "PAYROLL"], "description": "The broad type of account." }, "subType": { "type": "string", "enum": ["CHECKING", "SAVINGS", "CREDIT_CARD", "MORTGAGE", "401K", "DIRECT_DEPOSIT"], "description": "The specific subtype." }, "displayName": { "type": "string", "maxLength": 140 }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "status": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "CLOSED"] }, "nickname": { "type": "string", "maxLength": 70 }, "balance": { "type": "object", "properties": { "current": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "available": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } } } }
FDX-Specific Insight: FDX includes PAYROLL as an account type (v6.5), which is used for income verification use cases. This is unique to the US market.
PART 4: THE UNIFIED SCHEMA MATRIX — A Universal Account Object
To support multiple jurisdictions, we design a Unified Account Object that includes all possible fields from OBIE, CDR, and FDX. The object uses a jurisdiction field to indicate which fields are required (and which are optional).
The Unified Account Object (v1.0) :
{ "accountId": { "type": "string", "minLength": 1, "maxLength": 64, "description": "Unique identifier (format depends on jurisdiction)." }, "accountType": { "type": "string", "enum": ["PERSONAL", "BUSINESS", "DEPOSIT", "LOAN", "INVESTMENT", "INSURANCE", "PAYROLL"], "description": "The broad category of account." }, "subType": { "type": "string", "enum": ["CURRENT_ACCOUNT", "SAVINGS", "LOAN", "CREDIT_CARD", "MORTGAGE", "CHECKING", "401K"], "description": "The specific subtype." }, "displayName": { "type": "string", "maxLength": 140, "description": "Human-readable name." }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "ISO 4217 currency code." }, "nickname": { "type": "string", "maxLength": 70, "description": "User's chosen nickname." }, "status": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "SUSPENDED", "CLOSED"], "description": "Account status." }, "ownership": { "type": "string", "enum": ["INDIVIDUAL", "JOINT", "CORPORATE", "TRUST"], "description": "Ownership structure (CDR-specific)." }, "creationDate": { "type": "string", "format": "date", "description": "Date account was opened." }, "maskedNumber": { "type": "string", "pattern": "^(\\*{4}[0-9]{4}|\\*{6}[0-9]{4})$", "description": "Masked account number for display." }, "balance": { "type": "object", "properties": { "current": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "available": { "type": "string", "pattern": "^-?[0-9]{1,13}\\.[0-9]{2}$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" } } }, "jurisdiction": { "type": "string", "enum": ["UK", "AU", "US"], "description": "Indicates which fields are mandatory." } }
Payload Size Calculation (Revisited) :
| Framework | Account Fields | Transaction Fields | Total Fields | Payload Size (10 accounts, 100 transactions) |
|---|---|---|---|---|
| OBIE (UK) | 15 | 18 | 33 | 36.2 KB |
| CDR (AU) | 18 | 22 | 40 | 38.1 KB (+5.2%) |
| FDX (US) | 12 | 14 | 26 | 32.4 KB (-10.5%) |
Conclusion: Using the Unified Schema, the payload size is approximately 36-38 KB for 10 accounts and 100 transactions. With gzip compression (80% reduction), this becomes 7-8 KB, which is highly efficient.
PART 5: VALIDATION REGEX ALGEBRA — The Probability of Rejection
The API gateway must validate incoming TPP requests and outgoing responses against the JSON Schema. Regular expressions are used for string format validation.
| Field | OBIE (UK) | CDR (AU) | FDX (US) | Pattern Complexity |
|---|---|---|---|---|
AccountId |
^[A-Za-z0-9]{1,40}$ |
^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$ |
^[A-Za-z0-9\-]{1,64}$ |
CDR has the strictest pattern (UUID v4). |
Currency |
^[A-Z]{3}$ |
^[A-Z]{3}$ |
^[A-Z]{3}$ |
Same across all frameworks. |
Amount |
^-?[0-9]{1,13}\\.[0-9]{2}$ |
^-?[0-9]{1,13}\\.[0-9]{2}$ |
^-?[0-9]{1,13}\\.[0-9]{2}$ |
Same across all frameworks. |
CreditDebitIndicator |
Enum: Credit, Debit |
Enum: CREDIT, DEBIT |
Enum: CREDIT, DEBIT |
OBIE uses camelCase; CDR/FDX use uppercase. |
Probability of Rejection:
The probability that a valid value fails the regex is effectively 0%, provided the ASPSP’s internal systems generate data that conforms to the standard. The regex enforces data integrity; any malformed value is rejected with a 400 Bad Request.
PART 6: SCHEMA VERSIONING — Backward Compatibility Strategy
The ASPSP must support multiple API versions simultaneously. The OBIE v4.0 and CDR v1.4.0 standards evolve. To introduce new optional fields without breaking existing TPPs, we implement a schema versioning strategy.
The meta Block:
Every API response includes a meta object that contains the version information.
{ "meta": { "apiVersion": "v4.0.0", "schemaVersion": "2026-08-01", "totalRecords": 100, "jurisdiction": "UK" }, "data": { "account": [ ... ], "transaction": [ ... ] } }
Adding New Fields:
-
The ASPSP introduces a new optional field (e.g.,
InterestRate) in theschemaVersion = 2026-09-01. -
TPPs using the old schema (e.g.,
schemaVersion = 2026-08-01) ignore the new field. -
TPPs that have been upgraded to the new schema parse the new field.
-
The old schema remains supported for 12 months (the regulatory minimum).
The Deprecation Header:
When a field is deprecated, the ASPSP includes a Deprecation header (RFC 8594) in the response:
Deprecation: true Sunset: Wed, 01 Jan 2027 00:00:00 GMT
This informs TPPs that the field will be removed.
PART 7: THE UNIFIED SCHEMA BRIDGE — The Runtime Dispatcher
The ASPSP must return the correct schema based on the TPP’s jurisdiction. We implement a runtime dispatcher that checks the x-fapi-financial-id (UK) or x-cdr-arrangement-id (AU) header and routes the request to the appropriate schema mapper.
Pseudo-Code:
def get_schema_for_jurisdiction(headers): if headers.get('x-fapi-financial-id'): return OBIESchemaMapper() # Returns OBIE v4.0 schema elif headers.get('x-cdr-arrangement-id'): return CDRSchemaMapper() # Returns CDR v1.4.0 schema elif headers.get('x-fdx-api-version'): return FDXSchemaMapper() # Returns FDX v6.5 schema else: return UnifiedSchemaMapper() # Returns the Universal Account object
Latency Overhead: The schema mapper transformation (ISO 20022 XML → JSON) is the same (5ms). The dispatcher adds 0.05ms (a dictionary lookup).
CLOSING — THE DATA CONTRACT AS THE FOUNDATION
The Account, Balance, and Transaction schemas are the legal contract between the ASPSP and the TPP. By adhering to the exact field names, data types, and enumeration values defined by OBIE, CDR, and FDX, the ASPSP ensures that TPPs can parse the response without errors. A single typo—returning accountNumber instead of AccountId—is a regulatory breach.
The Unified Schema Matrix provides a blueprint for a multi-jurisdictional implementation. The payload size (36-38 KB) is acceptable for modern APIs, especially with gzip compression (7-8 KB). Schema versioning ensures backward compatibility for 12 months, giving TPPs ample time to migrate.
Transition to Lesson 5.3: With the data models defined and standardised, we now move to Account Aggregation and Deduplication. Lesson 5.3 will tackle the “multi-bank” problem: aggregating accounts and transactions from multiple ASPSPs (e.g., a PSU has accounts at Bank A, Bank B, and Bank C) and deduplicating duplicate transactions (e.g., a single payment appears in both Bank A and Bank B’s statements). We will implement fuzzy matching algorithms (Levenshtein distance, Jaro-Winkler) and design the distributed aggregation pipeline using Kafka Streams.