36 min read

The conference room on the sixth floor of Verdant Bank's Canary Wharf office smelled of fresh coffee and barely concealed excitement. Seven people from the product team sat around the table: two product managers, a UX lead, two engineers, a...

Chapter 28: RegTech APIs, Open Finance, and Interoperability

Learning Objectives

By the end of this chapter, you will be able to:

  • Explain what APIs are and why they matter for compliance professionals
  • Describe the PSD2 and UK Open Banking frameworks, including the roles of AISPs, PISPs, and ASPSPs
  • Explain the OAuth 2.0 authorization code flow and why it matters for consent management
  • Identify the compliance obligations of banks acting as API providers and fintechs acting as API consumers
  • Understand the FAPI security standard and why it exceeds standard OAuth 2.0 protections
  • Describe the emerging Open Finance landscape and its implications for compliance governance
  • Design a basic consent management and API audit trail architecture
  • Identify API governance obligations under GDPR, EBA guidelines, and Open Banking regulations

Opening Vignette: Maya's Questions

The conference room on the sixth floor of Verdant Bank's Canary Wharf office smelled of fresh coffee and barely concealed excitement. Seven people from the product team sat around the table: two product managers, a UX lead, two engineers, a partnerships director, and someone from marketing who had come because, she explained, this was "going to be a big launch." On the screen behind them was a slide deck titled "MoneyLens Partnership — Q2 Go-Live."

Maya Osei, Verdant's Chief Compliance Officer, sat at the far end of the table with a notepad and a pen she had not yet uncapped. She was thirty-two, had worked in financial services compliance since she was twenty-four, and had learned over those eight years that the most important thing she could do in a room like this was to listen carefully before she asked anything at all.

The partnerships director was explaining the arrangement. MoneyLens was a regulated fintech, authorized by the FCA as an Account Information Service Provider under PSD2. The app helped users aggregate financial data from multiple banks to give them a clear picture of their spending, saving, and debt. MoneyLens had approached Verdant about integrating directly into Verdant's Open Banking API. The customer journey was simple: a Verdant customer would visit MoneyLens, consent to sharing their Verdant account data, and MoneyLens would pull in their transactions. The product team loved it. MoneyLens had four hundred thousand active users. This was exposure. This was growth.

Maya waited until the deck reached its final slide — a Q2 launch timeline rendered in the corporate green that someone had clearly chosen to match Verdant's branding — before she uncapped her pen.

"How do we verify that MoneyLens has done its KYC?" she asked. "I mean on their customers — not on MoneyLens itself. When MoneyLens calls our API to retrieve a customer's transaction history, have they properly verified that person's identity? Do we know?"

The product manager and the partnerships director exchanged a glance that Maya recognized. It was the glance that meant: we assumed someone else was handling this.

"And the customer consent," she continued. "When a customer says yes to MoneyLens, is that consent stored in a format that satisfies our record-keeping obligations? Is it revocable? Does it expire? Can the customer see exactly what data they've consented to share?"

"There's a checkbox in the MoneyLens app," the UX lead offered.

"There's a checkbox," Maya said, not unkindly. "All right. And liability — if something goes wrong with the data, if a customer's transaction history is accessed without valid consent, or if MoneyLens has a breach, who is legally liable? Us? Them? Both?"

The room was quiet. Then the partnerships director said, carefully: "Those feel like compliance questions."

Maya nodded. "They are compliance questions. And I need answers to all of them before we go live." She looked at the timeline on the slide. "Q2 is achievable. But first we need to build this correctly."

She opened her notepad to a fresh page and wrote three words across the top: Verify. Consent. Liability.

This chapter is about those three words — and the technology, law, and governance frameworks that sit behind them.


Section 1: The API Economy in Financial Services

To understand why Open Banking matters for compliance, you first need to understand what an API is — and you do not need to be an engineer to grasp the essential concept.

An Application Programming Interface — API — is a defined contract between two software systems that specifies how they will communicate. Think of an API as the waiter in a restaurant. You (the customer, or in our context the requesting application) sit at a table and place an order. The waiter (the API) takes your order to the kitchen (the provider system), retrieves what you asked for, and brings it back. You never enter the kitchen. You never interact with the chef directly. The API defines the menu of what can be requested, the format in which requests must be made, and the format in which responses will be delivered.

In financial services, APIs have become the fundamental mechanism through which data moves between systems. When a payment is initiated, an API call travels from a merchant's system to a payment processor. When a compliance platform checks a name against a sanctions list, it sends an API request to a screening service and receives a response within milliseconds. When a bank regulatory reporting system submits data to a central bank, it will increasingly do so via an API rather than a file transfer.

For compliance professionals, this matters for a reason that goes beyond technology: APIs are data flows, and compliance depends entirely on knowing what data goes where, on what authority, and with what controls. Every API connection is a relationship — between systems, between organizations, between data subjects and data users. Governing those relationships is compliance work.

The shift from batch to real-time processing is one of the most significant consequences of the API economy for regulatory compliance. Traditional regulatory reporting was a batch process: a firm would compile a day's worth of transaction data and submit a report the following morning (T+1). The regulators received yesterday's picture of the world. API-based reporting enables real-time or near-real-time data sharing — the FCA's transaction reporting under MiFIR already requires submission of trade reports within the working day they occur, and the Bank of England is actively exploring API-based approaches to prudential reporting that would allow regulators to query firms' data directly rather than waiting for scheduled submissions.

The financial services API ecosystem has several distinct segments, each with its own regulatory implications. Open Banking APIs handle customer data sharing — a Verdant customer's transaction history moving to MoneyLens. RegTech integration APIs connect compliance systems to each other, for example, an AML monitoring platform pushing alert data to a case management system. Regulatory reporting APIs enable direct machine-to-machine submission of regulatory data to supervisory authorities. Payment APIs, as defined under PSD2, allow third-party providers to initiate payment transactions on a customer's behalf. Each of these raises different compliance questions, but they share a common compliance challenge: data governance in a connected, real-time world.


Section 2: Open Banking — The Regulatory Framework

Open Banking is not a technology. It is a regulatory mandate that happens to require technology to implement. The core idea is straightforward: a customer's financial data belongs to the customer, not to the institution that holds it, and customers should be able to share that data with third parties of their choosing. The regulation compels banks — which historically had no incentive to share their customer relationships with competitors — to provide standardized, secure access to account data.

