NAV

Integration Models

Select the appropriate model of ZaloPay integration

Website - ZaloPay Gateway

Overview Demo Integrated guide API

Desription

ZaloPay receives Merchant's order information by redirecting to ZaloPay Gateway

Processing flow

Sequence Flow

API specification

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 cases

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=""

Get list of supported banks

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.

Processing flow

Get bank list flow

API specification

Environment Method Endpoint
Sandbox POST https://sbgateway.zalopay.vn/api/getlistmerchantbanks
Real POST https://gateway.zalopay.vn/api/getlistmerchantbanks

Request data

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)

Response data

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

Sample code

/**
 * .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

Redirect

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.

The query string data when ZaloPay redirect to the Merchant page

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)

Sample code

/*
    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)
No matching results were found