Skip to content

Repository files navigation

fints-lib

npmCI

A client library for communicating with FinTS servers.

Note: This is a fork and continuation of the excellent work by Frederick Gnodtke (Prior99). We are grateful for the solid foundation and comprehensive implementation provided by the original project.


⚠️ FinTS 4.1 / FinTS 4.0 – Experimental Support

Experimental — use with caution in production

This library includes an implementation of the FinTS 4.1 XML-based protocol (FinTS4Client). This support is experimental and subject to the following limitations:

  • FinTS 4.0 is not a widely deployed version. Most German retail banks still use FinTS 3.0. FinTS 4.1 support is intended for banks and aggregators that have explicitly adopted the XML-based successor format.
  • Protocol negotiation is best-effort. The implementation will automatically try fallback versions (4.1 → 4.0 → 3.0) when a bank rejects the preferred version, but real-world servers may behave unpredictably.
  • TAN flows are partially supported. The interactive two-step TAN flow (PIN+TAN, chipTAN, pushTAN) is implemented via a tanCallback, but edge cases — such as HHD/Flickercode visualisation, multi-challenge flows, or bank-specific challenge formats — may require additional handling.
  • BPD/UPD parsing is partially generic. The FinTS 4.1 XML structure leaves room for bank-specific element naming. The parser applies fallback strategies, but untested banks may require further mapping.
  • No write operations.FinTS4Client is currently read-only (accounts, balances, statements). Credit transfers and direct debits are only available via the stable PinTanClient (FinTS 3.0).
  • TLS certificate requirements. Banks with private CA certificates or strict TLS policies require a custom Node.js https.Agent, which must be passed via fetchOptions. See Custom TLS / HTTPS configuration below.

For production use with the widest bank compatibility, use the PinTanClient (FinTS 3.0) described in the Quick Start section.


🎯 Improvements in this Fork

  • Updated Dependencies: All dependencies updated to their latest stable versions
  • Modern TypeScript: TypeScript 5.x with improved type safety
  • GitHub Actions: Automated CI/CD pipeline
  • FinTS 4.1 (Experimental): XML-based protocol with interactive TAN, version negotiation, and improved BPD parsing
  • Active Maintenance: Regular updates and dependency maintenance
  • Published as fints-lib and fints-lib-cli on npm

📦 Installation

npm install fints-lib
# or
yarn add fints-lib

For the CLI tool:

npm install -g fints-lib-cli
# or
yarn global add fints-lib-cli

Development Setup

# Install dependencies
yarn install
# Build all packages
yarn build
# Run tests
yarn test# Run linting
yarn lint

🚀 Quick Start

FinTS 3.0 (Stable — recommended for production)

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({url: "https://banking.example.com/fints",// Your bank's FinTS URLname: "username",pin: "12345",blz: "12345678",});constaccounts=awaitclient.accounts();console.log(accounts);

FinTS 4.1 (Experimental — XML-based)

import{FinTS4Client}from"fints-lib";// ⚠️ Experimental: most banks still use FinTS 3.0constclient=newFinTS4Client({url: "https://banking.example.com/fints41",name: "username",pin: "12345",blz: "12345678",});constaccounts=awaitclient.accounts();constbalance=awaitclient.balance(accounts[0]);conststmts=awaitclient.camtStatements(accounts[0]);

CLI Quick Start

npm install -g fints-lib-cli
fints-lib list-accounts \
--url https://banking.example.com/fints \
-n username -p 12345 -b 12345678

📖 Common Use Cases

1. Check Account Balance

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});constaccounts=awaitclient.accounts();constbalance=awaitclient.balance(accounts[0]);console.log(`Balance: ${balance.value.value}${balance.value.currency}`);