PSD2: The European Foundation

The EU's Second Payment Services Directive (PSD2), which came into force in 2018, is the legal foundation of Open Banking across the European Economic Area. PSD2 established three new categories of payment service provider that are directly relevant to the data-sharing regime.

Account Information Service Providers (AISPs) are regulated entities authorized to access a customer's payment account data for information purposes only. MoneyLens, in the Verdant scenario, is operating as an AISP. It reads data; it does not initiate transactions. Payment Initiation Service Providers (PISPs) are authorized to initiate payment transactions from a customer's payment account on the customer's instruction — a PISP can trigger a bank transfer without the customer needing to log into their bank directly. Account Servicing Payment Service Providers (ASPSPs) are the banks and building societies that hold the payment accounts and must provide API access to authorized AISPs and PISPs.

For Maya and Verdant Bank, this framework defines their role as an ASPSP. They must provide a dedicated API interface. They must grant access to authorized TPPs. They must not discriminate between TPP access and direct customer access — if the API serves a customer's transaction history, it must serve the same data with the same speed regardless of whether the request comes from the customer's own session or from a TPP acting on the customer's behalf.

PSD2 was implemented through a suite of technical standards, the most important being the Regulatory Technical Standards on Strong Customer Authentication and Common and Secure Open Standards of Communication (RTS on SCA and CSC), produced by the European Banking Authority. These standards specify how customer authentication must work when a customer first grants consent to a TPP (strong customer authentication, meaning two factors from at least two of the categories: something you know, something you have, something you are), and what technical standards the API interface must meet. The RTS required banks to provide a dedicated API interface by September 2019 — screened-scraping workarounds that some fintechs had historically used to access bank data without consent became impermissible.

Under PSD2, a TPP must be registered with its home country's national competent authority — in Germany, BaFin; in the Netherlands, DNB; in France, the ACPR. Registered AISPs and PISPs receive a license number on the national register. They also receive an eIDAS (Electronic Identification, Authentication and Trust Services) certificate, which is a digitally-signed credential that carries their regulatory authorization. When a TPP calls an ASPSP's API, it presents this certificate, and the ASPSP must verify the certificate against the national register before granting access. This is the mechanism by which Verdant satisfies itself that MoneyLens is genuinely authorized — not by asking MoneyLens to self-certify, but by verifying the eIDAS certificate against the authoritative register.

The liability framework under PSD2 is explicit. If a customer suffers a loss because an unauthorized payment was initiated through a PISP, the PISP bears liability — it is the PISP's obligation to verify customer identity and obtain valid consent. The ASPSP is liable only if it wrongly denied access to a properly authorized TPP. This liability allocation was contentious during PSD2's development and remains an area where the drafting is not perfectly clean — the interface between ASPSP liability and PISP liability in edge cases has generated regulatory guidance and litigation across the EU — but the general principle is clear: the TPP takes responsibility for its customer relationship.

UK Open Banking

The United Kingdom's Open Banking regime developed in parallel to PSD2 through a different mechanism: a Competition and Markets Authority (CMA) investigation into retail banking concluded in 2017 that the nine largest UK banks (Barclays, HSBC, Lloyds, Nationwide, RBS/NatWest, Santander, Danske, Bank of Ireland, and Allied Irish) must implement a standardized Open Banking API framework. This produced the CMA Order and the creation of Open Banking Limited (OBL), the entity responsible for setting the UK Open Banking standards.

The UK standard adopted the Financial-grade API (FAPI) specification, a security profile that strengthens standard OAuth 2.0 (the authorization protocol discussed in Section 4) with additional protections appropriate for financial data. FAPI requires mutual TLS (mTLS), certificate-bound access tokens, and signed requests and responses — significantly higher security assurance than vanilla OAuth 2.0.

By 2025, the UK Open Banking ecosystem had grown to over seven million active users and more than two hundred regulated providers. The UK's journey post-Brexit required adaptation: without EU membership, UK TPPs lost their eIDAS certificates, and the OBIE (Open Banking Implementation Entity, as OBL was formerly known) developed an equivalent UK eIDAS-equivalent certificate infrastructure. UK-authorized TPPs now use OBIE-issued certificates in the same way EU TPPs use eIDAS certificates.

The UK government's Smart Data initiative, launched in earnest through the Data (Use and Access) Act, extends the Open Banking model beyond payment accounts to mortgages, pensions, energy, and telecommunications. A customer will eventually be able to share their energy usage history with a comparison service, or their pension data with a financial planner, with the same consent-based API mechanism they use to share their bank transactions with a budgeting app. For compliance professionals at banks like Verdant, this expansion means the consent management and API governance infrastructure they build for Open Banking today will need to scale across a much broader set of data types.

The Global Open Banking Landscape

Open Banking has spread globally, but with significant variation in approach that matters for compliance professionals working across jurisdictions.

In the United States, Open Banking has developed without a mandatory regulatory standard. The Consumer Financial Protection Bureau's Section 1033 rule — derived from the Dodd-Frank Act's consumer data portability provisions — was finalized in 2024 and requires covered data holders (banks, fintechs, card issuers) to make consumer financial data available to authorized third parties. The US framework relies heavily on industry standards (the FDX standard, discussed in Section 7) rather than mandating a specific technical implementation, which means interoperability is less uniform than in the UK or EU.

Australia's Consumer Data Right (CDR), implemented from 2020, is arguably the most comprehensive mandatory Open Banking framework in the world. It began with banking, expanded to energy, and is extending to telecommunications and beyond. The CDR framework includes strong accreditation requirements for data recipients (the equivalent of TPPs), detailed consent standards, and a data holder compliance regime with significant teeth.

Singapore's Monetary Authority has published its API Playbook — a comprehensive framework of voluntary standards for financial API development — and the MyInfo digital identity platform allows financial institutions to verify customer identity using government-held data, eliminating much of the KYC friction in onboarding. The Singapore approach demonstrates how open data infrastructure can reduce compliance cost as well as enable new products.

Brazil launched Open Finance in 2021, deliberate in naming it more broadly than "Open Banking" to signal that the framework covers not just payment accounts but the full financial product suite: insurance policies, investment portfolios, credit products, and foreign exchange. Brazil's Open Finance is administered by the BCB (Banco Central do Brasil) and has achieved rapid adoption, becoming one of the largest Open Finance ecosystems in the world by number of consented data-sharing relationships.


