Select the appropriate model of ZaloPay integration
ZaloPay receives Merchant's order information by redirecting to ZaloPay Gateway
When the Merchant Server request to create an order to ZaloPay Server, ZaloPay Server will return a built-in link called orderurl
, Merchant use orderurl
to redirect the user to the ZaloPay Gateway page.
Example:
{
"returncode": 1,
"returnmessage": "Thành công",
"orderurl":"https://qcgateway.zalopay.vn/openinapp?order=eyJ6cHRyYW5zdG9rZW4iOiJ4dGd1SEs1YnU0VDJkSHE3TUFwTFFnIiwiYXBwaWQiOjN9"
}
bankcode | Results are displayed on the ZaloPay Gateway page |
---|---|
Empty ("" ) (*) |
List of payment methods and banks supported (CC , ATM , zalopayapp , ...) |
zalopayapp |
QR code to scan with ZaloPay App |
CC |
Form to input credit card information |
ATM bank code (VTB , VCB , ...) |
Form to input bank card information |
Example:
embeddata={"bankgroup": "ATM"}
bankcode=""
By default, API will return a list of all ZaloPay supported banks. If you want to return the custom list, you must register with 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
Parameter | Datatype | Required | Description |
---|---|---|---|
appid |
String | ✔ | appid provided by ZaloPay |
reqtime |
String | ✔ | • Time to call API (unix timestamp in millisecond). • Current time in milliseconds |
mac |
String | ✔ | = HMAC(hmac_algorithm, key1, appid+"|"+reqtime) |
Parameter | Datatype | Description |
---|---|---|
returncode |
int | Error code |
returnmessage |
String | Error detail |
banks |
Map(pmcid, List(bankdto)) | List of supported banks |
Bankdto format
Parameter | Datatype | Description |
---|---|---|
bankcode |
String | Bank code |
name |
String | Bank name |
displayorder |
int | Display order |
pmcid |
int | |
minamount |
long | Minimum payment amount |
maxamount |
long | Maximum payment amount |
Note about pmcid
Value | Name |
---|---|
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 (download at DOWNLOADS page)
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; // download at DOWNLOADS page
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
After the user has finished paying, they will be redirected to the Merchant page (according to RedirectURL Merchant provided to ZaloPay) to display the results.
Parameter | Datatype | Description |
---|---|---|
appid |
int | appid of order |
apptransid |
String | apptransid of order |
pmcid |
int | Payment channel |
bankcode |
String | Bank code |
amount |
long | Amount of order (VND) |
discountamount |
long | Discount (VND) |
status |
int | Error code |
checksum |
String | Use to check redirect is valid or not 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 (download at DOWNLOADS page)
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 {
// check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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 {
// check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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 {
// check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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 {
// check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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 {
// check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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
# check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
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:
# check if the callback has been received, if not Merchant should use getOrderStatus API to get final result
return "Ok", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8001)