2. Fetch Recent Transactions

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({/* ... */});constaccounts=awaitclient.accounts();constendDate=newDate();conststartDate=newDate(endDate.getTime()-30*24*60*60*1000);conststatements=awaitclient.statements(accounts[0],startDate,endDate);statements.forEach((statement)=>{statement.transactions.forEach((tx)=>{console.log(` ${tx.amount}${tx.currency}${tx.purpose||"N/A"}`);});});

3. SEPA Credit Transfer (Send Money)

import{PinTanClient,TanRequiredError}from"fints-lib";constclient=newPinTanClient({/* ... */});constaccounts=awaitclient.accounts();try{awaitclient.creditTransfer(accounts[0],{debtorName: "John Doe",creditor: {name: "Recipient",iban: "DE44500105175407324931",bic: "INGDDEFFXXX"},amount: 50.0,remittanceInformation: "Invoice #12345",});}catch(error){if(errorinstanceofTanRequiredError){consttan=awaitpromptUser(error.challengeText);// your UIawaitclient.completeCreditTransfer(error.dialog,error.transactionReference,tan,error.creditTransferSubmission);}}

4. FinTS 4.1 — Interactive TAN (Experimental)

⚠️ Experimental. Requires a bank that supports FinTS 4.1 XML.

import{FinTS4Client}from"fints-lib";import*asreadlinefrom"readline";asyncfunctionpromptTan(challenge: {challengeText?: string;transactionReference: string}): Promise<string>{constrl=readline.createInterface({input: process.stdin,output: process.stdout});returnnewPromise((resolve)=>{rl.question(`TAN challenge: ${challenge.challengeText??"(no text)"}\nEnter TAN: `,(tan)=>{rl.close();resolve(tan.trim());});});}constclient=newFinTS4Client({url: "https://banking.example.com/fints41",name: "username",pin: "12345",blz: "12345678",tanCallback: promptTan,// called automatically when the bank issues a challenge});constaccounts=awaitclient.accounts();// If the bank requires a TAN during the request, `promptTan` is invoked automatically.conststatements=awaitclient.camtStatements(accounts[0]);

🔐 Custom TLS / HTTPS Configuration (Node.js only)

Some banks use certificates signed by a private CA, or require specific TLS settings. Use createTlsAgent() to create a custom https.Agent and pass it via fetchOptions:

import{FinTS4Client,createTlsAgent}from"fints-lib";importfsfrom"fs";// Use a custom CA certificate (e.g. a bank-specific private CA)constagent=createTlsAgent({ca: fs.readFileSync("/path/to/bank-ca.pem","utf8"),});constclient=newFinTS4Client({url: "https://banking.example.com/fints41",name: "username",pin: "12345",blz: "12345678",fetchOptions: { agent },});

Security note: Never set rejectUnauthorized: false in production. This disables certificate verification entirely and exposes you to man-in-the-middle attacks.

// ✅ Development / testing only:constdevAgent=createTlsAgent({rejectUnauthorized: false});// ❌ Never in production:// const prodAgent = createTlsAgent({ rejectUnauthorized: false });

Note:createTlsAgent() and fetchOptions.agent are currently only supported by FinTS4Client (FinTS 4.1). The FinTS 3.0 PinTanClient / HttpConnection does not expose a custom-agent option; if you need custom TLS for a FinTS 3.0 endpoint, use the NegotiatingClient with preferredVersion: "4.1" or configure TLS at the Node.js process level (e.g. NODE_EXTRA_CA_CERTS).

🔄 HBCI Version Negotiation (FinTS 4.1)

FinTS4Client automatically negotiates the HBCI version with the server:

  1. It starts with your preferredHbciVersion (default: "4.1").
  2. If the server returns error 9010 (version not supported), it retries with "4.0", then "3.0".
  3. After the sync phase, the client adopts the highest version both sides support.
constclient=newFinTS4Client({// ...preferredHbciVersion: "4.1",// start with 4.1, fall back automatically});

Packages

🔒 Security

  • Never log credentials. The library masks PINs and TANs in debug output, but never log the raw config object.
  • Store credentials securely. Use environment variables or a secrets manager.
  • Use HTTPS only. Always use HTTPS URLs for FinTS endpoints.
  • Debug mode. Be cautious with debug: true in production — it logs full request/response XML.

Reporting Security Issues

Report security vulnerabilities privately via GitHub's Security tab instead of opening a public issue.

💡 Tips and Troubleshooting

Finding Your Bank's FinTS URL

Common Issues

Authentication Errors:

  • Verify username, PIN, and BLZ.
  • Some banks require enabling FinTS/HBCI access in online banking settings.
  • Check if your bank requires product registration.

TAN Requirements:

  • Use tanCallback (FinTS 4.1) or TanRequiredError catch (FinTS 3.0) to handle TAN challenges.

Timeout Issues:

constclient=newPinTanClient({timeout: 60000,maxRetries: 5});

FinTS 4.1 not working with my bank:

  • Most German retail banks use FinTS 3.0 — switch to PinTanClient.
  • Check the bank's FinTS URL: some banks have separate endpoints for v3 and v4.

Mentions

Resources

Contributing

Contributions in the form of well-documented issues or pull requests are welcome.

Contributors

  • Frederick Gnodtke (Original author)
  • Lars Decker (Fork maintainer)

This fork includes several enhancements over the original project:

  • Updated Dependencies: All dependencies updated to their latest stable versions for better security and performance
  • Modern TypeScript: Updated to TypeScript 5.x with improved type safety
  • GitHub Actions: Automated CI/CD pipeline for testing and npm publication
  • Active Maintenance: Regular updates and dependency maintenance
  • Published as fints-lib and fints-lib-cli on npm for easier installation

📦 Installation

For end users installing the library:

npm install fints-lib
# or
yarn add fints-lib

For the CLI tool:

npm install -g fints-lib-cli
# or
yarn global add fints-lib-cli

Development Setup

This project uses Yarn as the package manager. To set up the development environment:

# Install dependencies
yarn install
# Build all packages
yarn build
# Run tests
yarn test# Run linting
yarn lint

🚀 Quick Start

Minimal Configuration

import{PinTanClient}from"fints-lib";// Create a client with minimal required configurationconstclient=newPinTanClient({url: "https://banking.example.com/fints",// Your bank's FinTS URLname: "username",// Your banking usernamepin: "12345",// Your banking PINblz: "12345678",// Bank code (BLZ/Bankleitzahl)});// List all accountsconstaccounts=awaitclient.accounts();console.log(accounts);

CLI Quick Start

# Install globally
npm install -g fints-lib-cli
# List your accounts
fints-lib list-accounts \
--url https://banking.example.com/fints \
-n username \
-p 12345 \
-b 12345678

📖 Common Use Cases

1. Check Account Balance

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});// Get all accountsconstaccounts=awaitclient.accounts();// Check balance for first accountconstbalance=awaitclient.balance(accounts[0]);console.log(`Account: ${accounts[0].iban}`);console.log(`Balance: ${balance.value.value}${balance.value.currency}`);

CLI Example

fints-lib get-balance \
--url https://banking.example.com/fints \
-n username -p 12345 -b 12345678 \
-i DE89370400440532013000

2. Fetch Recent Transactions

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});constaccounts=awaitclient.accounts();// Fetch last 30 days of transactionsconstendDate=newDate();conststartDate=newDate(endDate.getTime()-30*24*60*60*1000);conststatements=awaitclient.statements(accounts[0],startDate,endDate);// Process transactionsstatements.forEach((statement)=>{console.log(`Date: ${statement.date}`);statement.transactions.forEach((transaction)=>{console.log(` ${transaction.descriptionStructured?.bookingText||"Transaction"}`);console.log(` Amount: ${transaction.amount}${transaction.currency}`);console.log(` Purpose: ${transaction.purpose||"N/A"}`);});});

CLI Example

# Fetch transactions for a date range
fints-lib fetch-transactions \
--url https://banking.example.com/fints \
-n username -p 12345 -b 12345678 \
-i DE89370400440532013000 \
-s 2024-01-01 -e 2024-12-31 \
--json > transactions.json

3. SEPA Credit Transfer (Send Money)

import{PinTanClient,TanRequiredError}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});constaccounts=awaitclient.accounts();constmyAccount=accounts[0];// Prepare transferconsttransfer={debtorName: "John Doe",creditor: {name: "Recipient Name",iban: "DE44500105175407324931",bic: "INGDDEFFXXX",// Optional for transfers within SEPA},amount: 50.0,remittanceInformation: "Payment for invoice #12345",};try{// Initiate transferconstresult=awaitclient.creditTransfer(myAccount,transfer);console.log("Transfer successful:",result.taskId);}catch(error){if(errorinstanceofTanRequiredError){// TAN is required - get TAN from userconsttan="123456";// Get from user input or TAN appconstresult=awaitclient.completeCreditTransfer(error.dialog,error.transactionReference,tan,error.creditTransferSubmission,);console.log("Transfer completed:",result.taskId);}else{throwerror;}}