Section 3: Open Finance — The Expanding Vision

If Open Banking represents the first chapter of the data portability story in financial services, Open Finance is the sequel — broader in scope, more complex in governance, and more significant in its compliance implications.

Open Banking, as implemented under PSD2 and the CMA Order, covers payment accounts: current accounts, prepaid cards, and similar products. A customer can share their Verdant current account data with MoneyLens. But the same customer may also hold a Verdant mortgage, a Verdant ISA, and a Verdant pension — and under Open Banking, none of that data is in scope. Open Finance changes that.

The UK's Smart Data initiative, backed by the Data (Use and Access) Act 2024, creates a statutory framework for extending data portability across the entire financial product suite. Mortgages, savings products, pension pots, and investment portfolios will all become subject to consent-based data sharing through standardized APIs. A customer approaching retirement will be able to aggregate all their pension pots from multiple providers into a single view using a regulated third-party app — something that today requires manual data collection and significant customer effort.

At the EU level, the Financial Data Access (FiDA) framework, proposed by the European Commission in 2023 as part of its Retail Investment Strategy, extends Open Banking principles to investment portfolios, insurance products, and crypto-asset holdings. FiDA proposes a new category of "Financial Information Service Provider" analogous to the AISP under PSD2, and a new concept of "financial data sharing scheme" — industry-led bodies that set the technical standards for data sharing in each sector. The compliance implications of FiDA for asset managers, insurers, and crypto platforms are significant: firms that have not been subject to Open Banking obligations will face them for the first time.

For compliance professionals, Open Finance raises several distinct challenges that go beyond simply scaling up the Open Banking model. The data types are more sensitive and more complex: a customer's mortgage data reveals their address, their income assessment, their loan-to-value ratio, and their payment history — data that is far more revealing than a list of coffee shop transactions. Consent management must be correspondingly more granular, and data minimization obligations under GDPR apply with greater force. The counterparty ecosystem is wider: under Open Finance, a pension data consumer might be a financial adviser, an employer, a fintech, or a government service, each with different authorization requirements and compliance profiles. AML risk becomes more nuanced as payment initiation expands to cover a broader range of financial products — initiating an investment transaction on a customer's behalf is materially different from initiating a £50 payment.


Section 4: The Technical Architecture of Open Banking APIs

Maya Osei is not an engineer. She does not need to be. But she does need to understand the technical architecture well enough to ask the right governance questions — to know, when an engineer tells her that "OAuth 2.0 handles the consent," whether that statement is complete or whether it elides important compliance considerations.

OAuth 2.0: The Authorization Framework

