FishPay is a production-oriented payment management infrastructure built using Java, Spring Boot, PostgreSQL, Razorpay, and Docker that enables businesses to integrate a complete payment management system without investing significant development time or dealing with the complexities involved in building one from scratch.
The system manages the complete payment lifecycle, including payment processing, payment verification, webhook reconciliation, invoice generation, refund management, transaction history, and analytics through reusable REST APIs.
Although FishPay currently integrates with Razorpay, its modular architecture allows future support for multiple payment gateways such as Stripe, PayPal, PayU, and others with minimal architectural changes.
- Order Creation
- Payment Verification
- Payment History
- Transaction Tracking
- Automatic Invoice Generation
- Invoice History
- PDF Download
- Refund Processing
- Refund Status
- Refund History
- Payment Reconciliation
- Refund Synchronization
- Async Invoice Generation
- Fast Payment Confirmation
- Backend Pagination
- Dockerized Backend
- PostgreSQL
- RESTful APIs
FishPay follows a modular payment workflow where payment requests are securely processed through Razorpay, verified using cryptographic signature validation, persisted in PostgreSQL, and integrated with asynchronous invoice generation, refund management, and webhook-based reconciliation.
π https://miro.com/app/board/uXjVHcgkeag=/?moveToWidget=3458764678553613549&cot=14
| Stage | Time |
|---|---|
| Signature Verification | ~50 ms |
| Payment Persistence | ~100 ms |
| Success Response | < 750 ms |
| Invoice Generation (Async) | Background |
| Cloudinary Upload | Background |
| Invoice URL Persistence | Background |
Unlike a simple payment gateway integration, FishPay addresses several real-world backend engineering challenges commonly encountered in payment systems.
Initially, the payment verification API performed every operation synchronously.
Verify Signature
β
Save Payment
β
Generate Invoice PDF
β
Upload to Cloudinary
β
Save Invoice URL
β
Return Response
Since PDF generation and cloud upload are expensive operations, the client had to wait approximately 3 seconds before receiving payment confirmation.
Invoice generation was moved into an asynchronous background task.
Verify Signature
β
Save Payment
β
Return Success Response
β
ββββββββ Background Thread ββββββββ
Generate Invoice
β
Upload to Cloudinary
β
Update invoiceUrl
β Payment confirmation reduced from approximately 3 seconds to under 1 second while maintaining eventual consistency.
Frontend responses cannot always be trusted as the single source of truth because network failures or application crashes may occur after payment completion.
Implemented secure Razorpay Webhook integration that verifies webhook signatures and automatically reconciles payment and refund events.
Supported events include:
- payment.captured
- payment.failed
- refund.processed
- order.paid
This guarantees database consistency even if the frontend never reports the payment outcome.
Sometimes Razorpay sends the webhook before the payment record is inserted into PostgreSQL.
Without handling this race condition, webhook processing would fail.
Implemented retry-based reconciliation logic that repeatedly searches for the payment before processing the webhook.
This ensures eventual consistency between asynchronous systems.
Instead of only creating refund records, FishPay synchronizes refund status across multiple entities.
Refund Created
β
PENDING
β
PROCESSING
β
PROCESSED
β
Payment.refunded = true
This keeps both Payment and Refund records synchronized automatically.
Invoice generation was intentionally separated from payment confirmation.
Background pipeline:
Payment Success
β
Async Task
β
Generate PDF
β
Upload to Cloudinary
β
Persist invoiceUrl
This significantly improves checkout experience while preserving complete invoice generation.
Instead of loading entire datasets, FishPay uses backend pagination for:
- Payments
- Invoices
- Refunds
allowing efficient handling of large transaction histories.
The backend is fully containerized using Docker, making deployments reproducible across development, staging, and production environments.
FishPay_Backend/
β
βββ src/main/java/com/fishpay
β
βββ config/
β βββ RazorpayConfig.java
β βββ SecurityConfig.java
β βββ CloudinaryConfig.java
β βββ AsyncConfig.java
β
βββ controllers/
β βββ PaymentController.java
β βββ InvoiceController.java
β βββ RefundController.java
β βββ WebhookController.java
β βββ HealthController.java
β
βββ service/
β βββ PaymentService.java
β βββ InvoiceService.java
β βββ RefundService.java
β βββ WebhookService.java
β βββ AsyncInvoiceService.java
β βββ CloudinaryService.java
β
βββ repository/
β βββ PaymentRepository.java
β βββ InvoiceRepository.java
β βββ InvoiceItemRepository.java
β βββ RefundRepository.java
β
βββ entity/
β βββ Payment.java
β βββ Invoice.java
β βββ InvoiceItem.java
β βββ Refund.java
β
βββ dto/
β βββ CreateOrderRequest.java
β βββ VerifyPaymentRequest.java
β βββ VerifyPaymentResponse.java
β βββ InvoiceHistoryResponse.java
β βββ RefundRequest.java
β βββ RefundResponse.java
β βββ RefundHistoryResponse.java
β βββ PaymentHistoryResponse.java
β βββ ...
β
βββ util/
β βββ RazorpaySignatureUtil.java
β βββ InvoiceGenerator.java
β βββ RefundStatus.java
β βββ PaymentStatus.java
β
βββ exception/
β
βββ FishpayApplication.java
β
βββ src/main/resources/
β βββ application.yml
β βββ ...
β
βββ Dockerfile
βββ pom.xml
βββ README.md
The backend follows production-standard layered architecture.
Controller
β
Service
β
Repository
β
Hibernate / JPA
β
PostgreSQL
This separation improves maintainability, scalability, testing, and code organization.
Merchant Application
β
βΌ
REST Controllers
β
βΌ
Service Layer
β
ββββββββ΄βββββββββββ
βΌ βΌ
PostgreSQL Razorpay APIs
β
βΌ
Razorpay Webhooks
β
βΌ
Webhook Reconciliation
β
βΌ
Payment Synchronization
β
βΌ
Invoice / Refund Modules
- Java 24
- Spring Boot 3.5.x
- Spring Web
- Spring Security
- Spring Data JPA
- Hibernate ORM
- Maven
- PostgreSQL
- Razorpay Java SDK
- Cloudinary
- Docker
- REST APIs
- Environment Variables
- Jackson
- BigDecimal
- Pageable
- JPA Repository
- Hibernate
- Async Processing (
@Async)
