Skip to main content
Back to Blog
18 April 202514 min read

Banking API Standards: Open Banking and Beyond

BankingAPI DesignOpen BankingSecurity

Implementing banking APIs that comply with Open Banking standards. PSD2 requirements, security considerations, and consent management.


Banking API Standards: Open Banking and Beyond

Open Banking transformed how banks expose APIs. From my experience implementing these systems at Lloyds Banking Group, here's a comprehensive guide to building compliant, secure banking APIs.

Regulatory Landscape

Understanding the regulatory framework is essential before writing any code.

PSD2 and Open Banking

RegulationScopeKey Requirements
PSD2EU/UKAccess to accounts, SCA, TPP licensing
UK Open BankingUKStandardized APIs, CMA9 mandate
Berlin GroupEUNextGenPSD2 API specification
FDXUS/CanadaFinancial data exchange standard

Third-Party Provider Types

TPP Categories:
├── AISP (Account Information Service Provider)
│   ├── Read-only account access
│   ├── Transaction history
│   └── Balance information
├── PISP (Payment Initiation Service Provider)
│   ├── Initiate payments on behalf of user
│   ├── Requires explicit consent
│   └── SCA mandatory
└── CBPII (Card-Based Payment Instrument Issuer)
    ├── Confirmation of funds
    └── Card scheme integration

Security Architecture

Strong Customer Authentication (SCA)

SCA requires two of three authentication factors:

interface SCAFactors { knowledge: 'password' | 'pin' | 'security_question'; possession: 'mobile_device' | 'hardware_token' | 'smart_card'; inherence: 'fingerprint' | 'face_id' | 'voice_recognition'; } interface SCAExemptions { // Transactions that may be exempt from SCA lowValue: boolean; // Under £30 (limits apply) recurringPayment: boolean; // Same amount, same payee trustedBeneficiary: boolean; // Customer-whitelisted merchantInitiated: boolean; // MIT with prior consent corporatePayment: boolean; // B2B payments } function requiresSCA(transaction: Transaction): boolean { // Low value exemption with cumulative limits if (transaction.amount < 30 && transaction.cumulativeAmount < 100 && transaction.transactionCount < 5) { return false; } // Recurring payment to same payee if (transaction.isRecurring && transaction.payeeId === transaction.previousPayeeId && transaction.amount === transaction.previousAmount) { return false; } // Default: SCA required return true; }

OAuth 2.0 + FAPI Implementation

Financial-grade API (FAPI) extends OAuth for banking:

interface FAPIAuthRequest { response_type: 'code id_token'; client_id: string; redirect_uri: string; scope: 'openid accounts' | 'openid payments'; state: string; nonce: string; code_challenge: string; // PKCE required code_challenge_method: 'S256'; request: string; // Signed JWT with request details } // Creating a signed request object (JAR) function createRequestObject(params: AuthParams): string { const payload = { iss: params.clientId, aud: params.authorizationServerUrl, response_type: 'code id_token', client_id: params.clientId, redirect_uri: params.redirectUri, scope: params.scope, state: generateSecureRandom(), nonce: generateSecureRandom(), exp: Math.floor(Date.now() / 1000) + 300, iat: Math.floor(Date.now() / 1000), claims: { id_token: { openbanking_intent_id: { value: params.consentId, essential: true } } } }; return signJWT(payload, privateKey, 'PS256'); }

Certificate-Based Authentication (MTLS)

import https from 'https'; import fs from 'fs'; interface BankingClientConfig { certificatePath: string; privateKeyPath: string; caCertPath: string; baseUrl: string; } function createBankingClient(config: BankingClientConfig) { const agent = new https.Agent({ cert: fs.readFileSync(config.certificatePath), key: fs.readFileSync(config.privateKeyPath), ca: fs.readFileSync(config.caCertPath), rejectUnauthorized: true }); return { async request<T>(endpoint: string, options: RequestInit): Promise<T> { const response = await fetch(\

Share this article