OAuth 2.0 is the industry-standard authorization framework that underlies Open Banking consent flows. Its core purpose is elegantly simple: it allows a customer (the resource owner) to authorize a third party (the TPP) to access data held by a server (the ASPSP's API) without sharing their password. This is sometimes called "delegated authorization" — the customer delegates limited access to the TPP for a limited time.

The mechanism used in Open Banking is the Authorization Code Flow, which works as follows. A Verdant customer visits MoneyLens and indicates they want to connect their Verdant account. MoneyLens redirects the customer to Verdant's authorization server with a request that specifies exactly what permissions (in OAuth parlance, "scopes") it is requesting: read account details, read balances, read transactions from the past ninety days. The customer authenticates with Verdant using their normal credentials and completes strong customer authentication. Verdant's authorization server presents a clear consent screen: "MoneyLens is asking to read your account details, balance, and transactions. Do you authorize this?" The customer clicks yes. Verdant issues a short-lived authorization code to MoneyLens, which MoneyLens immediately exchanges at Verdant's token endpoint for an access token and a refresh token. MoneyLens then uses the access token to call Verdant's data APIs. The access token has a defined lifetime (typically sixty minutes under UK Open Banking standards) and a defined scope (only the permissions the customer consented to). When the access token expires, MoneyLens can use the refresh token to obtain a new access token — but only as long as the consent remains valid and unrevoked.

The critical compliance properties of this flow are worth noting explicitly. The customer's password never leaves Verdant. The authorization is scoped: MoneyLens cannot read data it did not ask for permission to read. The authorization is time-limited: the consent expires when the customer revokes it or when the specified expiry date is reached. Every step is auditable: Verdant's authorization server logs the authorization code issuance, the token exchange, and every subsequent API call made with the access token.

OpenID Connect (OIDC) adds an identity layer on top of OAuth 2.0. Standard OAuth 2.0 tells the API "this access token is valid for these scopes" but does not tell the TPP who the authenticated user is. OIDC adds an ID token — a signed JSON Web Token (JWT) that contains claims about the authenticated user, including a stable identifier. In Open Banking, OIDC allows MoneyLens to confirm that the person who authorized the consent is indeed a Verdant customer with the account they claim to hold.

PKCE (Proof Key for Code Exchange, pronounced "pixie") is a security extension that protects the authorization code flow against interception attacks. Without PKCE, if an attacker intercepted the authorization code during its brief transit between Verdant and MoneyLens, they could potentially exchange it for an access token themselves. PKCE closes this attack vector by requiring MoneyLens to generate a secret code verifier before the flow begins, derive a code challenge from it, and send the challenge with the initial authorization request. Only the party holding the original code verifier — MoneyLens — can successfully complete the token exchange.

FAPI: Financial-Grade API Security

The Financial-grade API (FAPI) security profile, developed by the OpenID Foundation and mandated by UK Open Banking and several other national implementations, represents a significant security upgrade from standard OAuth 2.0.

The key additional protections in FAPI 1.0 Advanced — the profile used in UK Open Banking — are mutual TLS (mTLS), Pushed Authorization Requests (PAR), JWT Secured Authorization Response Mode (JARM), and certificate-bound access tokens. Mutual TLS means that both sides of the connection authenticate with certificates: the bank authenticates to the TPP and the TPP authenticates to the bank. This prevents impersonation attacks where a malicious server pretends to be a legitimate bank or TPP. Pushed Authorization Requests move the authorization request from the customer's browser (where it could be manipulated) to a secure server-to-server channel. JARM ensures that the authorization response itself is signed by the authorization server, preventing tampering. Certificate-bound access tokens cryptographically bind an access token to the TPP's certificate so that a stolen token cannot be used by a different party.

FAPI 2.0, now in widespread deployment, strengthens these protections further and addresses edge cases that emerged from implementation experience with FAPI 1.0. For compliance professionals, the significance of FAPI is that it provides a higher assurance that the entity calling Verdant's API is genuinely the TPP it claims to be — a claim that underpins the entire liability framework.

In UK Open Banking, customer consent is not merely a checkbox in an app — it is a structured data object stored on the ASPSP's systems. The consent object records the TPP that requested consent, the permissions granted, the customer who granted them, the date and time of authorization, the expiry date, and the status (awaiting authorization, authorized, consumed, revoked, expired). When MoneyLens calls Verdant's API, it references the consent ID in its request, and Verdant validates that the consent is still active, has not been revoked, has not expired, and includes the permission being exercised before returning any data.

This consent object is a compliance artifact of considerable value. It is the answer to the question "what did the customer agree to and when?" — a question that arises in GDPR data subject access requests, in regulatory investigations, and in customer complaints. Maya's consent management platform is, in essence, a database of consent objects and the audit log of all API calls made against each consent.


Section 5: Compliance Obligations for API Participants

The Open Banking framework distributes compliance obligations clearly across its participants, but clarity in the regulation does not always translate to clarity in practice.

Banks as ASPSPs

Verdant Bank, as an ASPSP, carries a defined set of obligations. First, it must provide and maintain a dedicated API interface that meets the required technical standards — the UK Open Banking API specification, built on FAPI, with defined uptime and performance requirements. The EBA's RTS prohibits ASPSPs from using a fallback mechanism (screenscraping) as a substitute for a properly functioning API. Second, Verdant must not discriminate between API access and direct access: it cannot throttle API responses, introduce artificial latency, or impose conditions on TPP access that it does not impose on its own customer-facing channels. Third, and critically for Maya's purposes, Verdant must verify TPP authorization before granting access.

The TPP verification process works through eIDAS certificates (or OBIE certificates in the UK post-Brexit). When MoneyLens presents its certificate, Verdant's API gateway must check that the certificate was issued by an authorized Trust Service Provider, that it has not been revoked, and that the authorization number it contains appears on the FCA register as an active AISP or PISP. This check should happen in real time on every API call, or against a regularly-updated cached version of the register. The FCA provides a machine-readable version of its Financial Services Register precisely to enable this automated verification.

A point that Maya raised in her product team meeting deserves particular attention: the bank's AML responsibility in the Open Banking context. Verdant is not responsible for conducting KYC on MoneyLens's customers — that is MoneyLens's obligation as the AISP. What Verdant is responsible for is satisfying itself that MoneyLens is a regulated entity subject to AML obligations. Once Verdant has verified MoneyLens's FCA authorization, it can treat MoneyLens's API calls as coming from a regulated firm. But this does not mean Verdant is entirely without AML responsibility: if Verdant's AML monitoring detects unusual patterns in the data being accessed via Open Banking APIs — for example, a TPP accessing an unusually high volume of customer data outside normal parameters — Verdant should investigate. The API audit log, discussed below, is the mechanism for this monitoring.

Record-keeping is a fundamental ASPSP obligation. Every API call must be logged: the TPP identifier, the customer consent ID, the permission exercised, the timestamp, the data returned, and the HTTP response code. This log serves multiple purposes. It is the evidence for regulatory supervisory review. It is the input to the GDPR consent audit trail that a customer can request under their data subject access rights. It is the source of anomaly detection for potential unauthorized access. And it is the contractual evidence in any dispute with a TPP about what data was accessed and when.

Fintechs and TPPs as API Consumers

MoneyLens, as an AISP consuming Verdant's API, carries its own compliance obligations. Registration is the foundation: it must hold a current FCA authorization as an AISP (or be passporting an equivalent EEA authorization), maintain its OBIE certificate, and keep its registration details current. If MoneyLens's FCA authorization lapses or is withdrawn, Verdant is obligated to refuse access immediately.

Consent management is the core operational compliance obligation for AISPs. MoneyLens must obtain valid consent from each customer before calling any ASPSP's API. The consent must be informed (the customer must understand what they are consenting to), specific (the consent must specify what data and for what purpose), freely given (the customer must not be coerced), and revocable (the customer must be able to withdraw consent and MoneyLens must stop accessing data promptly). The Open Banking consent standards specify the minimum information that must be presented to customers at the consent authorization step.

Data use restrictions are strict: MoneyLens may only use customer data for the purpose for which consent was given. It cannot take a customer's transaction history, obtained for budgeting purposes, and use it for credit risk assessment or targeted advertising without separate consent. This is not only a GDPR obligation — it is an explicit condition of AISP authorization under PSD2 and the FCA's rules.

For PISPs, the AML obligations are more demanding than for AISPs, because PISPs are initiating payment transactions. A PISP is a payment service provider in its own right and must comply with the Money Laundering, Terrorist Financing and Transfer of Funds Regulations. This means customer due diligence, transaction monitoring, and suspicious activity reporting obligations apply to the PISP for the transactions it initiates. The fact that the PISP is using a bank's API to initiate the transaction does not transfer these obligations to the bank.

Under GDPR, the data relationship between a TPP and a bank raises a question that is not always answered consistently: is the TPP a data processor (processing data on behalf of the bank) or a data controller (processing data for its own purposes)? In most Open Banking contexts, the TPP is best characterized as an independent data controller — it is receiving customer data based on the customer's direct consent, for the TPP's own service purposes, and is exercising its own judgment about how to use that data. This characterization matters because it determines what data protection agreement is required. Where the TPP is a data controller, the bank is not in a data controller-processor relationship with the TPP, and no Data Processing Agreement is required — but the bank should still implement contract terms with the TPP covering the permitted uses of data, security standards, and breach notification obligations.


Section 6: Python Implementation — Open Banking API Simulation

The following Python implementation simulates the compliance management layer that sits behind an Open Banking API at an ASPSP like Verdant Bank. The code demonstrates TPP verification, consent lifecycle management, API access control, audit logging, and compliance reporting.

from __future__ import annotations
import hashlib
import json
import secrets
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from enum import Enum
from typing import Optional
import uuid


class ConsentStatus(Enum):
    AWAITING_AUTHORISATION = "AwaitingAuthorisation"
    AUTHORISED = "Authorised"
    CONSUMED = "Consumed"      # One-time consent (PIS) used
    REVOKED = "Revoked"
    EXPIRED = "Expired"


class PermissionType(Enum):
    ACCOUNTS_BASIC = "ReadAccountsBasic"
    ACCOUNTS_DETAIL = "ReadAccountsDetail"
    BALANCES = "ReadBalances"
    TRANSACTIONS = "ReadTransactions"
    TRANSACTIONS_CREDITS = "ReadTransactionsCredits"
    TRANSACTIONS_DEBITS = "ReadTransactionsDebits"


class TPPType(Enum):
    AISP = "Account Information Service Provider"
    PISP = "Payment Initiation Service Provider"
    CBPII = "Card-Based Payment Instrument Issuer"


@dataclass
class TPPRegistration:
    """Registered Third-Party Provider (must be authorized by a national regulator)."""
    tpp_id: str
    name: str
    tpp_type: list[TPPType]
    regulator: str          # e.g., "FCA", "BaFin", "DNB"
    authorization_number: str
    certificate_fingerprint: str  # eIDAS or OBIE certificate fingerprint
    registered_date: date
    country: str
    active: bool = True

    def is_valid_for_permission(self, permission: PermissionType) -> bool:
        if permission in (PermissionType.ACCOUNTS_BASIC, PermissionType.ACCOUNTS_DETAIL,
                         PermissionType.BALANCES, PermissionType.TRANSACTIONS,
                         PermissionType.TRANSACTIONS_CREDITS, PermissionType.TRANSACTIONS_DEBITS):
            return TPPType.AISP in self.tpp_type
        return False


@dataclass
class ConsentObject:
    """Open Banking consent — customer's authorization for a TPP to access their data."""
    consent_id: str
    tpp_id: str
    customer_id: str
    permissions: list[PermissionType]
    status: ConsentStatus
    creation_date_time: datetime
    expiration_date_time: datetime
    transaction_from_date_time: Optional[datetime] = None
    transaction_to_date_time: Optional[datetime] = None
    authorisation_date_time: Optional[datetime] = None
    revocation_date_time: Optional[datetime] = None

    @classmethod
    def create(cls, tpp_id: str, customer_id: str,
               permissions: list[PermissionType],
               expiry_days: int = 90) -> "ConsentObject":
        now = datetime.utcnow()
        return cls(
            consent_id=f"C-{uuid.uuid4().hex[:12].upper()}",
            tpp_id=tpp_id,
            customer_id=customer_id,
            permissions=permissions,
            status=ConsentStatus.AWAITING_AUTHORISATION,
            creation_date_time=now,
            expiration_date_time=now + timedelta(days=expiry_days),
        )

    def authorise(self) -> None:
        if self.status != ConsentStatus.AWAITING_AUTHORISATION:
            raise ValueError(f"Cannot authorise consent with status {self.status.value}")
        self.status = ConsentStatus.AUTHORISED
        self.authorisation_date_time = datetime.utcnow()

    def revoke(self) -> None:
        if self.status not in (ConsentStatus.AUTHORISED,):
            raise ValueError(f"Cannot revoke consent with status {self.status.value}")
        self.status = ConsentStatus.REVOKED
        self.revocation_date_time = datetime.utcnow()

    def is_active(self) -> bool:
        return (self.status == ConsentStatus.AUTHORISED and
                datetime.utcnow() < self.expiration_date_time)

    def has_permission(self, permission: PermissionType) -> bool:
        return self.is_active() and permission in self.permissions


@dataclass
class APICallLog:
    """Audit log entry for every API call made by a TPP."""
    log_id: str
    timestamp: datetime
    tpp_id: str
    customer_id: str
    consent_id: str
    endpoint: str          # e.g., "/accounts", "/accounts/{id}/transactions"
    permission_used: PermissionType
    response_code: int
    records_returned: int
    ip_address: str = ""

    @classmethod
    def record(cls, tpp_id: str, customer_id: str, consent_id: str,
               endpoint: str, permission: PermissionType,
               response_code: int, records_returned: int) -> "APICallLog":
        return cls(
            log_id=f"LOG-{uuid.uuid4().hex[:10].upper()}",
            timestamp=datetime.utcnow(),
            tpp_id=tpp_id,
            customer_id=customer_id,
            consent_id=consent_id,
            endpoint=endpoint,
            permission_used=permission,
            response_code=response_code,
            records_returned=records_returned,
        )


class OpenBankingComplianceManager:
    """
    Compliance management layer for Open Banking API operations.
    Handles TPP verification, consent management, and audit logging.
    """

    def __init__(self, bank_name: str):
        self.bank_name = bank_name
        self._tpp_registry: dict[str, TPPRegistration] = {}
        self._consents: dict[str, ConsentObject] = {}
        self._api_log: list[APICallLog] = []

    def register_tpp(self, tpp: TPPRegistration) -> None:
        self._tpp_registry[tpp.tpp_id] = tpp

    def verify_tpp(self, tpp_id: str, certificate_fingerprint: str) -> tuple[bool, str]:
        """Verify TPP is authorized and certificate matches registry."""
        tpp = self._tpp_registry.get(tpp_id)
        if not tpp:
            return False, "TPP not registered"
        if not tpp.active:
            return False, "TPP authorization revoked"
        if tpp.certificate_fingerprint != certificate_fingerprint:
            return False, "Certificate fingerprint mismatch"
        return True, "TPP verified"

    def create_consent(self, tpp_id: str, customer_id: str,
                       permissions: list[PermissionType]) -> ConsentObject:
        tpp = self._tpp_registry.get(tpp_id)
        if not tpp:
            raise ValueError(f"Unknown TPP: {tpp_id}")

        # Verify TPP has permission to request these permissions
        for perm in permissions:
            if not tpp.is_valid_for_permission(perm):
                raise ValueError(f"TPP {tpp_id} not authorized for permission {perm.value}")

        consent = ConsentObject.create(tpp_id, customer_id, permissions)
        self._consents[consent.consent_id] = consent
        return consent

    def process_api_request(self, tpp_id: str, consent_id: str,
                            endpoint: str, required_permission: PermissionType,
                            customer_id: str) -> tuple[bool, str, int]:
        """
        Validate an API request before serving data.
        Returns (allowed, reason, http_response_code).
        """
        # Check consent exists and belongs to this TPP
        consent = self._consents.get(consent_id)
        if not consent:
            self._log_call(tpp_id, customer_id, consent_id, endpoint,
                          required_permission, 401, 0)
            return False, "Consent not found", 401

        if consent.tpp_id != tpp_id:
            self._log_call(tpp_id, customer_id, consent_id, endpoint,
                          required_permission, 403, 0)
            return False, "Consent does not belong to this TPP", 403

        if consent.customer_id != customer_id:
            self._log_call(tpp_id, customer_id, consent_id, endpoint,
                          required_permission, 403, 0)
            return False, "Consent customer mismatch", 403

        if not consent.has_permission(required_permission):
            self._log_call(tpp_id, customer_id, consent_id, endpoint,
                          required_permission, 403, 0)
            status_reason = f"Consent status: {consent.status.value}"
            perm_reason = (
                "permission not in consent"
                if required_permission not in consent.permissions
                else status_reason
            )
            return False, f"Permission denied: {perm_reason}", 403

        # All checks passed
        self._log_call(tpp_id, customer_id, consent_id, endpoint,
                      required_permission, 200, 1)
        return True, "Authorized", 200

    def _log_call(self, tpp_id: str, customer_id: str, consent_id: str,
                  endpoint: str, permission: PermissionType,
                  response_code: int, records: int) -> None:
        log = APICallLog.record(tpp_id, customer_id, consent_id, endpoint,
                               permission, response_code, records)
        self._api_log.append(log)

    def consent_audit_trail(self, customer_id: str) -> list[dict]:
        """All consents and API access for a specific customer (GDPR subject access support)."""
        customer_consents = [c for c in self._consents.values() if c.customer_id == customer_id]
        result = []
        for consent in customer_consents:
            tpp = self._tpp_registry.get(consent.tpp_id)
            calls = [log for log in self._api_log if log.consent_id == consent.consent_id]
            last_access = max((l.timestamp for l in calls), default=None)
            result.append({
                "consent_id": consent.consent_id,
                "tpp_name": tpp.name if tpp else "Unknown",
                "tpp_type": [t.value for t in (tpp.tpp_type if tpp else [])],
                "permissions": [p.value for p in consent.permissions],
                "status": consent.status.value,
                "created": consent.creation_date_time.isoformat(),
                "authorised": (
                    consent.authorisation_date_time.isoformat()
                    if consent.authorisation_date_time else None
                ),
                "expires": consent.expiration_date_time.isoformat(),
                "api_calls": len(calls),
                "last_access": last_access.isoformat() if last_access else None,
            })
        return result

    def tpp_activity_report(self, tpp_id: str, from_date: date, to_date: date) -> dict:
        """API activity report for a specific TPP — useful for supervisory reporting."""
        tpp_logs = [
            l for l in self._api_log
            if l.tpp_id == tpp_id and from_date <= l.timestamp.date() <= to_date
        ]
        tpp = self._tpp_registry.get(tpp_id)
        return {
            "tpp_id": tpp_id,
            "tpp_name": tpp.name if tpp else "Unknown",
            "period": f"{from_date} to {to_date}",
            "total_api_calls": len(tpp_logs),
            "successful_calls": sum(1 for l in tpp_logs if l.response_code == 200),
            "denied_calls": sum(1 for l in tpp_logs if l.response_code in (401, 403)),
            "unique_customers": len({l.customer_id for l in tpp_logs}),
            "permissions_used": list({l.permission_used.value for l in tpp_logs}),
        }

Demonstration: Verdant Bank's Open Banking Compliance Layer

# --- Setup: Verdant Bank initializes its compliance manager ---
verdant = OpenBankingComplianceManager(bank_name="Verdant Bank UK")

# Register MoneyLens as a verified TPP
moneylens = TPPRegistration(
    tpp_id="TPP-ML-001",
    name="MoneyLens Ltd",
    tpp_type=[TPPType.AISP],
    regulator="FCA",
    authorization_number="FRN-987654",
    certificate_fingerprint="SHA256:ab3d7e91fc2b...",
    registered_date=date(2023, 6, 1),
    country="GB",
    active=True,
)
verdant.register_tpp(moneylens)

# --- TPP Verification: Verdant checks MoneyLens on each connection ---
valid, reason = verdant.verify_tpp("TPP-ML-001", "SHA256:ab3d7e91fc2b...")
print(f"TPP verification: {valid} — {reason}")
# Output: TPP verification: True — TPP verified

# --- Consent Creation: Customer authorizes MoneyLens ---
consent = verdant.create_consent(
    tpp_id="TPP-ML-001",
    customer_id="CUST-VB-44821",
    permissions=[
        PermissionType.ACCOUNTS_BASIC,
        PermissionType.BALANCES,
        PermissionType.TRANSACTIONS,
    ],
)
print(f"Consent created: {consent.consent_id}, status: {consent.status.value}")
# Output: Consent created: C-4F8A1B2C3D4E, status: AwaitingAuthorisation

# Customer completes SCA at Verdant and authorises the consent
consent.authorise()
print(f"Consent status after SCA: {consent.status.value}")
# Output: Consent status after SCA: Authorised

# --- API Request Processing: MoneyLens calls the transactions endpoint ---
allowed, reason, code = verdant.process_api_request(
    tpp_id="TPP-ML-001",
    consent_id=consent.consent_id,
    endpoint="/accounts/44821/transactions",
    required_permission=PermissionType.TRANSACTIONS,
    customer_id="CUST-VB-44821",
)
print(f"API request: {allowed} ({code}) — {reason}")
# Output: API request: True (200) — Authorized

# Attempt to access a permission not in the consent
allowed, reason, code = verdant.process_api_request(
    tpp_id="TPP-ML-001",
    consent_id=consent.consent_id,
    endpoint="/accounts/44821/standing-orders",
    required_permission=PermissionType.ACCOUNTS_DETAIL,
    customer_id="CUST-VB-44821",
)
print(f"Unauthorized scope attempt: {allowed} ({code}) — {reason}")
# Output: Unauthorized scope attempt: False (403) — Permission denied: permission not in consent

# Customer revokes consent via Verdant app
consent.revoke()

# Attempt to use revoked consent
allowed, reason, code = verdant.process_api_request(
    tpp_id="TPP-ML-001",
    consent_id=consent.consent_id,
    endpoint="/accounts/44821/transactions",
    required_permission=PermissionType.TRANSACTIONS,
    customer_id="CUST-VB-44821",
)
print(f"Post-revocation attempt: {allowed} ({code}) — {reason}")
# Output: Post-revocation attempt: False (403) — Permission denied: Consent status: Revoked

# --- GDPR Consent Audit Trail: Customer requests their data access history ---
audit = verdant.consent_audit_trail("CUST-VB-44821")
print(f"\nConsent audit trail for customer CUST-VB-44821:")
for entry in audit:
    print(f"  Consent {entry['consent_id']}: {entry['tpp_name']}")
    print(f"    Status: {entry['status']}")
    print(f"    Permissions: {entry['permissions']}")
    print(f"    API calls: {entry['api_calls']}")

# --- TPP Activity Report: Maya's supervisory monitoring ---
report = verdant.tpp_activity_report(
    tpp_id="TPP-ML-001",
    from_date=date.today(),
    to_date=date.today(),
)
print(f"\nTPP Activity Report: {report['tpp_name']}")
print(f"  Period: {report['period']}")
print(f"  Total calls: {report['total_api_calls']}")
print(f"  Successful: {report['successful_calls']}")
print(f"  Denied: {report['denied_calls']}")
print(f"  Unique customers accessed: {report['unique_customers']}")

The output demonstrates the full compliance lifecycle: TPP verification, consent creation and authorization, permission-scoped access control, revocation enforcement, and audit trail generation. Every denied request is logged — creating an audit trail not just of what was accessed but of what was attempted and blocked.


Section 7: The RegTech Integration API Ecosystem

Open Banking APIs are the most publicly visible part of the financial services API landscape, but they represent only a fraction of the API activity that compliance professionals must govern. The interconnection of compliance systems through APIs — RegTech integration — is equally significant and considerably less regulated.

Most large financial institutions now operate multiple compliance point-solutions: a KYC platform, an AML transaction monitoring system, a sanctions screening engine, a trade surveillance platform, a regulatory reporting system, a case management system, and so on. These systems were frequently procured at different times, from different vendors, with different data models and communication standards. Connecting them — making an alert from the AML system automatically create a case in the case management system, or having the sanctions screening result feed into the customer risk rating — requires APIs. The governance of those internal APIs is a compliance obligation in its own right.

Industry bodies have moved to address the lack of standardization in RegTech integration APIs. In the United States, the Financial Data Exchange (FDX) has developed a standard API for consumer financial data sharing, increasingly adopted as the technical implementation vehicle for the CFPB's Section 1033 consumer data rights rule. In Europe, the Berlin Group's NextGenPSD2 standard provides a common API specification for PSD2 compliance across EU jurisdictions, avoiding the fragmentation that would otherwise result from each country's national competent authority interpreting the EBA's technical standards differently. STET, originally developed by the French banking federation, provides an alternative PSD2 API standard used primarily in France and a small number of other markets.

The shift toward API-based regulatory reporting is perhaps the most transformative development for compliance professionals in the regulatory data space. The Bank of England's BEEDS (Bank of England Electronic Data Submission) portal has evolved toward API-based submission for certain data collections. The Bank of England has also run the Transaction Data Collection project, which explores machine-readable financial data collection through API query, allowing the regulator to request specific data on-demand rather than receiving predetermined periodic reports.

At the EU level, the EBA's Integrated Reporting Framework (IReF) represents the most ambitious attempt to harmonize regulatory reporting across jurisdictions through a common data model. IReF aims to replace the patchwork of national reporting requirements (each with different formats, submission schedules, and data definitions) with a single EU-wide data dictionary and reporting framework. When implemented, firms operating across multiple EU member states will report to a single harmonized standard, submitted through a common API infrastructure to the EBA's data collection systems. The compliance implications are significant: firms will need to maintain their data in a format consistent with the IReF data model at all times, rather than transforming data into reporting formats at submission time.

API-based sanctions screening represents a specific application that has gained traction with compliance teams managing the increasingly dynamic sanctions environment. Rather than downloading bulk sanctions lists from OFAC, HMT, and the EU Office of Foreign Assets Control and running locally-maintained screening, firms can integrate directly with API-based sanctions data providers that update their data in real time as new designations are added. The March 2022 Russia sanctions — where hundreds of designations were added in a matter of days — highlighted the lag risk of batch list download approaches and accelerated adoption of real-time API-based screening.

API governance introduces specific technical challenges that compliance teams must understand and manage. API versioning is one of the most operationally significant: when a regulator or industry body updates its API specification (for example, when the UK Open Banking standard moves from version 3.1 to 4.0), firms acting as both API providers and consumers must manage the migration without service interruption. Version mismatches — a TPP calling a v3.1 endpoint on a bank that has moved to v4.0 — produce errors that affect real customers. Idempotency — the property that calling an API multiple times with the same inputs produces the same result — is critical for payment initiation APIs where a network failure might lead to retry logic that unintentionally submits duplicate payments. Rate limiting — the API provider restricting how many calls a consumer can make per minute or hour — affects compliance systems that may need to screen large volumes of data rapidly; compliance teams must negotiate appropriate rate limits in their API consumer agreements.


Section 8: Compliance Governance for the API Ecosystem

The governance framework for the API ecosystem must address three distinct layers: the bank as API provider (ASPSP), the bank as API consumer (where it uses third-party compliance services), and the internal API connections between compliance systems.

The API Inventory

Every external API connection is simultaneously a data flow, a third-party relationship, and a potential point of failure. The foundation of API governance is a complete, current API inventory — a register of every API connection the firm operates, including the data types flowing through each connection, the counterparty, the legal basis for the data transfer, the authentication mechanism, and the data retention arrangements on both sides.

An API inventory that is not actively maintained becomes stale within months, as new integrations are added through project initiatives, vendor upgrades, and tactical fixes without the compliance team's involvement. The best-practice governance model treats any new API connection as a change that requires compliance review — assessed for data protection implications (does a DPIA need to be updated?), third-party risk (is the counterparty subject to adequate supervisory oversight?), and operational resilience (what is the fallback if the API is unavailable?).

Firms operating as ASPSPs must implement a consent management platform — a system that maintains the authoritative record of all customer consents for Open Banking data sharing. This is not a simple database: it must integrate with the bank's API gateway to enforce consent at the point of data access, with the bank's customer-facing app to allow customers to view and revoke their consents, with the bank's audit logging infrastructure to record every API call against its authorizing consent, and with the bank's GDPR data subject access request process to produce consent audit trails on demand.

The consent management platform must also handle the complexity of consent lifecycle events: consents that expire and are not renewed (resulting in access token invalidation); consents that are partially revoked (a customer removes one permission but keeps others); consents that are superseded (a customer re-authorizes the same TPP with different permissions); and consents where the underlying data object changes (the customer closes the account that was the subject of the consent).

API Security Architecture

The security architecture for Open Banking APIs must implement defence in depth. At the network layer, all API traffic must be encrypted using TLS 1.3 or higher — plaintext API communication is not permissible for financial data. At the authentication layer, mutual TLS and FAPI-compliant token management ensure that both parties in each API call are who they claim to be. At the authorization layer, the consent validation logic described in Section 5 ensures that every data request is authorized before data is returned. At the application layer, an API gateway provides rate limiting, anomaly detection, and centralized logging.

The question of who logs what is operationally important. Verdant's API gateway logs every inbound request, including the TPP identifier, the access token reference, the endpoint called, the HTTP response code, and the response time. This log is the primary evidence for any compliance investigation involving API access. It must be retained for the duration required by the relevant regulations: under the FCA's SYSC rules, records relevant to regulated activities must generally be retained for six years; under GDPR, records should be retained no longer than necessary for the purpose for which they were collected, which in the case of API access logs is likely the period needed to respond to regulatory investigations and customer complaints.

GDPR and the API Data Subject

From the perspective of a Verdant customer whose data is shared with MoneyLens via the Open Banking API, GDPR grants a suite of rights that the API infrastructure must be capable of supporting. The right of access (Article 15) means the customer can ask Verdant to tell them what data has been shared with whom and when — the consent audit trail from the OpenBankingComplianceManager directly supports this. The right to erasure (Article 17) applies to the customer's data held by MoneyLens, not to the bank's audit logs of API calls (which are maintained for legitimate legal and regulatory purposes). The right to data portability (Article 20) is, in a sense, the legal basis underlying Open Banking itself — the customer's right to receive their data in a machine-readable format and have it transmitted to another controller is implemented through the Open Banking API.

Incident response in the API context requires specific planning. If Verdant detects that a TPP is making API calls in a pattern inconsistent with the customer's consent — accessing transaction data at unusual hours, querying multiple customers in rapid succession, or persisting after consent revocation — the response framework must include: immediate technical controls (suspending the access token), legal and contractual steps (notifying the TPP and invoking contractual breach provisions), supervisory notification (informing the FCA if the unauthorized access constitutes a reportable incident under GDPR or the Payment Services Regulations), and customer notification (informing affected customers of the unauthorized access).


Closing Vignette: The System Working Correctly

Six months after the product team meeting in Canary Wharf, Maya Osei was back in the same conference room, but the atmosphere had changed. The MoneyLens integration had gone live in March. It was now the end of September, and the product team had prepared a partnership review dashboard.

The consent management platform had processed 14,200 customer consent authorizations. Customers could see, directly in the Verdant app, every third party they had authorized to access their data, what permissions they had granted, and exactly when their data had last been accessed. Three hundred and twelve customers had visited the consent management screen in the first month — most out of curiosity, some to make changes. Forty-one had revoked their MoneyLens consent. The revocations had propagated to the API gateway within ninety seconds of the customer's action.

Maya pulled up the TPP activity report for MoneyLens on her laptop. In the first month of live operation, MoneyLens had made 2,847 API calls against Verdant's endpoints. Of those, 2,844 had returned HTTP 200 — data successfully delivered. Three had returned HTTP 403.

She looked at the three denied requests. All three had the same reason code: consent expired. MoneyLens's refresh token logic had failed to renew the access token before it expired in one of their integration environments. The customer had not been affected — their data had simply not been transmitted on those three occasions — and MoneyLens's engineering team had identified and fixed the bug within four days.

"Three denials in 2,847 calls," said the product manager, reading the same screen. "That's a problem, right?"

"It's the system working correctly," Maya said. "MoneyLens didn't have valid authorization for those three calls. Our API correctly refused them. No customer data left without consent. That's not a bug — it's a feature." She paused. "But I will follow up with MoneyLens on the refresh token issue. We need to understand whether it affected any other bank integrations."

She closed her laptop and made a note on her pad: Consent management review: refresh token lifecycle — Q4 audit.

Then she wrote something she had been thinking about since March, when she had watched the first customer consent flow through the system in real time: Open Banking didn't add a compliance problem. It made the compliance problem visible. The data flows that used to happen informally are now audited, consented, and reversible. I'd rather have this than what came before.

It was a more optimistic conclusion than she had expected to reach when she first uncapped her pen in this room six months ago. The compliance questions she had asked — verify, consent, liability — still mattered. But she could now answer them, in writing, with evidence, at any point a regulator might ask.

That, she reflected, was what RegTech was supposed to do.


Chapter Summary

APIs are the plumbing of modern financial services — the mechanism through which data flows between institutions, between regulators and regulated firms, and between financial services providers and their customers' authorized third parties. Open Banking, mandated by PSD2 in the EU and the CMA Order in the UK, creates a rights-based framework in which customers control the flow of their financial data through consent-governed API access.

For compliance professionals, the API ecosystem presents both challenge and opportunity. The challenge is the governance complexity: verifying counterparty authorization, managing consent lifecycles, auditing data flows, allocating liability, and maintaining API security in a rapidly evolving technical environment. The opportunity is the auditability that API-based data sharing provides — data flows that were previously informal, opaque, and uncontrolled can, with proper infrastructure, be logged, governed, and reversed.

Open Finance — the extension of Open Banking principles to mortgages, pensions, insurance, and investments — will multiply both the challenge and the opportunity. The compliance professional who builds the governance foundations now will be well-positioned to extend them.


Next chapter: Chapter 29 — Distributed Ledger Technology and Compliance: Blockchain in Regulatory Context