CLI Example

# Transfer money (will prompt for TAN if required)
fints-lib submit-credit-transfer \
--url https://banking.example.com/fints \
-n username -p 12345 -b 12345678 \
--account-iban DE89370400440532013000 \
--debtor-name "John Doe" \
--creditor-name "Recipient Name" \
--creditor-iban DE44500105175407324931 \
--amount 50.00 \
--remittance "Payment for invoice #12345"

4. SEPA Direct Debit (Collect Money)

import{PinTanClient,TanRequiredError}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});constaccounts=awaitclient.accounts();constmyAccount=accounts[0];// Prepare direct debitconstdebit={creditorName: "My Company GmbH",creditorId: "DE98ZZZ09999999999",// Your SEPA creditor IDdebtor: {name: "Customer Name",iban: "DE02120300000000202051",},amount: 99.99,mandateId: "MANDATE-2024-001",mandateSignatureDate: newDate("2024-01-15"),requestedCollectionDate: newDate("2024-12-15"),remittanceInformation: "Monthly subscription fee",};try{constresult=awaitclient.directDebit(myAccount,debit);console.log("Direct debit submitted:",result.taskId);}catch(error){if(errorinstanceofTanRequiredError){consttan="123456";// Get from userconstresult=awaitclient.completeDirectDebit(error.dialog,error.transactionReference,tan,error.directDebitSubmission,);console.log("Direct debit completed:",result.taskId);}else{throwerror;}}

