No release in over 3 years
A toolkit for ingesting and parsing statements from ING Bank.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 2.12
 Project Readme

ING Kontoauszug Parser

A Ruby gem for parsing ING Bank (Germany) statement PDFs and text exports into structured JSON.

Why This Gem?

ING Germany provides account statements as PDFs, but extracting transaction data programmatically is challenging:

  • PDF text extraction is messy – Column alignment, page breaks, and OCR artifacts make raw text unreliable
  • No official export API – ING doesn't provide a machine-readable format like CSV or OFX
  • Manual categorization is tedious – Hundreds of transactions need consistent tagging for budgeting

This gem solves these problems by:

  1. Extracting clean text from statement PDFs using poppler (fast) or pdf-reader (portable)
  2. Parsing transactions into structured data with dates, amounts, recipients, and narratives
  3. Extracting SEPA metadata like mandate IDs and references for reconciliation
  4. Validating IBANs using the ISO 13616 checksum algorithm
  5. Detecting payment methods like Google Pay for automatic categorization

Use it to build budgeting tools, import transactions into accounting software, or automate expense tracking.

Installation

# Gemfile
gem 'ing_kontoauszug_parser'
bundle install

Quick Start

require 'ing_kontoauszug_parser'

parser = IngKontoauszugParser::StatementParser.new
result = parser.parse(file_path: 'statement.pdf')

result[:header][:iban]              # => "DE89 3704 0044 0532 0130 00"
result[:statements].first[:amount_eur_numeric]  # => "-31.49"

API

parser = IngKontoauszugParser::StatementParser.new

# Parse PDF file
result = parser.parse(file_path: 'statement.pdf')

# Parse text export
result = parser.parse_text(File.read('export.txt'))

# Parse pre-split lines
result = parser.parse_lines(lines)

# Parse booking lines only (no header)
statements = parser.parse_statement_lines(lines)

Output Format

{
  "header": {
    "iban": "DE89 3704 0044 0532 0130 00"
  },
  "statements": [
    {
      "booking_date": "01.08.2025",
      "transfer_type": "Lastschrift",
      "recipient": "Allianz Direct Vers.",
      "amount_eur": "-31,49",
      "amount_eur_numeric": "-31.49",
      "amount_direction": "debit",
      "value_date": "01.08.2025",
      "narrative": "Versicherungsbeitrag August",
      "mandate_id": "MA123456",
      "reference": "RF123456789",
      "google_pay": true
    }
  ]
}

Statement Fields

Field Type Description
booking_date string Booking date (dd.mm.yyyy)
transfer_type string Transaction type (e.g., Lastschrift, Gutschrift)
recipient string Counterparty name
amount_eur string Original amount with German formatting
amount_eur_numeric string Normalized decimal (BigDecimal as string)
amount_direction string debit, credit, or neutral
value_date string Value date (dd.mm.yyyy)
narrative string Transaction details
mandate_id string? SEPA mandate ID (if present)
reference string? SEPA reference or ARN (if present)
google_pay boolean? true if Google Pay detected

CLI Tools

# Parse PDF statement to JSON
bin/pdf_to_json statement.pdf

# Write to file instead of stdout
bin/pdf_to_json -o output.json statement.pdf

# Interactive console
bin/console

Error Handling

PDF reader errors are wrapped as IngKontoauszugParser::Error:

begin
  parser.parse(file_path: 'encrypted.pdf')
rescue IngKontoauszugParser::Error => e
  puts e.message
end

Non-fatal issues (e.g., statements missing value dates) are collected in an optional warnings array:

result = parser.parse_text(text)
result[:warnings]&.each { |w| puts "Warning: #{w}" }

Development

bin/setup      # Install dependencies
rake test      # Run tests
rake rubocop   # Lint

Requirements

  • Ruby 3.0+
  • pdf-reader gem
  • Input files must be UTF-8 encoded

Documentation

Contributing

Bug reports and pull requests welcome on GitHub.