Skip to content

Repository files navigation

PaymentLab

Go PostgreSQL Docker ISO8583 OpenTelemetry License

PaymentLab is a microservice-based ISO 8583 payment simulator that models a realistic acquirer/issuer payment flow — built for testing, learning, and prototyping against ISO 8583 financial messaging without touching a real card network.

Overview

The project simulates the two sides of a card transaction:

  • Acquirer — an HTTP API gateway (and web UI) that receives transaction requests, applies backpressure/rate limiting, and forwards them to the issuer over TCP using ISO 8583-encoded messages.
  • Issuer — a TCP backend that decodes ISO 8583 messages, authorizes transactions against card/balance data, and returns a response.

Both services are independent Go binaries, each with their own PostgreSQL database, and can be run together locally with a single docker compose up, or deployed as two separate services (e.g. on different hosts) using the split compose files.

Screenshots

Transaction Simulator

image

Build ISO 8583 requests, inspect parsed fields, and trace issuer responses.

Webhook Integration

image

Receive signed webhook events with automatic retries and delivery history.

Architecture

                    ┌─────────────┐
   User / Web UI ──▶│  Acquirer   │  HTTP API · Port 8081
                    │  (Go/Gin)   │
                    └──────┬──────┘
                           │ ISO 8583 over TCP
                           ▼
                    ┌─────────────┐
                    │   Issuer    │  TCP Server · Port 5001
                    │    (Go)     │
                    └──────┬──────┘
                           │
              ┌────────────┴────────────┐
              ▼                         ▼
     Acquirer PostgreSQL         Issuer PostgreSQL
     (audit logs, port 5433)     (cards, balances, port 5432)

Full C4 model diagrams (context / container / component level) are in docs/:

Features

  • Interactive web interface for building and inspecting ISO 8583 messages
  • ISO 8583 message encoding/decoding driven by a declarative spec (web/spec.json) — no hardcoded field layouts
  • Acquirer ↔ Issuer flow over raw TCP, mirroring how real payment switches communicate
  • Card management API (create, list, update, delete, top-up)
  • Transaction processing with configurable backpressure (in-flight limits, queueing, timeouts) so overload degrades predictably (429/504) instead of falling over
  • Full transaction and card audit trail in PostgreSQL, with separate acquirer/issuer databases
  • Interactive web UI for building, sending, and tracing ISO 8583 messages in real time
  • OpenTelemetry metrics and tracing, OTLP-exportable to any compatible backend (optional — see docs/OBSERVABILITY.md for a Grafana Cloud walkthrough)
  • Built-in /health, /healthz, and /metrics endpoints

Prerequisites

  • Docker and Docker Compose (quick start / recommended)
  • Go 1.25+ (only needed for local, non-Docker development)
  • PostgreSQL 16 (only needed for local, non-Docker development — Docker Compose provisions this for you)

Quick Start

git clone https://github.com/fatihbulut/paymentlab.git
cd paymentlab

cp .env.example .env

docker compose up -d --build

Then open the web UI at http://localhost:8081.

Service Address
Acquirer HTTP API / Web UI http://localhost:8081
Issuer TCP service localhost:5001
Acquirer PostgreSQL localhost:5433
Issuer PostgreSQL localhost:5432

To stop everything:

docker compose down          # keep data
docker compose down -v       # also wipe database volumes

Docker Compose Usage

This repo ships three compose files:

  • docker-compose.yml — the all-in-one local development stack: builds both services from source and runs them alongside their own Postgres instances. This is what docker compose up uses by default and is the right choice for local development and evaluation.
  • docker-compose.acquirer.yml / docker-compose.issuer.yml — an example of running acquirer and issuer as independent deployments (e.g. on two separate hosts), pulling prebuilt images instead of building from source. See the comments at the top of each file for usage, and copy the matching .env.acquirer.example / .env.issuer.example before use.

Local Development

Running the services directly with Go is faster for iterating on code than rebuilding containers each time.

  1. Start just the databases:

    docker compose up -d issuer_postgres acquirer_postgres
  2. Set the environment variables from .env.example (source them into your shell, or configure your editor's run/debug configuration).

  3. Run each service in its own terminal:

    go run ./cmd/issuer
    go run ./cmd/acquirer

Database schema is managed via plain SQL migrations in migrations/ (see acquirer/ and issuer/ subfolders); they're applied automatically on service startup.

Testing

Run the Go unit tests:

go test ./...

For a load test against a running acquirer instance (uses Vegeta):

docker compose up -d --build
./test/load-test.sh

See docs/loadtest.md for guidance on tuning backpressure settings (INFLIGHT_LIMIT, QUEUE_SIZE, timeouts) under load.

Project Structure

cmd/
  acquirer/          # Acquirer service entrypoint
  issuer/             # Issuer service entrypoint
internal/
  acquirer/           # HTTP handlers, middleware, TCP client to issuer
  auth/                # Authorization rules and response codes
  card/                # Card domain model and service
  config/              # Environment-based configuration
  iso/                 # ISO 8583 codec + spec loader
  issuer/              # TCP server and transaction processing
  otel/                # OpenTelemetry setup and custom metrics
  proccode/            # ISO 8583 processing code (field 3) parsing
  scheme/              # BIN ranges, EMV tags, scheme response codes
  store/               # Storage interfaces + PostgreSQL implementation
  util/                # Shared helpers
migrations/            # SQL schema migrations (shared, acquirer, issuer)
web/                   # Static web UI + ISO 8583 spec (spec.json)
docs/                  # Architecture diagrams and domain documentation
test/                  # Load test script and sample request payload

Documentation

Contributing

Contributions are welcome!

  1. Fork the repo and create a feature branch.
  2. Make your changes, keeping them focused and consistent with the existing code style.
  3. Add or update tests where relevant (go test ./... should pass).
  4. Run go vet ./... and make sure the CI workflow would pass.
  5. Open a pull request describing what changed and why.

Please don't commit secrets, credentials, or environment files (.env) — only the .env*.example templates belong in the repo.

Roadmap

TBD — contributions and suggestions welcome. Open an issue to propose a direction.

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

ISO 8583 payment simulator — acquirer, issuer, and full-duplex TCP switch

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages