SaFi Bank Space : TM payment integration

(blue star) Relevant data

There are different types of payments planned to be executed by different domains. The different payment types:

  • Financial transaction

    • intrabank (customer to customer)

    • interbank

    • topup

    • own account transfer

  • Interest payment (most likely jobs scheduled within smart contracts)

    • accrual

    • payment

  • Loan instalment

    • overdraft

    • personal loan

  • Card transaction

  • Fee charging

    • subscription fee

    • transaction fee (atomic part of transaction)

  • Manual adjustments from BO (in case of disuputes)

The payments (transfers) are executed on TM via Postings. There is a requirement for transactions domain to show the full transaction history on a customer’s account, consolidating all the different transaction types.

Full list of postings Interactions with TM - Postings

(blue star) Background

TM offers an async request-response Postings API to send posting instructions on TM. This Postings API offers API client separation which allows creating a specific response topic per created clientId. Every message sent to the request topic with clientId will get sent to the corresponding response topic, which aims to create isolation between different payment integrations using the Postings API.

In addition to the above, TM offers two kinds of request topics based on the priority and SLA of the message. Messages in the priority topic are always processed prior to messages in the regular topic. Such priority topic is particularly useful when integrating with systems with strict SLA for processing (e.g. Card payments).

The question is how should the respective domain services connect to TM, and whether to use a single point of connection (such as a gateway) between TM and the domain services, essentially having a single Posting API client, or let every integration connect independently.

(A) Transaction manager as a common point of communication with Postings

TM would have configured a single Postings client, to which a single service would connect. This service (transaction-manager) would act as a facading layer over the TM Postings API. The rest of the services wishing to make money transfers would use the API exposed by the transaction-manager. Whenever a TM posting is completed, the transaction-manager emits an event (transaction event) to a Kafka topic, from which the Transaction-history-manager (TRHM) can build a consolidated view on transaction history.

Each integration having its own TM Postings client

TM would have configured a Postings API client per integration - a service (or domain) which wishes to make postings through TM. Whenever a posting is executed by the specific integration service, the result arrives in the respective response topic matched by the clientId.

(B) Option with history built from domain service events

The managing service listens to this posting response, enhances the posting with additional transactional details specific to the type of transaction and emits an event to its dedicated topic. The transaction history manager creates the transaction history from the enriched events published by domain services and Posting-instruction-batch-created topic containing postings emitted by smart contracts.

(C) Option with history built from TM Postings topic

The services making postings add all necessary data for transaction history to the Posting instruction itself as metadata (“batch_details”). This metadata gets then transferred as-is to the Posting-inststruction-batch-created topic by TM, from which the Transaction history manager would build the full transaction history.

(D) Option with history build from TM Posting and domain enrichment

The services making postings maintain the enrichment information about the transaction in their DB. They provide this enrichment information to their dedicated topic at the moment of publishing the posting request. The topic hence contains additional information about the transactions which were requested to be processed (not necessarily processed yet). At the same time, the service provides a unique transactionId (and originating service) to the posting details as an identifier for where to find the transaction enrichment data.

The transaction-history-manager listens to the Posting-instruction-batch-created topic and creates the transaction history detail from:

  • the data available in the posting originating from TM

  • the enrichment data about transaction coming from the originating service, matched by the transactionId

(blue star) Options considered

(A) Transaction manager as a common point

(B) Separate API client per integration + History built from domain service events

(C) Separate API client per integration + history built from TM Postings topic

(D) Separate API client per integration + History build from TM Postings and service enrichment topic

Description

All money transfers represented as postings would go through the transaction-manager

Services wishing to make money transfers create their own API client. Transaction history is built from enriched domain service events

Services wishing to make money transfers create their own API client. Transaction history is built from events in the single TM Posting-instruction-batch-created topic. Transaction enrichment is sent with the posting.

Services wishing to make money transfers create their own API client. Transaction history is built from events in the single TM-Posting-instruction-batch-created topic and enriched by information coming from domain service topics

Pros and cons

(plus) Single point which has full control over what transactions are happening grants more confidence to having transaction history under control

(plus) Rest of the services wishing to make transactions have simpler API to integrate against

(minus) The priority topics exposed by TM would need to be reimplemented in the transaction manager. Having the API flooded with low-priority transactions should not have performance effect on the priority transactions

(minus) As the transaction history manager (TRHM) listens only to the transaction events provided by the transaction manager (TRM), the postings are either not enhanced with domain-specific data for each transaction, or such data are passed through TRM (or TM directly), with TRM having to be flexible enough to understand such data or the TRM acting just as a “proxy”.

