Day 3 of Building an Offline UPI Payment System with Spring Boot Today I implemented idempotency in the payment flow using a unique requestId, while also studying the importance of concurrency handling in payment systems. What was added: • Duplicate payment requests are detected and blocked • Prevents double debit during retries or network interruptions • Proper 409 CONFLICT response handling • Custom exception flow for cleaner API behavior • Initial understanding of how concurrent duplicate requests can impact transactions Why this matters: In payment systems, retries and simultaneous requests are common. Without idempotency and concurrency safeguards, the same transaction can be processed multiple times. Current implementation works, but there is room to improve: Areas of improvement: • Return the original transaction response instead of only throwing duplicate error • Strengthen concurrent request handling with DB constraints / locking strategies • Add request payload validation for reused requestId • Introduce expiry/cleanup strategy for old idempotency keys • Improve observability with logs and audit trails Next step: I’ll be upgrading this into a more production-ready payment flow by improving concurrency safety and returning previous transaction state on retries. Built with: -Spring Boot -Spring Data JPA -H2 -REST APIs -Java Reliable backend systems are built by handling retries, race conditions, and edge cases not just successful requests. #Java #SpringBoot #BackendEngineering #Concurrency #Payments #SystemDesign #RESTAPI #SoftwareEngineering #LearningInPublic #Fintech
Implementing Idempotency in Spring Boot Payment System
More Relevant Posts
-
Why idempotency saved us from duplicate financial transactions 💳 One thing you learn quickly in real-time payment systems: Retries are not optional. Duplicates are dangerous. Recently ran into a scenario where a payment API was being retried due to intermittent network timeouts. From the client side, it looked simple: “Request failed → retry” But on the backend, that retry could have resulted in duplicate transactions — which is unacceptable in financial systems. 🔍 What actually happens under the hood: 1️⃣ Client sends payment request 2️⃣ Backend successfully processes the payment 3️⃣ Response times out due to network issues 4️⃣ Client retries the same request 5️⃣ Backend receives it again 👉 Now the system cannot tell: Is this a new payment or a retry of the same one? Without protection → 💥 duplicate charge -------- 💡 What is idempotency? Idempotency means: “No matter how many times you send the same request, the result remains the same.” --- 🛠️ What we implemented: • Introduced idempotency keys (unique per request) • Stored request state in Redis (PROCESSING / SUCCESS / FAILED) • Checked existing state before processing • Returned cached response for duplicate retries --- 🔁 How it works in practice: • First request → processed normally • Retry with same key → no reprocessing • Same response returned 👉 Client thinks retry succeeded 👉 System avoids duplicate transaction --- 🚀 Real impact: • Prevented duplicate financial transactions • Improved reliability during retries • Ensured consistent system behavior --- ⚠️ The hidden complexity: Idempotency is NOT just “check if request exists” It involves: • Handling partial failures (what if success but state not saved?) • Managing TTL (how long to keep keys?) • Handling concurrency (same request at same time) • Maintaining consistency across services --- 🧠 Key takeaway: In distributed systems: Failures are guaranteed Retries are inevitable. So your system must be: 👉 Safe to retry --- 📌 My biggest learning: The difference between a working system and a production-ready system is how it behaves when things go wrong. --- Curious — how are you handling idempotency in your systems? #SystemDesign #DistributedSystems #BackendEngineering #Payments #Microservices #Java #SpringBoot #TechInsights
To view or add a comment, sign in
-
-
Started building an offline-first UPI payment system in Java + Spring Boot. The core problem: digital payments fail when internet drops. Most solutions assume connectivity. This one doesn't. Day 1 focused on foundations- Account and Transaction models, initial settlement logic, REST APIs for testing, and H2 for rapid prototyping (PostgreSQL planned next for persistent storage and scale). But the more interesting work was defining the real engineering challenges: • How do you prevent the same payment from being processed twice when multiple relay devices forward it simultaneously? • How do you ensure an intercepted payment packet from yesterday cannot be replayed today? • How do you route payment data through untrusted devices without those devices being able to read it? None of that is implemented yet. But clear problem definition is exactly how Day 1 should end. #Java #SpringBoot #SystemDesign #FinTech #BuildInPublic #coding #springai
To view or add a comment, sign in
-
We had to switch payment gateways last year. The actual payment logic? Didn't change. Same amount, same customer, same order. What broke everything was this: Service A wanted different JSON format: Service B wanted different JSON format Same data. Completely different shape. And both want the amount in cents, not dollars. And both have their own status codes in the response — Service A returns "succeeded", Service B returns "captured" our service used 0 and 1. Both mean SUCCESS on our end. So we ended up with two DTOs, two mappers, and two places to break. I got tired of this and built a library that handles it differently. You just define the mapping once in a config file. Want to switch to Service A? Change one word. That's it. But the part I'm most happy with is transforms. The transforms handle the messy parts. Dollar to cents, status code normalization, phone masking — you register them once and reuse across every mapping. Works on the response side too. Their status codes map back to yours automatically. No new DTOs. No new mappers. Just a config file. I know this isn't a groundbreaking computer science problem, but it's the kind of thing that wastes hours every few months in almost every backend project I've seen. Built it in Spring Boot. Happy to share the repo if anyone wants to take a look or give feedback. Here is repo link if you want to use it: https://lnkd.in/geYginqf #Java #SpringBoot #Backend #OpenSource
To view or add a comment, sign in
-
Started Day 2 on my offline-first UPI payment system in Java + Spring Boot. Today’s focus was moving beyond basic money transfer APIs into something real products need: transaction history. Built a recent transactions endpoint that returns the last activity for a user instead of dumping raw database rows. Also started shaping responses through DTO mapping so customers only see relevant data like amount, status, counterparty, and transaction type (Sent / Received) — not internal fields. One underrated part of backend development: debugging response serialization, mapping layers, and edge cases often takes more effort than writing the endpoint itself. That’s where real learning happens. Current progress: ✅ Account creation API ✅ Payment transfer API ✅ Custom exception handling ✅ Transaction history feature in progress ✅ DTO-based response design Next steps: Finish transaction history cleanly Add timestamps JWT auth layer Idempotency for duplicate payment prevention PostgreSQL migration from H2 Building with a product mindset, not just CRUD. #Java #SpringBoot #BackendDevelopment #SystemDesign #FinTech #BuildInPublic #backenddev #SpringAI #SpringdataJPA #microservices
To view or add a comment, sign in
-
Day 6 — The Race Condition Bug Nobody talks about this in backend systems… Everything works perfectly… Until two users hit the same API at the same time. And suddenly: • Duplicate orders • Negative stock • Payment processed twice No errors. No crashes. Just silent data corruption. ⸻ 💥 The Problem Two threads access and modify shared data at the same time without proper control. Example: if (stock > 0) { stock–; } Looks correct, right? But under concurrency: Thread A reads stock = 1 Thread B reads stock = 1 Both decrement 👉 Final stock = -1 ⸻ ⚠️ Why it’s dangerous • Hard to reproduce (only happens under load) • Works fine in local testing • Fails silently in production • Direct impact on money and trust ⸻ ✅ The Fix Use proper concurrency control: • Optimistic locking (@Version) • Pessimistic locking (DB level) • Atomic operations • Synchronized blocks / locks • Idempotency for critical APIs ⸻ 🧠 Real lesson If your system handles payments, orders, or inventory… You’re already exposed to race conditions. It’s not “if” it will happen. It’s “when”. ⸻ 👇 Have you ever faced a race condition in production? What was your fix? ⸻ #Backend #Java #Microservices #SystemDesign #Concurrency #SpringBoot #CodingBugs #TechLeadership
To view or add a comment, sign in
-
-
Deep Dive into Error Handling & Request Validation in Payment Systems I recently worked on designing a robust error handling and validation mechanism for a payment integration system (Stripe-based), and documented the complete approach in this PDF: Here’s what I explored and implemented: 🔹 Structured Error Handling in Spring Boot Clear separation of 2xx (success), 4xx (client), and 5xx (server) responses Custom exception (StripeProviderException) with HTTP status, error code, and message Global exception handling using @RestControllerAdvice for clean and consistent responses 🔹 Standardized Error Codes 10xxx → Validation layer 20xxx → Processing layer 30xxx → External provider (Stripe) Helps quickly identify where the failure occurred in a distributed system 🔹 Validation First Approach Dedicated ValidationService to validate requests before business logic Fail-fast mechanism using custom exceptions 🔹 Handling External API (Stripe) Scenarios ✅ Success responses (2xx) → parsed and mapped ⚠️ Client/Server errors (4xx/5xx) → structured error handling ❌ No response (timeouts, network issues) → handled using retry-ready exception strategy 🔹 Dynamic Error Message Construction Handling inconsistent error formats from Stripe Creating meaningful messages using: type | message | code | param 🔹 Clean Service Design Separation of concerns between: HTTP layer Validation layer Business logic Exception handling This project helped me understand how real-world systems handle failures gracefully, especially in payment integrations where reliability is critical. GitHub Repository: https://lnkd.in/dBcjJwEF Always open to feedback and discussions! 🙌 #Java #Spring #SpringBoot #BackendDevelopment #ErrorHandling #SystemDesign #RestAPI #APIDesign #FullStackDeveloper #PaymentIntegration
To view or add a comment, sign in
-
𝐖𝐡𝐚𝐭 𝐡𝐚𝐩𝐩𝐞𝐧𝐬 𝐢𝐟 𝐚 𝐩𝐚𝐲𝐦𝐞𝐧𝐭 𝐀𝐏𝐈 𝐢𝐬 𝐜𝐚𝐥𝐥𝐞𝐝 𝐭𝐰𝐢𝐜𝐞? Without proper handling, it could result in duplicate transactions. That’s where Idempotency comes in. An API is idempotent if making the same request multiple times produces the same result. In real-world systems like payments, we use Idempotency Keys. A unique key is sent with each request. If the same request is received again with the same key, the server returns the previous response instead of processing it again. This ensures: No duplicate transactions Safe retries during network failures Consistent system behavior Idempotency is critical for APIs that involve financial operations, order creation, or any non-repeatable action. Reliable systems are not just about handling success. They are about handling retries safely. 𝑯𝒂𝒗𝒆 𝒚𝒐𝒖 𝒆𝒗𝒆𝒓 𝒕𝒉𝒐𝒖𝒈𝒉𝒕 𝒂𝒃𝒐𝒖𝒕 𝒉𝒐𝒘 𝒅𝒖𝒑𝒍𝒊𝒄𝒂𝒕𝒆 𝒓𝒆𝒒𝒖𝒆𝒔𝒕𝒔 𝒂𝒓𝒆 𝒉𝒂𝒏𝒅𝒍𝒆𝒅 𝒊𝒏 𝒃𝒂𝒄𝒌𝒆𝒏𝒅 𝒔𝒚𝒔𝒕𝒆𝒎𝒔? #Java #BackendDevelopment #APIDesign #SystemDesign #Microservices
To view or add a comment, sign in
-
-
🚀 Excited to share my progress on my Banking Application project! I started this project as a simple console-based application, and now I’ve successfully upgraded it into a REST API-based backend system using Spring Boot & JPA. 🔧 What I’ve implemented so far: 💳 Account Management Create Account Fetch All Accounts Get Account by Account Number 💰 Transactions Deposit Money Withdraw Money (with insufficient balance handling) Transfer Money between accounts (with transactional safety) 📊 Transaction History Built a separate Transaction module Used JPA relationships (@ManyToOne) Implemented clean DTO-based response Added automatic timestamp using @CreationTimestamp 🧠 Key Learnings: How REST APIs work in real backend systems Importance of DTOs over entities JPA relationships and database design Handling real-world scenarios like balance validation and transactions 🔜 What’s next? Adding Spring Security 🔐 Role-based authentication Making the project production-ready This journey from console app → REST API has been a great learning experience 🚀 #Java #SpringBoot #BackendDevelopment #JPA #RESTAPI #LearningInPublic #SoftwareDevelopment
To view or add a comment, sign in
-
🚀 Built a Secure Payment API using Spring Boot & HmacSHA256 Authentication Today I implemented a mini project to understand how secure communication works between external systems and backend services. In this project, I designed a Spring Boot API where incoming payment requests are verified using HmacSHA256 signatures before reaching the controller layer. 🔹 Implemented a custom HmacFilter using Spring Security 🔹 Added ExceptionHandlerFilter to manage filter-level errors 🔹 Verified request integrity using HmacSHA256 signature validation 🔹 Explored how Spring Security Filter Chain works internally 🔹 Debugged request flow using breakpoints to understand filter execution Request Flow: Client → ExceptionHandlerFilter → HmacFilter → PaymentController This hands-on implementation helped me deeply understand: ✔ API authentication mechanisms ✔ Spring Security filter architecture ✔ Handling exceptions outside controllers Excited to continue exploring backend security patterns and building scalable microservices using Java & Spring Boot. #Java #SpringBoot #SpringSecurity #BackendDevelopment #JavaDeveloper #LearningInPublic
To view or add a comment, sign in
-
-
🚨 Duplicate requests can break your system Real scenario: Payment API was called twice due to network retry 💥 Result: Double payment 😬 ✅ Solution: Implemented idempotency - Used unique request ID - Stored request state in DB 💡 Takeaway: APIs should be safe for retries. Especially for payments, orders, critical operations. #Java #SpringBoot #BackendDevelopment #SoftwareEngineering #Microservices #JPA #RESTAPI #DeveloperLife #CareerGrowth
To view or add a comment, sign in
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development