The times when the standards are expanded or updated are fun (https://www.europeanpaymentscouncil.eu/what-we-do/epc-paymen...), translating hundreds of pages of PDF into working code and then have hundreds of banks implement those changes in the same nightly hour during a weekend...but once it is working, there is no ambiguity or (horror) manual intervention in payment messages. Either you as a bank send valid messages and they are processed, or you don't and they get rejected.
I wrote a bit about the tool and my experience with SEPA standards at https://evrim.zone/blog/projects/batch2sepa, check it out!
That said, this library is made to be extensible. One day I think it will even be able to encapsulate any type of bank. For example, imagine bofaISO20022.createACHPaymentInitation or something
The only thing XML gives you over any of those formats is unstructured mixing of text and data, which is more a foot-gun than anything. Oh, and of course, being significantly more verbose.
Another challenge is that different banks may use slightly different versions of the standard messages that are enunciated via the implementation specific concrete XML namespace in the xmlns attribute of the message envelope.
Overall, ISO 20022 is an improvement over MT940/MT942 and friends, although it is not easy to use.
The must know a lot about ISO20022 payments! I'd love to get in touch with you, if you can please shoot me an email @ svapnil@woodside.sh :)
My name is Svapnil Ankolkar and I've recently built iso20022.js, a library for creating ISO20022 payments in Typescript.
The goal of this project is to be the easiest way to create, and eventually ingest, files in the ISO20022 standard, the defacto XML standard for bank payments.
I'd love to know what you think and importantly know about any improvements you'd like us to make!
// 1. Import
import { ISO20022 } from 'iso20022.js'
// 2. Instantiate the sender
const iso20022 = new ISO20022(initiatingPartyInfo);
// 3. Send
iso20022.createSWIFTCreditPaymentInitiation(paymentInstructions);I will admit I'm usually very skeptical about "Do X in Y line" claims because usually you can do anything in one line by shoving the entire codebase behind a "DoIt()" call. But I'll actually give them this one. I'm not even worried about the data taking up so many lines as clearly the data is necessary. If they were full of mandatory function calls or something I'd ding 'em too, but they're not, it's just the data you need.
The bigger question of course is what do you end up with. Clearly that method call isn't going to actually send an instruction to your bank to debit your account and credit somebody else's. I guess `creditPaymentInitiation` is an object that has can be converted to a properly formatted message that can then be sent to your bank using an external tool?
> import { ISO20022 } from 'iso20022.js'
> const iso20022 = new ISO20022({ /.../ });
> const creditPaymentInitiation = iso20022.createSWIFTCreditPaymentInitiation({ /.../});
> console.log(creditPaymentInitiation.toString());
Now are we counting the import and not counting the log statement, or are we counting the log statement and not the import?
I'm not too worried about it.
Support bank statements.
I think it's scary to do any finance related stuff using NPM dependencies. How large is your dependency tree?
Visualized: https://npmgraph.js.org/?q=iso20022.js
Could you help me understand who the target devs are for this library? I doubt it's someone like me, who would try to use it as a replacement for stripe before realizing all of the stuff I have to do outside of that and giving up on it. But maybe this is more for people who are doing heavy financial management anyway? Or am I just completely thinking about what this is wrongly?
You're right. Accepting credit card payments over the internet is usually done handled by black-box third party payment processors.
Bank payments, like ACH, SWIFT, and others are usually built in-house by companies that move money at scale, like payroll providers, insurance companies, and other old school institutions.
As companies that do heavy financial management refresh their architecture and move to modern web servers and the like, they'll likely need to rebuild it from scratch. This is what iso20022.js plays a small part in - if they're building on Node this is a convenient library for them to use.
Are companies do heavy financial management refreshing their architecture in node, javascript and typescript? And do they then rely on a library with one sole contributor?
Sorry if this sounds dismissive. I am actually afraid by the answer, because, having worked in fintech, I wouldn't be surprised if the answer is "yes, certainly some".
Thanks for the explanation!
Black box payment processors and Stripe need libraries too.
Some thoughts:
- replace strings with enums where possible. E.g. "USD" should be from an enum
- this sort of data-interop library could maybe be written in a configuration language that it uses to generate libraries for different languages
- a glossary would be really helpful
- a list of banks who've adopted this ISO standard might be interesting
Note how this is a typescript project and leverages a type for currency that comes from a common library, and therefore doesn’t have to do any of the work! https://github.com/Svapnil/iso20022.js/blob/main/src/lib/typ...
I think payments is an industry in general that is starving for the right information, so a free and open source package like this should have an abundance of information. I'll make sure I add it in.
The configuration language sounds really interesting. What I think is special about this library is that it comes with all the Typescript furnishings one would need to have a powerful dev experience. The goal is to make it incredibly easy for a developer to use iso20022, not just another middle layer that obfuscates it
It's not simple; it might just be an interesting distant goal to keep in mind.
Believe it or not, many bank use custom/non-standard currency code internally.
I agree enum can be used for SWIFT, but it need to be string to be used internally in many bank.
The remaining 675,000 lines of code are to:
- Perform Risk / Fraud scoring to decide whether you want to, indeed, process this payment.
- Deal with the myriad of failure scenarios - including mapping them to your own system's error semantics - in a way that your customers can understand to reduce support calls.
- Refund, void or reverse previous payments.
- Create the necessary accounting entries in order to do settlements / settlement reports for your customers.
- Etcetera
Payments systems are perplexing to me: Nothing is a more obvious candidate for an absolute, standardised, commoditised piece of software in the same way that the global IP network routes packets - only in payments we are routing "promises" and our routes, and routing decisions, are in many ways much simpler.
Yet there are very few industries where this particular wheel gets reinvented as often as it does; each organisation convinced that it has its own unique approach to doing this absolutely standard, regulated "thing" - which, reductio ad absurdum, is just an expensive buffer in a network of pipes.
Hopefully open-source software will pave the way: TigerBeetle is an amazing start (distributed ledgers), and it's hopefully only a matter of time until the other components of a payments switch are freely available as open-source components with high-quality APIs.
- ensures all operations are atomic. You can't just post to an API and then insert something in your database: that's a guarantee to have payments in one place and not the other.
- has some way to retry on failure: your average job-queue with exponential backoff is quite certainly still too naive.
- has full, secured and guaranteed audit logs. That have all the data needed for an audit, but also not too much. You chose to not go for the Event Sourced Architecture because of Reasons? Good luck bolting it in now.
The hard part isn't generating some pain.001.001.03 (yes, that really is the name for the SWIFT Payments Initiation in iso-20022) format. The hard part is everything else.
If you work with multiple banks, like many corporates or fintechs, multiply many of these lines by the number of banks you work with.
Even before starting to code anything, a big part of the job is obtaining the documentation from each bank and specifying the integration for each bank.
For instance, for the same payment scheme, different banks require different maximum payments per file or payload, or maximum payment file or payload size.
More things to consider in this high-level article https://www.numeral.io/blog/bank-payment-integrations-challe...
If US has any defense, it is that it is not alone in this craziness as almost every bigger power center carefully manages its domain to ensure it remains a relevant player. To put it simply, there is too much money in managing different pipes.
At this point though, short of complete collapse necessitating full rewrite of the existing payment systems, standardization will not happen. ISO itself is a convoluted mess with one real benefit of using standard XML.
We also have no standard way of letting users authenticate to their bank to download transactions. Once you get logged in there is usually a way to get OFX (QFX) files but the process is manual. I happened on the European open banking documentation the other day...jealous.
If you enjoy SOAP you'd feel right at home and likely have better tooling foundations already, if you don't you probably want a library like this one, at least when they've implemented SEPA support.
ISO20022 is the XML standard to send payment instructions, and this library conveniently exposes it's models in Typescript format. It seems like understanding what ISO20022 is is super important, so I'll spend some effort educating people on what this is
There are tools that can turn the schema files into POJO/dataclasses/structs/etc in your language of choice, sometimes with proper data validation. Not sure about Typescript, but Java/Python/Golang definitely have those.
It may very well be lost knowledge in certain ecosystems, but generating a valid XML based on the given schema is generally a solved problem. Not sure if the projects adds anything beyond that.
I think there's always some ergonomic gap between these XML Schema generated classes and SDKs that developers are comfortable using. My intention for this library is for a non-payment developer to be able to interact with the ISO20022 schemas, while being as true to the underlying models as possible.
Generating classes from the XSD's is fairly trivial in most languages. The hard part is being able to read the XSD's and then being able to create the ISO20022 message with all of the required elements (given all the possible combinations of valid elements).
I guess creating a code-time library where it was not possible to create an ISO20022 message that invalid would be interesting. But being able to create invalid ISO20022 is fairly easy to do for free.
You would need to upload that XML to a bank to actually process the transaction.
There are other formats like NACHA (US only), where you have to generate a text file with a pretty specific format, and upload that, often via sFTP to the Bank's server to process.
https://docs.iso20022js.com/quickstart#step-4-send-the-payme...
- Shelving a Windows box in some authorized datacenter.
- Going through a years long process of getting certified to send payment instructions to the scheme (e.g. SWIFT network).
- Receiving a couple of USB sticks that contain certificates and signing keys.
- Connecting to the schemes VPN.
- Having all the legals in place.
- And probably many more things I was never exposed to.
1. Security Adding vendors is a very scary thing for companies, rightfully so. Open source is great for this, because an NPM package is not a vendor.
2. Signing / Sending a Transaction iso20022.js doesn't deal with message sending yet. Best case there is a straightforward SFTP setup, which I've given instructions for here: https://docs.iso20022js.com/quickstart#step-4-send-the-payme...
3. Getting certified to send payment instructions. This should be the work of the module!
Not to mention that the flows of ISO20022 messages are full duplex. If you send a message you need to be ready to handle a response (acceptance or rejection of a credit/debit for example).
There isn't something we are currently offering yet, althoug I wrote about how this works in the quickstart guide: https://docs.iso20022js.com/quickstart#step-4-send-the-payme...
How do you get a response/know if your file processed correctly?
I think it is a not very good idea to develop finance software in node
In order to transmit bank payments programatically, you must have direct transmission enabled with your banking partner. If you have any questions about this, don’t hesitate to reach out to us.
So do we need to get this enabled on a per bank basis or a per account basis?
If you have more questions, I'd love to help you out - please shoot me an email @ svapnil@woodside.sh
The test cases for this library validate against the XSD for the ISO files, which could be extended to handle more test cases.
Banks sometimes offer a test SFTP endpoint they use. Engineers have had to do this from scratch at the companies they worked at in the past. If this is something you're interested in, we should talk more @ svapnil@woodside.sh
I wanted to know this as well - specifically sms based payments if its so easy to wrap payment calls... found this:
---
ISO 20022 is a global standard for electronic data interchange between financial institutions, enabling efficient and secure exchange of financial messages. It is widely used in various payment scenarios, including:
* Cross-border payments:
ISO 20022 facilitates international transactions by providing a common language for financial institutions to communicate.
High-value payments: It is used for large-value transactions, such as wholesale payments, securities settlements, and treasury transactions.
Retail payments: ISO 20022 is also used for retail payments, including credit transfers, direct debits, and e-payments.
Real-time payments: It supports real-time payment systems, enabling fast and efficient transactions.
* SMS-based payment initiation:
An SMS can be used to initiate a payment, with the payment details (e.g., amount, recipient) encoded in an ISO 20022 message. The message would then be sent to a payment processor or financial institution for processing.
Mobile payment apps:
Mobile payment apps can use ISO 20022 for payment processing in the background, while the user interacts with the app via SMS or a graphical user interface.
Instead of webhooks, a developer would poll an SFTP directory for an unique PSR file to ingest. Eventually, iso20022.js should support ingesting PSR files and provide an interface for using them.
fiat bank payments require a lot of information to be send correctly, for better or for worse. this library conveniently exposes the elements needed to send a payment, as per the most widely used standard available (iso20022)
https://evrim.zone/blog/knowledge/iso_20022_pain_001
For Americans who've never heard of it, FedNow is seemingly using a 'a bespoke flavor of the ISO 20022 specification' (https://news.ycombinator.com/item?id=36805571). I think that it's a pretty handy format to be familiar with, and is quite simple to work with too. If the Fed or participating banks decide to open up the system like European banks have done so, it can be handy to get familiar with it for us financial hackers out there!
Neat none-the-less! I always like this sort of actually-it's-simpler-than-you-think peek behind the curtain.