API: Payments
Relevant source files
The following files were used as context for generating this wiki page:The Payments API is a core component of the e-commerce platform, responsible for handling all financial transactions related to orders. It is implemented as a dedicated microservice (payment-app) that communicates with the rest of the system via the API Gateway and a NATS message broker. Its primary functions include initiating payment processes for different methods, verifying payment completion, and handling external notifications from payment gateways.
This module supports two main payment methods: Cash on Delivery (COD) and online bank transfer via the SePay gateway. The system is designed to be extensible for future payment integrations.
Architecture
The payment system follows a microservice architecture. The API Gateway exposes the payment endpoints to the client. Requests are then forwarded as messages over NATS to the payment-app microservice, which contains the core business logic. The payment-app interacts with its own PostgreSQL database via Prisma and also communicates with the order-app to fetch order details and update order statuses.
The following diagram illustrates the high-level architecture of the payment flow.
API Endpoints
The following endpoints are exposed by the API Gateway for payment operations.
| Method | Endpoint | Description |
|---|---|---|
POST | /payments/process | Initiates a payment for an order. Supports COD and SEPAY methods. |
POST | /payments/verify | Verifies a payment after a client-side redirect from a payment gateway. (Not used by SePay webhook). |
POST | /payments/confirm-cod/:orderId | Confirms a COD payment has been received (e.g., by a shipper). This updates the payment status to PAID. |
POST | /payments/webhook/sepay | Receives asynchronous webhook notifications from the SePay gateway to confirm transactions. |
GET | /payments/order/:orderId | Retrieves the payment details associated with a specific order ID. |
GET | /payments/:id | Retrieves payment details by its unique payment ID. |
Sources: apps/gateway/src/payments/payments.controller.ts:13-77, postman-collection.json
Data Models and Types
The payment system uses several DTOs (Data Transfer Objects) and type definitions for structuring data across services.
Enums
| Enum | Values | Description |
|---|---|---|
PaymentMethod | COD, SEPAY | The available methods of payment. |
PaymentStatus | UNPAID, PAID | The status of a payment transaction. |
Sources: libs/shared/types/payment.types.ts:46-54
Core DTOs
PaymentProcessDto
Used to initiate a payment.
| Field | Type | Description |
|---|---|---|
orderId | string | The ID of the order to be paid for. |
method | PaymentMethod | The chosen payment method (COD or SEPAY). |
amountInt | number | The total amount in the smallest currency unit (cents). |
Sources: libs/shared/dto/payment.dto.ts:9-21
SePayWebhookDto
Used to validate incoming webhook data from the SePay gateway.
| Field | Type | Description |
|---|---|---|
id | number | The unique ID of the transaction from SePay. |
content | string | Transaction description, expected to contain the order ID (e.g., "Thanh toan DH123"). |
transferType | 'in' | 'out' | The direction of the transfer. Only 'in' is processed. |
transferAmount | number | The amount transferred. |
referenceCode | string | SePay's reference code for the transaction. |
Sources: libs/shared/dto/payment.dto.ts:37-88
Response Types
PaymentProcessResponse
The response after a payment is processed.
| Field | Type | Description |
|---|---|---|
paymentId | string | The unique ID of the created payment record. |
status | PaymentStatus | The initial status of the payment (UNPAID). |
paymentUrl | string? | The URL for the SePay QR code image, if the method is SEPAY. |
message | string? | A descriptive message about the result. |
Sources: libs/shared/types/payment.types.ts:21-28
Core Payment Flows
1. Processing a New Payment
This flow is initiated when a user proceeds to checkout and selects a payment method. The client sends a request to POST /payments/process.
The sequence diagram below shows the interactions for both SEPAY and COD methods.
This diagram shows the payment processing flow, including validation against the order service and handling of different payment methods.
Sources: apps/gateway/src/payments/payments.controller.ts:33-36, apps/payment-app/src/payments/payments.service.spec.ts:91-143
For SEPAY payments, the paymentUrl is constructed using environment variables:
SEPAY_ACCOUNT_NUMBERSEPAY_BANK_NAMEACCOUNT_NAME
The URL format is: https://qr.sepay.vn/img?acc=...&bank=...&amount=...&des=...
Sources: apps/payment-app/src/payments/payments.service.spec.ts:138-141, apps/payment-app/src/payments/payments.service.spec.ts:200-234
2. SePay Webhook Handling
When a customer completes a bank transfer, SePay sends an asynchronous POST request to the /payments/webhook/sepay endpoint. The payment-app then processes this notification to update the payment and order status.
This diagram illustrates how the system handles incoming webhooks from SePay, including duplicate checks and updating payment/order statuses.
Sources: apps/gateway/src/payments/payments.controller.ts:21-25, apps/payment-app/src/payments/payments.service.spec.ts:439-536
3. Confirming a COD Payment
Cash on Delivery (COD) payments are initially marked as UNPAID. Once the delivery is complete and cash is collected, a shipper or admin must confirm the payment via the POST /payments/confirm-cod/:orderId endpoint.
This diagram shows the flow for an authorized user to confirm a COD payment, which transitions its status to PAID.
Sources: apps/gateway/src/payments/payments.controller.ts:50-55, apps/payment-app/src/payments/payments.service.spec.ts:538-641
Summary
The Payments API provides a robust and decoupled system for managing order payments. By leveraging a dedicated microservice and a message broker, it isolates payment logic from other parts of the application. It effectively handles different payment workflows, including immediate online payments via SePay and deferred confirmation for COD, ensuring that order and payment statuses remain synchronized throughout the process.