Chọn mô hình tích hợp ZaloPay phù hợp
ZaloPay tiếp nhận thông tin đơn hàng từ Merchant bằng cách redirect sang ZaloPay Gateway

Khi Merchant Server gọi request tạo đơn hàng cho ZaloPay Server, ZaloPay Server sẽ trả về một đoạn link chuyển tiếp đã được build sẵn gọi là orderurl, Merchant sử dụng orderurl này để redirect người dùng đến trang cổng thanh toán ZaloPay.
Ví dụ:
{
  "returncode": 1,
  "returnmessage": "Thành công",
  "orderurl":"https://qcgateway.zalopay.vn/openinapp?order=eyJ6cHRyYW5zdG9rZW4iOiJ4dGd1SEs1YnU0VDJkSHE3TUFwTFFnIiwiYXBwaWQiOjN9"
}
| bankcode | Kết quả hiển thị trên trang cổng thanh toán | 
|---|---|
Rỗng ("") (*) | 
Danh sách tất cả các hình thức và ngân hàng được hỗ trợ (CC, ATM, zalopayapp, ...) | 
zalopayapp | 
Hiển thị QR code để thanh toán bằng ví ZaloPay/ Mở ứng dụng ZaloPay để thanh toán qua ví đối với mobile | 
CC | 
Form nhập thông tin Credit Card | 
Mã ngân hàng ATM (VTB, VCB, ...) | 
Form nhập thông tin thẻ của ngân hàng tương ứng | 
Ví dụ:
embeddata={"bankgroup": "ATM"}
bankcode=""
Mặc định sẽ trả về danh sách tất cả các ngân hàng được ZaloPay hỗ trợ. Nếu muốn trả về danh sách theo yêu cầu thì phải đăng ký với ZaloPay.