CLI Example

fints-lib submit-direct-debit \
--url https://banking.example.com/fints \
-n username -p 12345 -b 12345678 \
--account-iban DE89370400440532013000 \
--creditor-name "My Company GmbH" \
--creditor-id DE98ZZZ09999999999 \
--debtor-name "Customer Name" \
--debtor-iban DE02120300000000202051 \
--amount 99.99 \
--mandate-id MANDATE-2024-001 \
--mandate-date 2024-01-15 \
--collection-date 2024-12-15 \
--remittance "Monthly subscription fee"

5. List Multiple Accounts and Their Balances

import{PinTanClient}from"fints-lib";constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});// Get all accounts with balancesconstaccounts=awaitclient.accounts();for(constaccountofaccounts){console.log(`\n${account.accountName||"Account"} (${account.iban})`);console.log(` Type: ${account.accountType||"N/A"}`);try{constbalance=awaitclient.balance(account);console.log(` Balance: ${balance.value.value}${balance.value.currency}`);console.log(` Available: ${balance.availableBalance?.value||"N/A"}`);}catch(error){console.log(` Balance: Unable to fetch`);}}

Before using any FinTS library you have to register your application with Die Deutsche Kreditwirtschaft in order to get your registration number. Note that this process can take several weeks. First you receive your registration number after a couple days, but then you have to wait anywhere between 0 and 8+ weeks for the registration to reach your bank's server. If you have multiple banks, it probably reaches them at different times.

