A highly resilient, multi-provider payment gateway built with Java 21 and Spring Boot 3. Designed to mirror enterprise fintech architectures, featuring distributed system patterns, API idempotency, and cryptographic webhook security.
Frontend: Pair this API with the Payment Orchestration Dashboard — a Next.js/TypeScript UI for creating payments, monitoring routing, and testing webhook verification against this backend.
This project was designed to demonstrate mastery of concepts required for enterprise payment integration:
- Database-Level Idempotency: Prevents double-charging by utilizing unique constraints on
idempotency_key. If a network drop causes a merchant to retry a request, the system safely returns the original result without re-processing. - Apache Camel Integration: Implements the Enterprise Integration Pattern (EIP) "Content-Based Router". Incoming payments are dynamically routed to different mock providers (Stripe vs. PayPal) based on the transaction currency.
- Webhook Signature Verification: A dedicated endpoint to receive async provider updates. Validates incoming payloads using cryptographic signatures to prevent payload spoofing.
- Containerized DevOps: Built with a multi-stage Dockerfile (optimizing image size) and Docker Compose for seamless local infrastructure provisioning (App + PostgreSQL).
- ⚙️ CI/CD Ready: Includes a declarative CI pipeline configuration for automated build verification.
- Language: Java 21
- Framework: Spring Boot 3.3.4, Spring Data JPA, Spring Validation
- Integration: Apache Camel 4.4.0
- Database: PostgreSQL 15
- Security: HMAC-SHA256 (Javax Crypto)
- Tooling: Lombok, Maven, Docker, Docker Compose, Git
The entire system (Application + Database) can be spun up with a single command:
# Clone the repository
git clone https://github.com/OJCodeCanvas/payment-orchestration-platform.git
cd payment-orchestration-platform
# Start the infrastructure
docker-compose up --build -dNote: The application takes about 15 seconds to fully boot and connect to the database.
curl -X POST http://localhost:8080/api/v1/payments \
-H "Content-Type: application/json" \
-d '{
"merchantId": "merch_001",
"amount": 100.50,
"currency": "EUR",
"idempotencyKey": "unique-order-abc-123"
}'Response:
{
"id": 1,
"status": "COMPLETED",
"transactions": [
{
"providerId": "MOCK_STRIPE",
"providerTransactionId": "ch_8aad3b41...",
"status": "SUCCESS"
}
]
}Running the exact same curl command again will return the identical id: 1 response without creating a new database entry or hitting the mock provider again.
curl -X POST http://localhost:8080/api/v1/payments \
-H "Content-Type: application/json" \
-d '{"merchantId": "merch_001", "amount": 80.00, "currency": "GBP", "idempotencyKey": "unique-order-gbp-456"}'To test the HMAC signature verification:
curl -X POST http://localhost:8080/api/v1/webhooks/stripe \
-H "X-Webhook-Signature: fake_signature" \
-d '{"status": "SUCCESS"}'PAYLOAD='{"providerTransactionId": "ch_123", "status": "SUCCESS"}'
SECRET="wallee_super_secret_webhook_key_12345"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
curl -X POST http://localhost:8080/api/v1/webhooks/stripe \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: $SIGNATURE" \
-d "$PAYLOAD"src/main/java/com/wallee/mock/payment_gateway/
├── controller/ # REST API endpoints (Payments & Webhooks)
├── dto/ # Data Transfer Objects for incoming requests
├── enums/ # Strict state machines (OrderStatus, TransactionStatus)
├── model/ # JPA/Hibernate Entities with relational mapping
├── repository/ # Spring Data JPA interfaces
├── routing/ # Apache Camel RouteBuilder (Content-Based Router)
└── service/ # Core business logic (Idempotency checks, orchestration)