| Environment | Method | Endpoint | 
|---|---|---|
| Sandbox | POST | https://sbgateway.zalopay.vn/api/getlistmerchantbanks | 
| Real | POST | https://gateway.zalopay.vn/api/getlistmerchantbanks | 
application/x-www-form-urlencoded| Tham số | Kiểu dữ liệu | Bắt buộc | Ý nghĩa | 
|---|---|---|---|
appid | 
String | ✔ | appid của merchant được cung cấp | 
reqtime | 
String | ✔ | • Thời điểm gọi api (unix timestamp in milisecond).  • Thời gian tính đến milisecond, và lấy theo current time.  | 
mac | 
String | ✔ | = HMAC(hmac_algorithm, key1, appid+"|"+reqtime) | 
| Tham số | Kiểu dữ liệu | Ý nghĩa | 
|---|---|---|
returncode | 
int | Mã lỗi | 
returnmessage | 
String | Thông tin lỗi | 
banks | 
Map(pmcid, List(bankdto)) | Danh sách các ngân hàng | 
Định dạng bankdto
| Tham số | Kiểu dữ liệu | Ý nghĩa | 
|---|---|---|
bankcode | 
String | Mã ngân hàng | 
name | 
String | Tên ngân hàng | 
displayorder | 
int | Thứ tự sắp xếp | 
pmcid | 
int | |
minamount | 
long | Số tiền thanh toán tối thiểu | 
maxamount | 
long | Số tiền thanh toán tối đa | 
Chú thích pmcid
| Giá trị | Tên gọi | 
|---|---|
36 | 
Visa/Master/JCB | 
37 | 
Bank Account | 
38 | 
ZaloPay | 
39 | 
ATM | 
41 | 
Visa/Master Debit | 
/**
 * .Net core 2.1.505
 */
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZaloPay.Helper; // HmacHelper, RSAHelper, HttpHelper, Utils (tải về ở mục DOWNLOADS)
using ZaloPay.Helper.Crypto;
using Newtonsoft.Json; // https://www.newtonsoft.com/json
namespace ZaloPayExample
{
    class Program
    {
        static string appid = "553";
        static string key1 = "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q";
        static string getBankListUrl = "https://sbgateway.zalopay.vn/api/getlistmerchantbanks";
        class BankDTO {
            public string bankcode { get; set; }
            public string name { get; set; }
            public int displayorder { get; set; }
            public int pmcid { get; set; }
        }
        class BankListResponse {
            public string returncode { get; set; }
            public string returnmessage { get; set; }
            public Dictionary<string, List<BankDTO>> banks { get; set; }
        }
        static async Task Main(string[] args)
        {
            var reqtime = Utils.GetTimeStamp().ToString();
            Dictionary<string, string> param = new Dictionary<string, string>();
            param.Add("appid", appid); 
            param.Add("reqtime", reqtime); 
            param.Add("mac", HmacHelper.Compute(ZaloPayHMAC.HMACSHA256, key1, appid+"|"+reqtime));
            var result = await HttpHelper.PostFormAsync<BankListResponse>(getBankListUrl, param);
            Console.WriteLine("returncode = {0}", result.returncode);
            Console.WriteLine("returnmessage = {0}", result.returnmessage);
            foreach(var entry in result.banks) {
                var pmcid = entry.Key;
                var banklist = entry.Value;
                foreach(var bank in banklist) {
                    Console.WriteLine("{0}. {1} - {2}", pmcid, bank.bankcode, bank.name);
                }
            }
        }
    }
}
// Java version "1.8.0_201"
import org.apache.http.NameValuePair; // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONObject; // https://mvnrepository.com/artifact/org.json/json
import org.json.JSONArray;
import vn.zalopay.crypto.HMACUtil; // tải về ở mục DOWNLOADS
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class GetBankList {
    private static Map<String, String> config = new HashMap<String, String>(){{
        put("appid", "553");
        put("key1", "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q");
        put("key2", "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3");
        put("endpoint", "https://sbgateway.zalopay.vn/api/getlistmerchantbanks");
    }};
    public static void main(String[] args) throws Exception {
        String appid = config.get("appid");
        String reqtime = Long.toString(System.currentTimeMillis());
        String data = appid +"|"+ reqtime;
        String mac = HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, config.get("key1"), data);
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("appid", appid));
        params.add(new BasicNameValuePair("reqtime", reqtime)); // miliseconds
        params.add(new BasicNameValuePair("mac", mac));
        URIBuilder uri = new URIBuilder(config.get("endpoint"));
        uri.addParameters(params);
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet get = new HttpGet(uri.build());
        CloseableHttpResponse res = client.execute(get);
        BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent()));
        StringBuilder resultJsonStr = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            resultJsonStr.append(line);
        }
        JSONObject result = new JSONObject(resultJsonStr.toString());
        JSONObject banksObject = result.getJSONObject("banks");
        System.out.format("returncode = %s", result.getInt("returncode"));
        System.out.format("returnmessage = %s", result.getString("returnmessage"));
        for(String pmcid : banksObject.keySet()) {
            JSONArray banks = banksObject.getJSONArray(pmcid);
            banks.forEach(bank -> {
                System.out.format("%s. %s\n", pmcid, bank.toString());
            });
        }
    }
}
// go version go1.11.1 linux/amd64
package main
import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "strconv"
    "time"
    "github.com/zpmep/hmacutil" // go get github.com/zpmep/hmacutil
)
var (
    appid = "553"
    key1  = "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q"
    key2  = "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3"
)
func main() {
    params := make(url.Values)
    params.Add("appid", "553")
    params.Add("reqtime", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)) // miliseconds
    data := fmt.Sprintf("%v|%v", params.Get("appid"), params.Get("reqtime")) //appid|reqtime
    params.Add("mac", hmacutil.HexStringEncode(hmacutil.SHA256, key1, data))
    res, err := http.Get("https://sbgateway.zalopay.vn/api/getlistmerchantbanks?" + params.Encode())
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)
    var result map[string]interface{}
    if err := json.Unmarshal(body, &result); err != nil {
        log.Fatal(err)
    }
    for k, v := range result {
        log.Printf("%s = %+v", k, v)
    }
}
// Node v10.15.3
const axios = require('axios').default; // npm install axios
const CryptoJS = require('crypto-js'); // npm install crypto-js
const config = {
  appid: "553",
  key1: "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q",
  key2: "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3",
  endpoint: "https://sbgateway.zalopay.vn/api/getlistmerchantbanks"
};
let reqtime = Date.now();
let params = {
  appid: config.appid,
  reqtime: reqtime, // miliseconds
  mac: CryptoJS.HmacSHA256(config.appid + "|" + reqtime, config.key1).toString() // appid|reqtime
};
axios.get(config.endpoint, { params })
  .then(res => {
    let banks = res.data.banks;
    for (let id in banks) {
      let banklist = banks[id];
      console.log(id + ".");
      for (let bank of banklist) {
        console.log(bank);
      }
    }
  })
  .catch(err => console.error(err));