-- https://github.com/nemiah/phpFinTS

Packages

This library is maintained in a monorepo using lerna. These packages are included:

  • fints-lib - Core library (Take a look for library usage instructions.)
  • fints-lib-cli - Command line interface (Take a look for CLI usage instructions.)

🔒 Security

This library handles sensitive financial data and credentials. Please follow these security best practices:

Credential Handling

  • Never log credentials: The library masks PINs and TANs in debug output, but you should never log the raw configuration object
  • Store credentials securely: Use environment variables or secure credential stores (e.g., AWS Secrets Manager, Azure Key Vault) instead of hardcoding credentials
  • Use HTTPS only: Always use HTTPS URLs for FinTS endpoints to ensure encrypted communication
  • Debug mode: Be cautious when enabling debug mode (debug: true) in production environments, as it logs detailed request/response information

Example: Secure Credential Loading

import{PinTanClient}from"fints-lib";// ✅ Good: Load from environment variablesconstclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,debug: false,// Disable in production});// ❌ Bad: Hardcoded credentialsconstbadClient=newPinTanClient({url: "https://example.com/fints",name: "username",pin: "12345",// Never hardcode!blz: "12345678",});

Reporting Security Issues

If you discover a security vulnerability, please report it privately via GitHub's "Security" tab instead of opening a public issue.

💡 Tips and Troubleshooting

Finding Your Bank's FinTS URL

You can find your bank's FinTS endpoint URL in this community database:

Common Issues

Authentication Errors:

  • Verify your username, PIN, and BLZ are correct
  • Some banks require you to enable FinTS/HBCI access in your online banking settings
  • Check if your bank requires registration (see registration note below)

TAN Requirements:

  • Many operations (transfers, direct debits) require TAN authentication
  • Use try-catch with TanRequiredError to handle TAN challenges properly
  • Some banks require TAN even for login - handle with completeLogin()

Timeout Issues:

  • Increase the timeout value in client configuration:
    constclient=newPinTanClient({// ... other configtimeout: 60000,// 60 secondsmaxRetries: 5,});

Date Range Queries:

  • Not all banks support all date ranges - some limit how far back you can query
  • Use shorter date ranges if you experience timeouts or errors

Best Practices

  1. Always use environment variables for credentials:

    constclient=newPinTanClient({url: process.env.FINTS_URL,name: process.env.FINTS_USERNAME,pin: process.env.FINTS_PIN,blz: process.env.FINTS_BLZ,});
  2. Enable debug mode during development:

    constclient=newPinTanClient({// ... credentialsdebug: process.env.NODE_ENV==="development",});
  3. Handle errors gracefully:

    import{FinTSError,TanRequiredError,PinError}from"fints-lib";try{constaccounts=awaitclient.accounts();}catch(error){if(errorinstanceofTanRequiredError){// Handle TAN requirement}elseif(errorinstanceofPinError){// Handle PIN error}elseif(errorinstanceofFinTSError){console.error(`FinTS Error [${error.code}]: ${error.message}`);}}
  4. Close dialogs when done:

    constdialog=awaitclient.startDialog();try{// ... perform operations}finally{awaitdialog.end();}

Mentions

FinTS is a complex and old format and this library wouldn't have been possible without the great work of:

  • Prior99/fints - The original repository by Frederick Gnodtke that this fork is based on. Thank you for creating such a comprehensive and well-structured FinTS implementation! 🙏
  • python-fints was used a reference implementation.
  • Open-Fin-TS-JS-Client provides a demo server used for testing this library.
  • mt940-js is used internally for parsing the MT940 format.

Resources

Contributing

Contributions in the form of well-documented issues or pull-requests are welcome.

Contributors

  • Frederick Gnodtke (Original author)
  • Lars Decker (Fork maintainer)

About

Typescript FinTS client library.

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages