Architecture
Hii Payments consists conceptually of the following parts:
- a Unified Payment API (UP API) for requests and responses related to card payment flows
- several PSP Connectors, one specific service for each payment service provider that is supported
- a configuration front-end for each PSP connector
- a core Java framework library that implements generic functionality which is used by all PSP Connectors
Every PSP Connector is a microservice independent of other PSP Connectors without any shared runtime code.
With Hii Payments, a POS system can be integrated once with the Unified Payment API and via that single integration switch between any supported PSP without any modification of the POS.
System context
Containers
Our preferred method of integration is with an asynchronous event-driven API, for example using webhooks.
PSPs with RESTful APIs
If the PSP doesn't offer an asynchronous webhook API, the next best option is a RESTful API. However, this is only viable if the request-response flow is finalized in a predictable and timely fashion. The service cannot wait for a response more than a couple of seconds. Therefore, this integration is typically not possible if any human interaction is involved (as with card payments), but it could work for gift cards or similar.
PSPs with stateful APIs
The least favorable option to integrate with are PSPs that only offers stateful APIs that depend on a long-lived connection to be constantly up. This typically means a socket and a binary, XML or JSON protocol of some sort. We need a design to support these integrations without compromising our own event-driven architecture. To achiveve this, we would favor a propxy service pattern to isolate the stateful connection in its own microservice.
Components
The components view shows the internals of a PSP Connector. It shows that a PSP Connector service consists of the following
- A spec-first schema used for all validation. There's no additional DTOs needed for validation and processing
- A shared core module handling common processing
- A PSP specific integration module
APIs
The following APIs are part of Hii Payments:
- Unified Payment API
- API used by Checkout Engine and potentially other POS systems to integrate with once to be able to use any existing PSP connector. This API is available as messaging over Pub/Sub in addition to Open API. The message format is defined as JSON schema.
- This API is supported by every PSP Connector.
- Configuration API for each specific PSP Connector. E.g. Adyen Connector configuration API
- API used to configure checkouts for the Adyen PSI.
IDEALS
Hii Retail services adheres to the IDEALS principles in microservice architecture. This section covers how the design choices in Hii Connect - Payments fulfills the IDEALS.
Interface segregation
The service will offer two types of APIs
- Open API (e.g. Adyen Connector configuration API)
- Messaging over Pub/Sub (e.g. Unified Payment API)
The Pub/Sub APIs are used by the Checkout Engine for asynchronous payment flows. The Open APIs are primarily for configuration and management, but they also offer resources to initiate payment flows in a callback fashion where the response is sent to a webhook endpoint. This message flow is intended for edge deployment when a Pub/Sub messaging bus won't be available.
Deployability
- The solution is designed as a serverless, independently releasable, testable and scalable service.
- Best practices from the cloud platform will be followed
- Favor serverless (Cloud Run)
- Infrastructure as code
Event-driven
The solution architecture is event-driven and based on Pub/Sub.
- All execution occurs within the request or event-scope. The service requires no CPU cycles outside of the request context.
- Message processing is idempotent and commutative, meaning it handles duplicate messages and out-of-order messages gracefully and strongly eventually consistent (SEC).
Availability over consistency
The system is designed around an immutable data model in a strongly consistent Postgres DBMS. We use database transactions for a consistent internal state in the service.
Our availability is boosted by Pub/Sub because we can allow it to retry in case our Postgres is temporarily unavailable. Therefore the system will behave as 'strongly eventually consistent', when observed from the outside. Once all payment messages has been processed our state will include results for all operations.
Finally, the system depends on external PSPs which are typically stateful and focused on consistency. The Hii Payments attempts to hide all of the messy state management, that is common in the external PSP solutions.
Loose-coupling
This service has no dependencies on other services. but is essential for our Checkout Engine to fulfill payments.
Single responsibility
The single responsibility of the service is to process payment flows for payment cards. Every PSP Connector is deployed as a separate micro service, including a specific version of the core library, ensuring that one integration will not change because a new one is introduced, some other PSP connector is modified or released with a newer version of the core library, or any other service is modified. The possible exception is when a PSP proxy service is used for integrations with PSP's with stateful connections, then there will be a dependency between the PSP Connector service and the PSP proxy service.
General considerations
General Hii Retail design considerations as applied to the PSP Connectors.
Multi-tenancy
The PSP Connector services are multi-tenant.
- All payment flows runs in a tenant scope.
- Checkout configuration and webhooks are isolated by tenant
Auditing
The PSP Connectors will write audit records for
- Webhook creation and deletion
- CRUD operations on checkout configuration
- Service usage of configuration will not be audited, only read operations performed by users.
Security
- All ingress and egress uses TLS
- All APIs are secured using either
- Hii Retail IAM (for users)
- Workload identity
- OCMS
- Webhook endpoints are secured using basic authentication
- Username and password are generated together with a unique endpoint URL
- The password will only be displayed once (in the create response)
- Passwords are encrypted in the database using PBKDF2 with unique salts
- Data is encrypted at rest using Google managed keys
- Automated backups will be used in Cloud SQL for recovery of webhooks and configuration
Legal compliance
GDPR
The service will not use any directly identifying personal data. Depending on integations, it may see some indirectly identifying personal data, for example a loyalty account number. This has been discussed with our GDPR subject experts and we've concluded we don't need to take any extra measures to protect that data.
For future integrations, we shall continue to protect ourselves from handling identifying data. It would for example be problematic to integrate a service that uses social security numbers for loyalty.
PCI
The service will not be in-scope of PCI, meaning it will not receive, process, store or transmit any Account Data, Cardholder data or sensitive authentication data. For definitions see.
We will not accept integrating with PSP's that can't guarantee to keep our services out of the PCI scope.
Data mesh
Not planned.
Global reach
Cloud SQL is the only component that we can't scale across regions easily. To counter that, we can opt to move to Cloud Spanner. It supports Postgres drivers which would make the transition invisible to the application.
Internationalization
The service will support i18n and l10n.
- All date-time fields are UTC "Zulu" time
- All numbers are proper numbers
- Produced receipt texts are translated as per required financial legislation
The PSP Connectors will support translations of PSP Connector specific texts as required for each individual integration. The PSP Connectors shall integrate with any future translation service in Hii Retail. Until available, the PSP Connectors will include translations as Java native language resource bundles as that is the minimum development and design effort.