<?php
// PHP Version 7.3.3
$config = [
  "appid" => 553,
  "key1" => "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q",
  "key2" => "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3",
  "endpoint" => "https://sbgateway.zalopay.vn/api/getlistmerchantbanks"
];
$reqtime = round(microtime(true) * 1000); // miliseconds
$params = [
  "appid" => $config["appid"],
  "reqtime" => $reqtime,
  "mac" => hash_hmac("sha256", $config["appid"]."|".$reqtime, $config["key1"]) // appid|reqtime
];
$resp = file_get_contents($config["endpoint"]."?".http_build_query($params));
$result = json_decode($resp, true);
foreach ($result as $key => $value) {
  echo "$key: $value<br>";
}
# ruby 2.5.1p57
require 'json'
require 'openssl' # gem install openssl
require 'net/http'
config = {
  appid: '553',
  key1: '9phuAOYhan4urywHTh0ndEXiV3pKHr5Q',
  key2: 'Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3',
  endpoint: 'https://sbgateway.zalopay.vn/api/getlistmerchantbanks'
}
params = {
  appid: config[:appid],
  reqtime: (Time.now.to_f.round(3) * 1000).to_i # miliseconds
}
data = config[:appid] +"|"+ params[:reqtime].to_s # appid|reqtime
params[:mac] = OpenSSL::HMAC.hexdigest('sha256', config[:key1], data) 
uri = URI(config[:endpoint])
uri.query = URI.encode_www_form(params)
res = Net::HTTP.get_response(uri)
result = JSON.parse(res.body)
puts "returncode: " + result["returncode"].to_s
puts "returnmessage: " + result["returnmessage"]
result["banks"].each do |pmcid, banklist|
  banklist.each do |bank|
    puts "#{pmcid}. #{bank}" 
  end
end
# coding=utf-8
# Python 3.6
from time import time
import hmac, hashlib, urllib.parse, urllib.request
config = {
  "appid": 553,
  "key1": "9phuAOYhan4urywHTh0ndEXiV3pKHr5Q",
  "key2": "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3",
  "endpoint": "https://sbgateway.zalopay.vn/api/getlistmerchantbanks"
}
reqtime = int(round(time() * 1000)) # miliseconds
data = "{}|{}".format(config["appid"], reqtime) # appid|reqtime
params = {
  "appid": config["appid"],
  "reqtime": reqtime,
  "mac": hmac.new(config['key1'].encode(), data.encode(), hashlib.sha256).hexdigest()
}
response = urllib.request.urlopen(url=config["endpoint"], data=urllib.parse.urlencode(params).encode())
result = json.loads(response.read())
print("returncode: {}".format(result["returncode"]))
print("returnmessage: {}".format(result["returnmessage"]))
for pmcid, banklist in result["banks"].items():
  for bank in banklist:
    print("{}. {}".format(pmcid, bank))