(minus) Domain specific logic required to be executed prior to transaction execution needs to be understood by the transaction manager. Either that, or the transaction manager exposes domain agnostic enough API which is similar to using the TM Postings API directly.

(minus) Postings emitted by smart contracts do not flow through the TRM, hence breaking the assumption that each transaction flows through TRM - such cases would need to be handled separately.

(plus) Separation of domain-specific implementation is achieved by each domain acting on postings independently. The domain service has power over e2e delivery without dependencies on TRM.

(plus) Any domain specific actions needed to be executed prior to the transaction can happen within the domain service, leveraging its domain knowledge.

(plus) The services are able to provide transaction events after a posting is processed, which are enhanced by domain-specific data.

(minus) The transaction history manager has to listen on all topics for all of the services which are sending postings against TM. Thus granting less confidence for the TRHM not to miss any transaction.

(minus) The transaction history manager has to listen also on the TM posting topic as results of the postings emitted by smart contracts are only published there.

(plus) Separation of domain-specific implementation is achieved by each domain acting on postings independently. The domain service has power over e2e delivery without dependencies on TRM.

(plus) Any domain specific actions needed to be executed prior to the transaction can happen within the domain service, leveraging its domain knowledge.

(plus) The transaction history manager listens to a single TM topic, being ensured it does not miss a single processed or rejected posting.

(minus) Transaction data enrichment has to be done by providing schema-less string-to-string metadata map to Posting instruction.

(minus) The data sent through postings as enrichment must not contain PII, which may create difficulties in some types of transactions.

(plus) Separation of domain-specific implementation is achieved by each domain acting on postings independently. The domain service has power over e2e delivery without dependencies on TRM.

(plus) Any domain specific actions needed to be executed prior to the transaction can happen within the domain service, leveraging its domain knowledge.

(plus) Transaction history manager listens to a single TM topic to compile the list of transactions that have been tried to be processed.

(plus) Transaction enrichment is done by domain services emitting an event with a well-defined schema.

(plus) TM Postings do not contain any PII as they only contain a reference to a transaction originating from the domain service

(minus) Transaction history manager has to do a consolidation and transactionId matching of the events coming from TM and the domain services

Estimated cost

(blue star) Action items

(blue star) Outcome

The approach (D) Option with history build from TM Posting and domain enrichment was chosen as agreed by the forum of tech leads.

This allows us to leverage the separation of posting API clients, make the transaction-history-manager aware of every single transaction, and as well be sure not to send PII information through TM.

Attachments:

~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
tm-integration-single (application/vnd.jgraph.mxfile)
tm-integration-single.png (image/png)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
tm-postings-decentralized (application/vnd.jgraph.mxfile)
tm-postings-decentralized.png (image/png)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
tm-postings-decentralized (application/vnd.jgraph.mxfile)
tm-postings-decentralized.png (image/png)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
tm-postings-decentralized (application/vnd.jgraph.mxfile)
tm-postings-decentralized.png (image/png)
tm-integration-single (application/vnd.jgraph.mxfile)
tm-integration-single.png (image/png)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
~tm-postings-decentralized.tmp (application/vnd.jgraph.mxfile)
tm-postings-decentralized (application/vnd.jgraph.mxfile)
tm-postings-decentralized.png (image/png)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
tm-postings-integration-balances (application/vnd.jgraph.mxfile)
tm-postings-integration-balances.png (image/png)
tm-postings-integration-balances (application/vnd.jgraph.mxfile)
tm-postings-integration-balances.png (image/png)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
tm-postings-integration-balances (application/vnd.jgraph.mxfile)
tm-postings-integration-balances.png (image/png)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
tm-integration-common-history (application/vnd.jgraph.mxfile)
tm-integration-common-history.png (image/png)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~tm-integration-common-history.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
~tm-postings-integration-balances.tmp (application/vnd.jgraph.mxfile)
tm-postings-integration-balances (application/vnd.jgraph.mxfile)
tm-postings-integration-balances.png (image/png)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
tm-integration-single (application/vnd.jgraph.mxfile)
tm-integration-single.png (image/png)
tm-integration-common-history (application/vnd.jgraph.mxfile)
tm-integration-common-history.png (image/png)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
~tm-integration-single.tmp (application/vnd.jgraph.mxfile)
tm-integration-single (application/vnd.jgraph.mxfile)
tm-integration-single.png (image/png)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
~drawio~557058:27349720-65fa-4129-b290-8abf5953e7fb~tm-posting-integration-enrichment.tmp (application/vnd.jgraph.mxfile)
tm-posting-integration-enrichment (application/vnd.jgraph.mxfile)
tm-posting-integration-enrichment.png (image/png)