Create Order Endpoint
Relevant source files
The following files were used as context for generating this wiki page:
The Create Order endpoint is the primary mechanism for initiating a payment transaction with the ZaloPay gateway. It receives order details from a client, constructs a request for ZaloPay's API, and returns a payment URL that the client can use to complete the transaction. This process involves generating a unique transaction ID, creating a cryptographic signature (MAC), and communicating directly with the ZaloPay service.
The overall system is a simple Go application that exposes an API to interact with ZaloPay. The server is initialized in main.go, which sets up the configuration, services, and API routes.
Sources: main.go:12-25, api/api.go, services/order.go
API Endpoint
The endpoint is exposed via a POST request to /order/create.
- Method:
POST - Path:
/order/create - Handler:
orderAPI.CreateOrder
This route is defined within the NewAPI function, which sets up the Gin router and groups the order-related endpoints under the /order path.
// File: api/api.go:10-13
func (api *API) setupRouter() {
orderAPI := NewOrderAPI(api.orderService)
api.router.POST("/order/create", orderAPI.CreateOrder)
}
Sources: api/api.go:10-13
Data Flow and Sequence
The creation of a ZaloPay order follows a clear sequence, starting from the client's request to the final response containing the payment URL.
The following sequence diagram illustrates the interaction between the client, the API server, the order service, and the ZaloPay payment gateway.
Request and Response
Request Body
The client must send a JSON object with the amount for the order.
| Parameter | Type | Description | Example |
|---|---|---|---|
amount | int | The total order amount. | 50000 |
This is defined by the CreateOrderRequest struct in the order.go API handler.
// File: api/order.go:8-10
type CreateOrderRequest struct {
Amount int `json:"amount"`
}
Sources: api/order.go:8-10
Response Body
Upon successful creation, the API returns a JSON object containing the order_url and zp_trans_token from ZaloPay.
{
"return_code": 1,
"return_message": "success",
"order_url": "https://sandbox.zalopay.com.vn/spa/v2/payment?token=...",
"zp_trans_token": "...",
"app_trans_id": "..."
}
The structure of the response is the direct pass-through of the response from the ZaloPay gateway.
Sources: api/order.go:24, payment/zalopay.go:48-50
Core Logic
Order Service
The OrderService acts as an intermediary between the API handler and the payment gateway. Its primary responsibility is to orchestrate the order creation process.
- It receives the
amountfrom the API layer. - It generates a unique transaction ID (
app_trans_id) for the order. The format isyyMMdd_randomstring. - It calls the
CreateOrdermethod on theZaloPayGateway, passing the amount and the newly generated transaction ID.
// File: services/order.go:11-20
func (s *orderService) CreateOrder(amount int) (map[string]interface{}, error) {
// Generate app_trans_id
appTransID, err := common.GenerateAppTransID()
if err != nil {
return nil, err
}
// Call ZaloPay to create an order
return s.zaloPay.CreateOrder(amount, appTransID)
}
Sources: services/order.go:11-20
ZaloPay Gateway
The payment.ZaloPayGateway contains the most critical logic for interacting with the ZaloPay API.
HMAC Signature Generation
A crucial step is creating an HMAC (Hash-based Message Authentication Code) signature to authenticate the request. The signature is generated using the HMAC-SHA256 algorithm with key1 from the configuration.
The data string for the HMAC is a concatenation of several fields, separated by |:
appid|apptransid|appuser|amount|apptime|embeddata|item
This logic is implemented in the CreateOrder method of the zalopay gateway.
This diagram shows the process of creating the HMAC signature and sending the request.
Sources: payment/zalopay.go:30-32
Request to ZaloPay
After generating the signature, the gateway sends a POST request to the CreateOrderURL specified in the configuration. The body of the request is a form-urlencoded payload containing all the required parameters, including the generated mac.
// File: payment/zalopay.go:21-46
func (z *zaloPay) CreateOrder(amount int, appTransID string) (map[string]interface{}, error) {
// ... (setup)
data := fmt.Sprintf("%v|%v|%v|%v|%v|%v|%v", z.cfg.AppID, appTransID, "user123", amount, appTime, embedData, items)
mac := common.NewHMAC(z.cfg.Key1, data)
body := url.Values{}
body.Add("app_id", z.cfg.AppID)
// ... (add other fields)
body.Add("mac", mac)
// ... (http.PostForm call)
}
Sources: payment/zalopay.go:21-46
Configuration
The application relies on several configuration values to connect to ZaloPay. These are loaded from a config.yml file and stored in a struct.
| Parameter | Description | Source File |
|---|---|---|
AppID | The application ID provided by ZaloPay. | config/config.go:10 |
Key1 | The first key, used for HMAC generation. | config/config.go:11 |
Key2 | The second key, used for callback validation (not in this flow). | config/config.go:12 |
CreateOrderURL | The ZaloPay API endpoint for creating orders. | config/config.go:13 |
// File: config/config.go:9-14
type ZaloPay struct {
AppID string `yaml:"app_id"`
Key1 string `yaml:"key1"`
Key2 string `yaml:"key2"`
CreateOrderURL string `yaml:"create_order_url"`
}
Sources: config/config.go:9-14