curl https://sbgateway.zalopay.vn/api/getlistmerchantbanks \
  -d appid=553 \
  -d reqtime=1555640370536 \
  -d mac=e2c88a751fc3862f79648e9524cf865ae05579b4435a74dae5992867c3b412ca
Sau khi người dùng hoàn thành thanh toán, ZaloPay Gateway sẽ redirect về trang hiển thị kết quả của Merchant (theo redirect_url Merchant đã cung cấp cho ZaloPay).
| Tham số | Kiểu dữ liệu | Ý nghĩa | 
|---|---|---|
appid | 
int | appid của đơn hàng | 
apptransid | 
String | apptransid của đơn hàng | 
pmcid | 
int | Kênh thanh toán | 
bankcode | 
String | Mã ngân hàng | 
amount | 
long | Giá trị của đơn hàng VND | 
discountamount | 
long | Giảm giá VND | 
status | 
int | Mã lỗi | 
checksum | 
String | Dùng để kiểm tra redirect có hợp lệ hay không. Kiểm tra hmac hợp lệ: HMAC(hmac_algorithm, key2, appid +"|"+ apptransid +"|"+ pmcid +"|"+ bankcode +"|"+ amount +"|"+ discountamount +"|"+ status) | 
/*
    ASP.Net core
*/
using Microsoft.AspNetCore.Mvc;
using ZaloPay.Helper; // HmacHelper, RSAHelper, HttpHelper, Utils (tải về ở mục DOWNLOADS)
using ZaloPay.Helper.Crypto;
namespace ZaloPayExample.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class RedirectController: ControllerBase
    {
        private string key2 = "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3";
        [HttpGet]
        public IActionResult Get()
        {
            var data = Request.Query;
            var checksumData = data["appid"] +"|"+ data["apptransid"] +"|"+ data["pmcid"] +"|"+ 
                data["bankcode"] +"|"+ data["amount"] +"|"+ data["discountamount"] +"|"+ data["status"]; 
            var checksum = HmacHelper.Compute(ZaloPayHMAC.HMACSHA256, key2, checksumData);
            if (!checksum.Equals(data["checksum"])) {
                return StatusCode(400, "Bad Request");
            }
            else {
                // kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
                return StatusCode(200, "OK");
            }
        }
    }
}
import org.json.JSONObject;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.util.Map;
import java.util.logging.Logger;
@Controller
public class RedirectController {
    private Logger logger = Logger.getLogger(this.getClass().getName());
    private String key2 = "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3";
    private Mac HmacSHA256;
    public RedirectController() throws Exception  {
        HmacSHA256 = Mac.getInstance("HmacSHA256");
        HmacSHA256.init(new SecretKeySpec(key2.getBytes(), "HmacSHA256"));
    }
    @GetMapping("/redirect-from-zalopay")
    public ResponseEntity redirect(@RequestParam Map<String, String> data) {
        String checksumData = data.get("appid") +"|"+ data.get("apptransid") +"|"+ data.get("pmcid") +"|"+ data.get("bankcode") +"|"+
                data.get("amount") +"|"+ data.get("discountamount") +"|"+ data.get("status");
        byte[] checksumBytes = HmacSHA256.doFinal(checksumData.getBytes());
        String checksum = DatatypeConverter.printHexBinary(checksumBytes).toLowerCase();
        JSONObject result = new JSONObject();
        if (!checksum.equals(data.get("checksum"))) {
            return ResponseEntity.badRequest().body("Bad Request");
        } else {
            // kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
            return ResponseEntity.ok("OK");
        }
    }
}
// go version go1.11.1 linux/amd64
package main
import (
    "fmt"
    "log"
    "net/http"
    "github.com/zpmep/hmacutil"
)
// App config
var (
    key2 = "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3"
)
func main() {
    mux := http.DefaultServeMux
    mux.HandleFunc("/redirect-from-zalopay", func(w http.ResponseWriter, r *http.Request) {
        r.ParseForm()
        data := r.Form
        checksumData := data.Get("appid") + "|" + data.Get("apptransid") + "|" + data.Get("pmcid") + "|" + data.Get("bankcode") + "|" + data.Get("amount") + "|" + data.Get("discountamount") + "|" + data.Get("status")
        checksum := hmacutil.HexStringEncode(hmacutil.SHA256, key2, checksumData)
        if checksum != data.Get("checksum") {
            w.WriteHeader(400)
            fmt.Fprint(w, "Bad Request")
        } else {
            // kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
            fmt.Fprint(w, "Ok")
        }
    })
    log.Println("Server is listening at port :8001")
    http.ListenAndServe(":8001", mux)
}
// Node v10.15.3
const CryptoJS = require('crypto-js');
const express = require('express');
const app = express();
const config = {
  key2: "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3"
};
app.get('/redirect-from-zalopay', (req, res) => {
  let data = req.query;
  let checksumData = data.appid + '|' + data.apptransid + '|' + data.pmcid + '|' + data.bankcode + '|' + data.amount + '|' + data.discountamount + '|' + data.status;
  let checksum = CryptoJS.HmacSHA256(checksumData, config.key2).toString();
  if (checksum != data.checksum) {
    res.sendStatus(400);
  } else {
    // kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
    res.sendStatus(200);
  }
});
app.listen(8001, function () {
  console.log('Server is listening at port :8001');
});
<?php
// PHP Version 7.3.3
$key2 = "Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3";
$data = $GET;
$checksumData = $data["appid"] ."|". $data["apptransid"] ."|". $data["pmcid"] ."|". $data["bankcode"] ."|". $data["amount"] ."|". $data["discountamount"] ."|". $data["status"];
$checksum = hash_hmac("sha256", $checksumData, $key2);
if (strcmp($mac, $data["checksum"]) != 0) {
  http_response_code(400);
  echo "Bad Request";
} else {
  // kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
  http_response_code(200);
  echo "Ok";
}
# ruby 2.5.1p57
# rails 5.2.3
# config/routes.rb
# Rails.application.routes.draw do
#   match '/redirect-from-zalopay' => 'redirect#handle', via: :get
# end
# app/controllers/redirect_controller.rb
require 'json'
require 'openssl'
class RedirectController < ApplicationController 
  def initialize
    super
    @config = {
      key2: 'Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3'
    }
  end
  # POST /callback
  def handle
    data = request.query_parameters
    checksumData = data["appid"] +"|"+ data["apptransid"] +"|"+ data["pmcid"] +"|"+ data["bankcode"] +"|"+ data["amount"] +"|"+ data["discountamount"] +"|"+ data["status"]
    checksum = OpenSSL::HMAC.hexdigest('sha256', @config[:key2], checksumData)
    if checksum != data['checksum']
      render text: 'Bad Request', status: :bad_request
    else
      # kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
      render text: 'OK', status: :ok
    end
  end
end
# coding=utf-8
# Python 3.6
from flask import Flask, request, json
import hmac, hashlib
app = Flask(__name__)
config = {
  'key2': 'Iyz2habzyr7AG8SgvoBCbKwKi3UzlLi3'
}
@app.route('/redirect-from-zalopay', methods=['GET'])
def redirect():
  data = request.args
  checksumData = "{}|{}|{}|{}|{}|{}|{}".format(data.get('appid'), data.get('apptransid'), data.get('pmcid'), data.get('bankcode'), data.get('amount'), data.get('discountamount'), data.get('status'))
  checksum = hmac.new(config['key2'].encode(), checksumData, hashlib.sha256).hexdigest()
  if checksum != data.get('checksum'):
    return "Bad Request", 400
  else:
    # kiểm tra xem đã nhận được callback hay chưa, nếu chưa thì tiến hành gọi API truy vấn trạng thái thanh toán của đơn hàng để lấy kết quả cuối cùng
    return "Ok", 200
if __name__ == '__main__':
  app.run(host='0.0.0.0', port=8001)