Payment Request and Callback Flow
Relevant source files
The following files were used as context for generating this wiki page:This document outlines the technical implementation of the ZaloPay payment integration, focusing on the two primary processes: creating a payment request and handling the subsequent payment confirmation callback from ZaloPay. The system exposes API endpoints to initiate payments and receive status updates, using HMAC signatures to secure the communication with the ZaloPay service.
The entire flow is orchestrated through a Go application using the Gin web framework. The core logic is separated into API handlers for routing and service layers for business logic, with dedicated packages for cryptographic functions.
System Configuration
The application's behavior is controlled by a central configuration file, config.json. This file stores essential credentials and endpoints required to communicate with the ZaloPay API.
| Parameter | Description |
|---|---|
app_id | The application ID provided by ZaloPay. |
key1 | The secret key used to generate the HMAC signature for creating orders. |
key2 | The secret key used to verify the HMAC signature of incoming callbacks. |
endpoint | The URL of the ZaloPay API endpoint for creating payment orders. |
Sources: config.json, services/order.go:19-22
Payment Creation Flow
The payment creation process is initiated by a client request to the application's backend. The backend then constructs a signed request and sends it to ZaloPay to generate a payment order and a corresponding payment URL.
This diagram illustrates the sequence of events for creating a new payment order.
Sources: api/handler.go:17-27, services/order.go:14-61
API Endpoint: POST /api/create-order
This is the main endpoint for initiating a payment. It is responsible for calling the underlying order service that communicates with ZaloPay.
- Route:
/api/create-order - Method:
POST - Handler:
api.CreateOrder
The route is registered in main.go and defined in api/api.go.
Sources: main.go:16, api/api.go:7, api/handler.go:17-27
Order Creation Logic
The core logic resides in the services/order.go file. The CreateOrder function performs the following steps:
- Transaction ID Generation: A unique transaction ID (
app_trans_id) is created. The format isyyMMdd_followed by a unique identifier. - Parameter Assembly: A map of parameters required by the ZaloPay API is constructed.
- HMAC Signature Generation: A signature (
mac) is generated to ensure data integrity.- A specific string is constructed by concatenating several parameters with
|as a separator:app_id|app_trans_id|app_user|amount|app_time|embed_data|item. - This string is then hashed using HMAC-SHA256 with
key1from the configuration.
- A specific string is constructed by concatenating several parameters with
- API Request: A
POSTrequest containing the parameters and the generatedmacsignature is sent to the ZaloPay endpoint. - Response Handling: The response from ZaloPay is parsed. If successful, the
order_urlis extracted and returned to the client, which can then redirect the user to this URL to complete the payment.
Sources: services/order.go:14-61, crypto/hmac.go:7-10
The following table details the key parameters sent to the ZaloPay create order API.
| Parameter | Description | Source Value |
|---|---|---|
app_id | The application ID. | config.app_id |
app_trans_id | Unique transaction ID for the order in the merchant's system. | fmt.Sprintf("%s_%s", time.Now().Format("060102"), "123456") (example) |
app_user | The user initiating the payment. | "user123" (hardcoded) |
app_time | Transaction timestamp in milliseconds. | common.GetAppTime() |
amount | The transaction amount. | 50000 (hardcoded) |
item | A JSON string representing the items in the cart. | [] (hardcoded empty array) |
embed_data | A JSON string for extra data. The callback URL is often included here. | {"redirecturl": "https://google.com"} (hardcoded) |
description | A description of the transaction. | fmt.Sprintf("ZaloPay Integration Demo - #%s", apptransid) |
bank_code | Code of the bank or payment method. | "zalopayapp" (hardcoded) |
mac | The HMAC-SHA256 signature of the concatenated data string, generated using key1. | crypto.HMACSha256(data, config.key1) |
Sources: services/order.go:28-45
Payment Callback Flow
After the user completes the payment on ZaloPay's platform, ZaloPay sends a server-to-server POST request to the callback URL configured by the merchant. This callback informs the application about the final status of the transaction.
This diagram shows the callback verification process.
Sources: api/handler.go:29-66
API Endpoint: POST /api/callback
This endpoint is designed to receive asynchronous notifications from ZaloPay.
- Route:
/api/callback - Method:
POST - Handler:
api.Callback
Sources: main.go:17, api/api.go:8, api/handler.go:29-66
Callback Handling Logic
The api.Callback handler is responsible for processing incoming notifications. Its primary responsibility is to verify the authenticity of the callback before processing the data.
- Data Parsing: The handler parses the incoming JSON request body, which is expected to contain
data(a JSON string) and amac(the signature). - Signature Verification:
- The handler computes a new HMAC-SHA256 signature using the
datastring from the payload andkey2from the configuration. - This newly generated signature is compared with the
macvalue received in the callback. - If the signatures do not match, the callback is considered invalid, and an error response is sent back to ZaloPay.
- The handler computes a new HMAC-SHA256 signature using the
- Business Logic: If the signature is valid, the
datastring (which itself is a JSON object containing transaction details) is parsed. The application should then update the order status in its database based on this information. The current implementation logs the data but does not perform a database update. - Acknowledgement: The handler sends a JSON response back to ZaloPay to acknowledge receipt of the callback. A
return_codeof1indicates success, while other values indicate failure.
Sources: api/handler.go:29-66, crypto/hmac.go:7-10
The following table shows the expected response format for acknowledging a ZaloPay callback.
| Field | Type | Description |
|---|---|---|
return_code | int | 1 for success, non-1 for failure. |
return_message | string | A message describing the result (e.g., "success"). |
Sources: api/handler.go:55-56, api/handler.go:63-64
Summary
The ZaloPay integration in this repository is built around two distinct but connected flows. First, a client-initiated request to /api/create-order generates a signed request to ZaloPay, resulting in a payment URL for the user. Second, ZaloPay sends an asynchronous notification to the /api/callback endpoint to confirm the transaction status. Security and data integrity are maintained throughout this process by using separate HMAC-SHA256 keys (key1 for outgoing requests and key2 for incoming callbacks).