Processing SEPA transactions with Ruby

by Sahil Gadimbayli, Founder / Senior Engineer

SEPA, also known as Single European Payment Area, is a system of tools/technologies/regulations, facilitating simplification of bank transfers denominated in EUR.

There are quite a few steps involved in processing SEPA transactions from start to end. These include:

  • management of EBICS users
  • generation of XML documents with different formats; depending on your needs
  • communicating XML files to financial institutions
  • reading and parsing bank statements to perform updates in your system (if needed)

Building all of the above from scratch would take a considerable amount of time. I have encountered a few awesome tools in ruby, that may help us with just that, and save some of your precious time.

We will go through tools that we can use for each step, also noting some gotchas along the way.

Management of EBICS users

First of all, to submit transactions and fetch bank statements, we would need to have the EBICS users contracted, configured and confirmed.

This post assumes that you have done a contractual part with your bank/financial institution and have details at hand for the user. If not, please contact your financial institution to provide you with an EBICS user.

EBICS users can be an SRZ type or not. The difference is that the prior may process transactions on behalf of other customers of the bank, given the authorization. Normal users (NON-SRZ) may only process transactions for bank account it is associated with.

So, before asking for an EBICS user, it's good to know what your needs are for its utilization.

Configuring and confirming an EBICS user involves 3 steps.

  1. Create an EBICS user with data given by your financial institution; saving keys, and other user-related data.
  2. Print INI file received after creation, and physically sign/send to the bank
  3. Confirm the user when you receive ok from your bank

Folks at Rails Love built an awesome gem Epics, to do just that.

Let's get started.

Setting up the user initially...

# initialize user

user =
  Epics::Client.setup(
    "some-secure-password",
    "https://ebics.sandbox",
    "EBICS_HOST_ID",
    "EBICS_USER_ID",
    "EBICS_PARTNER_ID"
  )

# save keys (important!)

user.save_keys('path/to/my.key')

# submit keys to the bank
# sends the signature key
user.INI

# sends the encryption and authentication keys
user.HIA

# save ini file (you will need to print, sign and send this to the bank)

user.save_ini_letter( 'Bank Name', "/path/to/ini.html" )

Once your financial institution confirms that you may proceed with the user, you will have to confirm the user again(HBP order type) and download public keys of the bank.

Epics gem becomes handy in this part as well.

# initialize the client you have set up above

user = Epics::Client.new(
  File.open('/path/to/my.key'),
  'some-secure-password',
  'https://ebics.sandbox',
  'EBICS_HOST_ID',
  'EBICS_USER_ID',
  'EBICS_PARTNER_ID'
  )

# confirm and fetch the bank's public keys

user.HBP

# save new keys
# (you will use these keys from now on to initialize client)

user.save_keys('path/to/my.key')

# Try something to see if user works.

# this will return available order
# types for the user. However, from experience
# this list is not always correct :)
user.HAA

Now, we have got the EBICS user creation out of the way, let's go through how we can build an XML from list of transactions with correct format.

Generating XML documents consisting your transactions

Folks at SalesKing, wrote an awesome gem Sepa King to build XML files for direct debit and credit transactions with legacy and latest schema format.

Note that, Sepa King will suit your needs only if you are using a NON-SRZ user.

It is due to differences between container and non-container XML schema, which Sepa King currently does not support.

Explaining container and non-container format is not part of this blog post, thus we skip to usage of Sepa King.

Identify if you would like to create a debit or credit transaction, and create an XML out of it by providing data to Sepa King.

Have a look at their Readme, as it is pretty straight forward.

Once you have generated the XML, we need to communicate this to the bank.

Communicating XML to financial institutions

Now we have the XML file from Sepa King, we can use the Epics gem again to initialize our EBICS user, and communicate this XML to the bank.

# Generate the XML file
xml_file =
  'your_xml_output_received_from_sepa_king...'

# initialize EBICS user

user =
  Epics::Client.new(
    File.open('/path/to/my.key'),
    'some-secure-password',
    'https://ebics.sandbox',
    'EBICS_HOST_ID',
    'EBICS_USER_ID',
    'EBICS_PARTNER_ID'
  )
  
# Submit to bank

puts user.CDD(xml_file) # for direct debit
puts user.CCT(xml_file) # for direct transfer

Response is transaction_id and order_id of the order. Mind that the order type(CDD | CCT) is important to distinguish as they are used for seperate things(direct debit vs direct transfers).

It may happen that some order types are not available for your user, and you may get errors due to not being authorized to perform such orders. In that case, contact your financial institution to enable the required order types for your Ebics User.

Fetching and parsing bank statements to perform updates

It may be that, you need to follow up with the transactions you have submitted previously by reading bank statements, parsing it to perform updates in your system or to send out notifications. You decide...

Parsing XML documents and digging for data using Xpath is always painful. To ease their pain for common good, folks at Barzahlen wrote another awesome gem Camt Parser, which parses bank statements and supports several formats(C52, 53, 54).

Let's get to use it.

# Initialize EBICS user

user =
  Epics::Client.new(
    File.open('/path/to/my.key'),
    'some-secure-password',
    'https://ebics.sandbox',
    'EBICS_HOST_ID',
    'EBICS_USER_ID',
    'EBICS_PARTNER_ID'
  )

# Request C53 bank statement

collection_of_statements =
  user.C53(from_date = "2020-04-14", to_date = "2020-04-15")

# Pass it to camt_parser

parsed_document =
  CamtParser::String.parse(collection_of_statements[0])

# You may also parse files
parsed_document =
  CamtParser::File.parse '/path/to/your_statement.xml'

# Now, you can iterate over statements

parsed_document.statements.each do |statement|
  puts statement.account.iban
  statement.entries.each do |entry|
    # Access individual entries/bank transfers
    puts entry.amount
    puts entry.debitor.iban
  end
end

See other accessors and how an example C53 statement looks like here.

That's all for now.

We have gone through:

  • creation and management of EBICS users
  • creation of Direct Debit and Transfer XML files
  • communication with banks
  • parsing and using bank statements

There are lots of small details that we did not cover in this post such as batch booking, differences in statements, container and non-container XML formats. However, this should get you started.

Wish you a chargeback-free statements! Reach out to us if you have any suggestions for the post or questions about SEPA or any project that may need integration of such payment methods in your systems.

More articles

Dumping and restoring data between different Schemas in Postgres

Going from multiple database setup into a single database with multiple schemas, we will go through the process of dumping and restoring data between different schemas in PostgreSQL.

Read more

Adding index to text columns in Postgres

Speed up your queries by adding index to text columns in Postgres using gin strategy.

Read more

Tell us about your project

lightfulweb OÜ

  • Tallin
    Sepapaja tn 6
    15551 Tallin, Estonia