如果你曾嘗試使用歐洲銀行 API 建立應用程式,你很可能遇過我所碰到的同一道障礙:憑證需求。PSD2 規定你必須擁有 eIDAS QWAC 憑證才能直接與銀行通訊,而這些憑證既昂貴又耗時。

不過,有一條路徑可以完全跳過憑證。我將展示如何運作 — 並附上你可以立即執行的實際程式碼。

簡短版本

與其取得自己的 eIDAS 憑證並向每家銀行註冊為第三方提供者(Third Party Provider),不如使用已經擁有憑證的帳戶資訊服務提供者(Account Information Service Provider, AISP)。你的應用程式與其 API 通訊;他們再與銀行通訊。你永遠不會接觸到憑證。

權衡之處:你必須依賴中介機構。但對大多數獨立專案、小型企業及個人理財工具而言,這是完全合理的權衡。你可以透過乾淨的 REST API 取得銀行資料,而無需處理相互 TLS 及各家銀行的註冊程序。

你需要準備什麼

  • Python 3.8+(僅使用標準函式庫,基礎功能無需 pip 安裝)
  • 來自 AISP 提供者的 API 金鑰
  • 歐盟支援國家的銀行帳戶

我是 open-banking.io 的維護者,因此將以我們的 API 作為範例 — 但此模式適用於任何 PSD2 AISP(Enable Banking、Salt Edge、Tink 等)。請選擇符合你覆蓋範圍與預算的提供者。

步驟 1:取得 API 金鑰

註冊並取得 API 金鑰。將其儲存為環境變數:

export OBI_API_KEY="***"

Enter fullscreen mode Exit fullscreen mode

絕對不要硬編碼。如果不慎提交到 git,請立即輪替金鑰。

步驟 2:啟動銀行連線

你的使用者需要同意分享其資料。這會將他們重新導向至銀行的登入頁面:

import os
import json
import urllib.request

API_BASE = "https://api.open-banking.io/v1"
API_KEY=os.env...EY"]

def create_session(bank_id: str, return_url: str) -> dict:
    """Start a bank connection. Returns a consent URL for the user."""
    payload = json.dumps({
        "bank_id": bank_id,
        "return_url": return_url,
    }).encode()

    req = urllib.request.Request(
        f"{API_BASE}/sessions",
        data=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        method="POST",
    )

    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

# Example: connect to a Danish bank
result = create_session("nordea-dk", "https://yourapp.com/callback")
print(f"Send the user to: {result['consent_url']}")

Enter fullscreen mode Exit fullscreen mode

使用者造訪 consent_url,登入其銀行並核准。接著會被重新導向回你的 return_url,並附帶工作階段權杖。

步驟 3:取得帳戶與餘額

當工作階段獲得授權後:

def get_accounts(session_id: str) -> list:
    req = urllib.request.Request(
        f"{API_BASE}/sessions/{session_id}/accounts",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())["accounts"]

def get_balance(session_id: str, account_id: str) -> dict:
    req = urllib.request.Request(
        f"{API_BASE}/sessions/{session_id}/accounts/{account_id}/balance",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

accounts = get_accounts(result["session_id"])
for acct in accounts:
    bal = get_balance(result["session_id"], acct["id"])
    print(f"{acct['name']}: {bal['amount']} {bal['currency']}")

Enter fullscreen mode Exit fullscreen mode

步驟 4:取得交易紀錄

def get_transactions(session_id: str, account_id: str) -> list:
    req = urllib.request.Request(
        f"{API_BASE}/sessions/{session_id}/accounts/{account_id}/transactions",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())["transactions"]

for txn in get_transactions(result["session_id"], accounts[0]["id"]):
    print(f"{txn['date']} | {txn['amount']:>8} | {txn['description'][:50]}")

Enter fullscreen mode Exit fullscreen mode

就是這樣。你可以在不碰觸任何憑證的情況下讀取即時銀行資料。

值得注意的陷阱

同意期限。 PSD2 的同意通常會到期(一般為 90 天,視銀行而定)。你需要定期重新授權。請將此納入應用程式的流程 — 不要假設工作階段會永久有效。

已入帳與待處理。 交易分為兩種。 booked 交易已完成; pending 交易則為暫時性,可能變更或消失。如果你正在建立預算工具,請將 booked 作為事實來源,並小心去重 — 同一筆交易在結算期間可能同時出現在兩個清單中。

銀行覆蓋缺口。 沒有任何 AISP 涵蓋所有歐盟銀行。在投入之前,請檢查提供者的覆蓋清單,確認是否包含使用者實際需要的銀行。較小的區域性銀行通常是缺口所在。

速率限制。 PSD2 API 會針對每次同意執行存取頻率限制(交易通常為每日 4 次)。請積極快取。不要迴圈輪詢。

隱私模式。 有些提供者會在伺服器端儲存你的交易資料。其他提供者(例如我們)則使用用戶端持有的加密金鑰,因此提供者無法讀取使用者資料。如果你正在為注重 GDPR 的使用者開發,請確認你採用的是哪一種模式。

什麼時候應該取得憑證

如果你正在建立規模化的受監管金融產品 — 處理支付(PIS)、進行信用查核,或服務數千名使用者跨越多家銀行 — 請取得自己的 eIDAS 憑證並直接連接。中介機構會增加延遲、每次呼叫的成本,以及規模化時你不想要的依賴關係。

但對於個人專案、小型 SaaS 工具、內部儀表板,以及任何只需要讀取帳戶資料而無需企業負擔的應用程式而言:AISP 路徑是務實的選擇。


揭露:我是 John,open-banking.io 的維護者 — 這是一個無需憑證的 PSD2 歐盟銀行帳戶資訊服務。上述程式碼可與我們的 API 搭配使用,但此模式適用於任何合規的 AISP。如有問題,歡迎在留言區找我。