NAV
php csharp java javascript python

PayPage交易-折價券模式設計概要

安全性設計

所有的付費要求發動都僅能從特約商店的網頁伺服器發出請求,將傳輸的資料以AES加密,再透過HTTPS加密傳輸。交易資料不由消費者端送出,可確保資料不被消費者竄改。所有付費資訊經過MYPAY Link匝道進行轉送處理,特約商店不需要處理消費者的付費流程以及安全控管。

資料驗證

交易參數中有一組由雜湊函式運算出的驗証碼,作為資料驗証用,以確保資料正確性。 大部分交易模式,特約商店以導頁的方式處理付費流程,特約商店只需確保與MYPAY LINK連線正常,即可確保交易安全以及確保資料安全。

系統架構

所有請求與查詢只能透過伺服器發動,由特約商店的網頁伺服器利用伺服端服務程式發動交易,以避免交易資料被消費者竄改或攔截。為確保交易安全,MYPAY Link僅能接受 https connection,注意僅接受TLS1.2以上協定。

MYPAY LINK 目前提供之服務與格式

MYPAY LINK 提供多種交易與應用方式,應用情境如下:

(1)PayPage金流交易請求:透過MYPAY交易頁面作付款動作

(2)交易查詢:查詢金流交易資訊

(3)交易退款:金流交易退款,支援即時退款且未超過退款期限內之支付方式皆可使用此方式發動退款。

我們提供介接方式是透過https連線,只接受POST方式傳送交易資料。

介接網址

特約商店模式

位置 API介接網址
測試區 https://pay.usecase.cc/api/agent
正式區 https://ka.mypay.tw/api/agent

Client模式(限定功能)

位置 API介接網址
測試區 https://pay.usecase.cc/api/open
正式區 https://ka.mypay.tw/api/open

資料加密方式

AES 256編碼 + base64編碼(附錄四資料加密方式)

加密金鑰

金鑰會透過mail發送,也可從管理後台取得

文字編碼

一律使用UTF-8相容編碼

PayPage金流交易-折價券模式

<?php
/**
 * 經銷商串接-PayPage金流交易-折價券模式
 */
final class AgentVoucher
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號(代特約商店發動)
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['items'] = [
                                [
                                 'id' => '1',
                                 'name' => '好棒棒麻辣鍋湯包',
                                 'cost' => '1000',
                                 'amount' => '1',
                                 'total' => '1000'
                                ]
                            ];
        $rawData['user_id'] = "userid";
        $rawData['order_id'] = "1234567890";
        $rawData['ip'] = "192.168.0.1";
        $rawData['pfn'] = "0";
        $rawData['cost'] = 900;
        $rawData['agent_sms_fee_type'] = 1;
        $rawData['agent_charge_fee_type'] = 1;
        $rawData['agent_charge_fee'] = 90;
        $rawData['voucher_type'] = "1";
        $rawData['voucher_paid'] = [
                                       [
                                        'product_id' => 'P01',
                                        'serial_number' => 'P1635306439',
                                        'name' => '好食券',
                                        'cost' => 50,
                                        'issuer' => '1',
                                        'refund_return_type' => '3'
                                       ]
                                   ];
        $rawData['voucher_free'] = [
                                       [
                                        'product_id' => 'F01',
                                        'serial_number' => 'F1635306439',
                                        'name' => 'VIP免費券',
                                        'cost' => 50,
                                        'issuer' => '1'
                                       ]
                                   ];
        $rawData['voucher_invoice_type'] = "1";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/orders'
        );
    }
    /**
     * AES 256 加密
     * @param array $fields
     * @param string $key
     * @return string
     */
    public function encrypt($fields, $key)
    {
        $data = json_encode($fields);
        $size = openssl_cipher_iv_length('AES-256-CBC');
        $iv   = openssl_random_pseudo_bytes($size);
        $data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        $data = base64_encode($iv . $data);
        return $data;
    }
    /**
     * 資料 POST 到主機
     * @param array $postData
     * @return mixed
     */
    public function post($postData = [])
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
    /**
     * 取得送出欄位資料
     * @return array
     */
    public function getPostData ()
    {
        $postData = array();
        $postData['agent_uid'] = $this->agentUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$AgentVoucher = new AgentVoucher();
$AgentVoucher->run();
?>

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
    /// <summary>
    /// 經銷商串接-PayPage金流交易-折價券模式
    /// </summary>
    public class AgentVoucher {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "518169081001";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";

        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucher simulator = new AgentVoucher();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            ArrayList items = new ArrayList();

            dynamic item = new ExpandoObject();
            item.id = "1";
            item.name = "好棒棒麻辣鍋湯包";
            item.cost = "1000";
            item.amount = "1";
            item.total = "1000";
            items.Add(item);


            ArrayList voucherPaid = new ArrayList();

            dynamic voucherPaid = new ExpandoObject();
            voucherPaid.product_id = "P01";
            voucherPaid.serial_number = "P1635306439";
            voucherPaid.name = "好食券";
            voucherPaid.cost = 50;
            voucherPaid.issuer = "1";
            voucherPaid.refund_return_type = "3";
            voucherPaid.Add(voucherPaid);


            ArrayList voucherFree = new ArrayList();

            dynamic voucherFree = new ExpandoObject();
            voucherFree.product_id = "F01";
            voucherFree.serial_number = "F1635306439";
            voucherFree.name = "VIP免費券";
            voucherFree.cost = 50;
            voucherFree.issuer = "1";
            voucherFree.Add(voucherFree);


            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.items = items;
            rawData.user_id =  "userid";
            rawData.order_id =  "1234567890";
            rawData.ip =  "192.168.0.1";
            rawData.pfn =  "0";
            rawData.cost =  900;
            rawData.agent_sms_fee_type =  1;
            rawData.agent_charge_fee_type =  1;
            rawData.agent_charge_fee =  90;
            rawData.voucher_type =  "1";
            rawData.voucherPaid = voucherPaid;
            rawData.voucherFree = voucherFree;
            rawData.voucher_invoice_type =  "1";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/orders";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.agentKey, IV);
            var svr_encode = Encrypt(svr_json, this.agentKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["agent_uid"] = this.agentUid;
            postData["service"] = svr_toUrlEncode;
            postData["encry_data"] = data_toUrlEncode;
            return postData;
        }
        /// <summary>
        /// AES 256 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <param name="byteIV"></param>
        /// <returns></returns>
        private string Encrypt(string data, string key, byte[] byteIV) {
            var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
            var enBytes = AES_Encrypt(data, byteKey, byteIV);
            return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
        }
        /// <summary>
        /// AES 256 加密處理
        /// </summary>
        /// <param name="original"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
            try {
                var data = Encoding.UTF8.GetBytes(original);

                var cipher = Aes.Create().CreateEncryptor(key, iv);

                var de = cipher.TransformFinalBlock(data, 0, data.Length);
                return de;
            } catch {
                return null;
            }
        }
        /// <summary>
        /// 轉換Bytes
        /// </summary>
        /// <param name="a"></param>
        /// <param name="arryB"></param>
        /// <returns></returns>
        private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
            List < byte > c = new List < byte > ();
            c.AddRange(a);
            arryB.ToList().ForEach(b => {
                c.AddRange(b);
            });
            return c.ToArray();
        }
        /// <summary>
        /// 產生AES的IV
        /// </summary>
        /// <returns></returns>
        private static byte[] GetBytesIV() {
            var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
            aes.KeySize = 256;
            aes.GenerateIV();
            return aes.IV;
        }
        /// <summary>
        /// 資料 POST 到主機
        /// </summary>
        /// <param name="pars"></param>
        /// <returns></returns>
        private string Post(NameValueCollection pars) {
            string result = string.Empty;
            string param = string.Empty;
            if (pars.Count > 0) {
                pars.AllKeys.ToList().ForEach(key => {
                    param += key + "=" + pars[key] + "&";
                });
                if (param[param.Length - 1] == '&') {
                    param = param.Remove(param.Length - 1);
                }
            }
            byte[] bs = Encoding.UTF8.GetBytes(param);

            try {
                HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = bs.Length;
                using(Stream reqStream = req.GetRequestStream()) {
                    reqStream.Write(bs, 0, bs.Length);
                }
                using(WebResponse wr = req.GetResponse()) {
                    Encoding myEncoding = Encoding.GetEncoding("UTF-8");
                    using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
                        result = myStreamReader.ReadToEnd();
                    }
                }

                req = null;
            } catch (WebException ex) {
                throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
            }
            return result;
        }
    }
    /// <summary>
    /// 串接服務請求欄位
    /// </summary>
    public class ServiceRequest {
        public string service_name { get; set; }
        public string cmd { get; set; }
    }
}

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
 * 經銷商串接-PayPage金流交易-折價券模式
 * 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
 * 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
 * 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
 * 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
 */
public class AgentVoucher {
    /**
     * 經銷商商務代號
     */
    String agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucher simulator = new AgentVoucher();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        ArrayList items = new ArrayList();

        Map<Object, Object> item = new HashMap<Object, Object>();
        item.put("id", "1");
        item.put("name", "好棒棒麻辣鍋湯包");
        item.put("cost", "1000");
        item.put("amount", "1");
        item.put("total", "1000");
        items.add(item);


        ArrayList voucherPaid = new ArrayList();

        Map<Object, Object> voucherPaid = new HashMap<Object, Object>();
        voucherPaid.put("product_id", "P01");
        voucherPaid.put("serial_number", "P1635306439");
        voucherPaid.put("name", "好食券");
        voucherPaid.put("cost", 50);
        voucherPaid.put("issuer", "1");
        voucherPaid.put("refund_return_type", "3");
        voucherPaid.add(voucherPaid);


        ArrayList voucherFree = new ArrayList();

        Map<Object, Object> voucherFree = new HashMap<Object, Object>();
        voucherFree.put("product_id", "F01");
        voucherFree.put("serial_number", "F1635306439");
        voucherFree.put("name", "VIP免費券");
        voucherFree.put("cost", 50);
        voucherFree.put("issuer", "1");
        voucherFree.add(voucherFree);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("items", items);
        rawData.put("user_id", "userid");
        rawData.put("order_id", "1234567890");
        rawData.put("ip", "192.168.0.1");
        rawData.put("pfn", "0");
        rawData.put("cost", 900);
        rawData.put("agent_sms_fee_type", 1);
        rawData.put("agent_charge_fee_type", 1);
        rawData.put("agent_charge_fee", 90);
        rawData.put("voucher_type", "1");
        rawData.put("voucherPaid", voucherPaid);
        rawData.put("voucherFree", voucherFree);
        rawData.put("voucher_invoice_type", "1");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/orders");
        return rawData;
    }
    /**
     * AES 256 加密
     * @param rawData 原始資料
     * @param AesKey AES256金鑰字串
     * @return 轉換成Base64資料
     */
    public String encrypt(Map rawData, String AesKey) {

        try {
            ObjectMapper objMapper = new ObjectMapper();

            byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
            byte[] key = AesKey.getBytes(UTF_8);

            // 16 bytes is the IV size for AES256
            PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
                    new CBCBlockCipher(new AESEngine()));
            // Random iv
            SecureRandom rng = new SecureRandom();
            byte[] ivBytes = new byte[16];
            rng.nextBytes(ivBytes);

            cipher.init(true, new ParametersWithIV(new KeyParameter(key),
                    ivBytes));
            byte[] outBuf = new byte[cipher.getOutputSize(data.length)];

            int processed = cipher
                    .processBytes(data, 0, data.length, outBuf, 0);
            processed += cipher.doFinal(outBuf, processed);

            byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
            System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
            System.arraycopy(outBuf, 0, outBuf2, 16, processed);

            Base64.Encoder encoder = Base64.getEncoder();
            String base64 = encoder.encodeToString(outBuf2);
            return base64;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 資料 POST 到主機
     * @param qstr 串接資料
     * @return 服務回傳JSON資訊
     */
    public String post(String qstr) {
        String result = "";
        try {
            // 資料
            byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);

            URL iurl = new URL(this.url);
            SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
            sc.init(null, null, new java.security.SecureRandom());

            HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
            con.setSSLSocketFactory(sc.getSocketFactory());
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            con.setRequestProperty("Content-Length",
                    String.valueOf(qstr_bytes.length));
            con.setRequestProperty("Accept-Charset", "UTF-8");

            con.setDoOutput(true);
            con.setDoInput(true);

            con.getOutputStream()
                    .write(qstr.getBytes(Charset.forName("UTF-8")));
            con.getOutputStream().flush();

            BufferedReader in = new BufferedReader(new InputStreamReader(
                    con.getInputStream(), "UTF-8"));
            String inputLine;
            StringBuffer response = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine + "\r\n");
            }

            try {
                result = response.toString();
            } finally {
                in.close();
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return result;
    }
    /**
     * 取得送出欄位資料
     * @return POST完整資料
     */
    public String getPostData() {
        String postData = "";
        try {
            // Base64需要使用UrlEncode做傳輸
            String data_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.agentKey), "UTF-8");

            postData = "agent_uid=" + this.agentUid + "&service="
                    + svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return postData;
    }
}

const crypto = require('crypto');
const httpRequest = require('https');

/**
 * 經銷商串接-PayPage金流交易-折價券模式
 */
function AgentVoucher() {
    // 經銷商商務代號
    this.agentUid = "518169081001";
    // 經銷商金鑰或認證碼
    this.agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucher.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        items: [
                   {
                    'id': "1",
                    'name': "好棒棒麻辣鍋湯包",
                    'cost': "1000",
                    'amount': "1",
                    'total': "1000"
                   }
               ],
        user_id: "userid",
        order_id: "1234567890",
        ip: "192.168.0.1",
        pfn: "0",
        cost: 900,
        agent_sms_fee_type: 1,
        agent_charge_fee_type: 1,
        agent_charge_fee: 90,
        voucher_type: "1",
        voucher_paid: [
                          {
                           'product_id': "P01",
                           'serial_number': "P1635306439",
                           'name': "好食券",
                           'cost': 50,
                           'issuer': "1",
                           'refund_return_type': "3"
                          }
                      ],
        voucher_free: [
                          {
                           'product_id': "F01",
                           'serial_number': "F1635306439",
                           'name': "VIP免費券",
                           'cost': 50,
                           'issuer': "1"
                          }
                      ],
        voucher_invoice_type: "1",

    };
};
/**
 * 取得服務位置
 */
AgentVoucher.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/orders"
    };
};
/**
 * AES 256 加密
 */
AgentVoucher.prototype.encrypt = function (fields, key) {
    let eData = JSON.stringify(fields);
    const blockSize = 16;
    const iv = crypto.randomBytes(blockSize);
    const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
    let tmpCipher = encryptor.update(Buffer.from(eData));
    let finalCipher = encryptor.final();
    const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
    let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
    return data;
};
/**
 * 資料 POST 到主機
 */
AgentVoucher.prototype.post = function (postData) {
    return new Promise((res, rej) => {
        let options = {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            rejectUnauthorized: false
        };

        let send_process = httpRequest.request(this.url, options, (api_res) => {
            let res_data = "";
            api_res.on('data', (tmp_data) => {
                res_data += tmp_data;
            });
            api_res.on('end', () => {
                res(res_data);
            });
        });

        send_process.write(JSON.stringify(postData));
        send_process.end();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucher.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucher.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucher = new AgentVoucher();
AgentVoucher.run();


# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes

"""經銷商串接-PayPage金流交易-折價券模式
"""
class AgentVoucher:
    # 經銷商商務代號
    agentUid = "518169081001";
    # 經銷商金鑰或認證碼
    agentKey = b"2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    # 特約商店商務代號
    storeUid = "289151880002"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/agent"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'items': [
                         {
                          'id': "1",
                          'name': "好棒棒麻辣鍋湯包",
                          'cost': "1000",
                          'amount': "1",
                          'total': "1000"
                         }
                     ],
            'user_id': "userid",
            'order_id': "1234567890",
            'ip': "192.168.0.1",
            'pfn': "0",
            'cost': 900,
            'agent_sms_fee_type': 1,
            'agent_charge_fee_type': 1,
            'agent_charge_fee': 90,
            'voucher_type': "1",
            'voucher_paid': [
                                {
                                 'product_id': "P01",
                                 'serial_number': "P1635306439",
                                 'name': "好食券",
                                 'cost': 50,
                                 'issuer': "1",
                                 'refund_return_type': "3"
                                }
                            ],
            'voucher_free': [
                                {
                                 'product_id': "F01",
                                 'serial_number': "F1635306439",
                                 'name': "VIP免費券",
                                 'cost': 50,
                                 'issuer': "1"
                                }
                            ],
            'voucher_invoice_type': "1",
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/orders'
        }

    def encrypt(self, fields, key):
        """AES 256 加密

        Args:
            fields {dict}: 欄位資料
            key {bytes}: AES金鑰

        Returns:
            {string}: 加密資料
        """
        data = json.dumps(fields, separators=(',', ':'))
        data = Padding.pad(data.encode('utf-8'), AES.block_size)
        iv = get_random_bytes(AES.block_size)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        data = cipher.encrypt(data)
        data = base64.b64encode(iv + data)
        return data

    def post(self, postData):
        """資料 POST 到主機

        Args:
            postData {dict}: 欄位資料

        Returns:
            {string}: JSON資料
        """
        result = requests.post(self.url, postData)
        return result.text

    def getPostData(self):
        """取得送出欄位資料

        Returns:
            {dict}: 欄位資料
        """
        postData = {
            'agent_uid': self.agentUid,
            'service': self.encrypt(self.getService(), self.agentKey),
            'encry_data': self.encrypt(self.getRawData(), self.agentKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

AgentVoucher = AgentVoucher()
AgentVoucher.run()


回傳 JSON 結構如下:

{
    "code": "200",
    "msg": "資料正確",
    "url": "http:\/\/pay.usecase.cc\/payment\/95227.html",
    "uid": 95227,
    "key": "d2c55a2055cbe6f711f1e977039e2a8f"
}

此交易請求參數內含交易訂單編號,與查詢用之金鑰,以及付費網址。貴司也可將此交易訂單編號綁定貴司的消費者訂單,我們會透過主動回報機制,以POST方式回報交易即時資訊,回報網址可以在管理系統中設定,啟動服務後,系統就會主動回傳訂單狀態。

經銷商『PayPage金流交易-折價券模式』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/orders"}
JSON格式,AES256加密資料
encry_data text 『PayPage金流交易-折價券模式』欄位參考
JSON格式,AES256加密資料

『PayPage金流交易-折價券模式』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
user_id string 消費者帳號 必填
user_name string 消費者姓名,電子錢包交易必要欄位
user_real_name string 消費者真實姓名,電子錢包交易必要欄位
user_english_name string 消費者英文姓名,電子錢包交易必要欄位
user_zipcode string 消費者郵遞區號
user_address string 消費者帳單地址
user_sn_type string 證號類型 『證號類型』值參考
user_sn string 付款人身分證/統一證號/護照號碼
user_phone string 消費者家用電話
user_cellphone_code string 消費者行動電話國碼,電子錢包交易必要欄位
user_cellphone string 消費者行動電話,電子錢包交易必要欄位
user_email string 消費者 E-Mail,電子錢包交易必要欄位
user_birthday string 消費者生日
cost string 支付總金額
= 物品之總價加總 + 運費 - 折價券總金額
必填
currency string 預設交易幣別(預設為TWD新台幣) 『幣別類型』值參考
enable_dcc integer 啟用dcc(自動換匯) 『自動換匯』值參考
order_id string 訂單編號(訂單編號最長為50bytes) 必填
ip string 消費者來源 IP 必填
item string 訂單內物品數
items array 訂單物品項目 必填
每筆『商品項目』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
pfn string 預選付費方法 『付款方式』值參考
interface string interface 對照表
success_returl string 交易成功導頁網址
failure_returl string 交易失敗導頁網址
limit_pay_days integer 虛擬帳號與超商代碼使用之有效天數
enable_quickpay integer 啟用快速結帳 『啟用快速結帳』值參考
transaction_type integer 交易類型 『交易類型』值參考
creditcard_installment string 國內信用卡分期顯示限定
JSON 格式如下
{
"3": ["013", "822", "808"],
"6": ["822", "812"]
}
each_code string eACH交易代碼(如果使用eACH必須指定交易代碼)
issue_invoice_state integer 開立發票 『電子發票是否開立狀態』值參考
invoice_ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
invoice_input_type integer 電子發票開立類型 『電子發票開立類型』值參考
invoice_cloud_type string 「雲端發票」類型 當invoice_input_type為1,此狀態才有效
『雲端發票類型』值參考
invoice_tax_id string 統一編號 當invoice_input_type為1,此欄位才有效,非必要
invoice_mobile_code string 手機條碼 當invoice_cloud_type為2,此欄位才有效
invoice_natural_person string 自然人憑證條碼 當invoice_cloud_type為3,此欄位才有效
invoice_m_post_zone string EMail 紙本寄送郵遞區號 當invoice_cloud_type為4,此欄位才有效,非必須
invoice_m_address string EMail 紙本寄送住址 當invoice_cloud_type為4,此欄位才有效,非必須
invoice_love_code string 愛心碼 當invoice_input_type為2,此欄位才有效
invoice_b2b_title string 發票抬頭 當invoice_input_type為3時,此欄位才有效
invoice_b2b_id string 統一編號 當invoice_input_type為3時,此欄位才有效
invoice_b2b_address string 發票地址 當invoice_input_type為3時,此欄位才有效
invoice_b2b_title_force string 若選擇實體發票時,發票抬頭無法異動。 『電子發票欄位異動』值參考
invoice_b2b_id_force string 若選擇實體發票時,統一編號無法異動。 『電子發票欄位異動』值參考
invoice_b2b_address_force integer 若選擇實體發票時,預設地址無法異動。 『電子發票欄位異動』值參考
agent_sms_fee_type integer 經銷商代收費是否含簡訊費 『含不含簡訊費』值參考
agent_charge_fee_type integer 經銷商代收費是否含手續費 『含不含手續費類型』值參考
agent_charge_fee integer 經銷商代收費
is_agent_charge integer 是否為經銷商代收費模式
若 is_agent_charge 有指定,以指定優先
若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1
若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0
『是否為經銷商代收費模式』值參考
voucher_type string 折價券模式 『驗證折價券方式』值參考
voucher_paid array 有償票券 每筆『有償票券項目』欄位參考
voucher_free array 無償票券 每筆『無償票券項目』欄位參考
voucher_invoice_type string 折價券發票金額開立類型 『發票金額開立類型』值參考

『PayPage金流交易-折價券模式』回傳欄位

參數名稱 型態 說明 必須
code string 交易回傳碼
msg string 回傳訊息
uid string 金流交易訂單UID
key string 交易驗証碼
url string 交易網址

『交易完成回傳資訊』回報欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
key string 交易驗証碼
prc string 主要交易回傳碼(retcode)
finishtime string 交易完成時間(YYYYMMDDHHmmss)
cardno string 銀行端口回傳碼
acode string 授權碼
card_type string 信用卡卡別 『信用卡別類型』值參考
issuing_bank string 發卡行
issuing_bank_uid string 發卡銀行代碼
is_agent_charge int 是否為經銷商代收費模式 『是否為經銷商代收費模式』值參考
transaction_mode integer 交易服務類型 『交易服務類型』值參考
supplier_name string 交易之金融服務商
supplier_code string 交易之金融服務商代碼 『金流供應商代碼』值參考
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
voucher_paid array 有償票券項目 每筆『有償票券項目』欄位參考
voucher_free array 無償票券項目 每筆『無償票券項目』欄位參考
price string 請求交易點數/金額
actual_price string 實際交易點數/金額
recharge_code string 交易產品代碼
love_cost string 愛心捐款金額
retmsg string 回傳訊息
pfn string 付費方法
trans_type integer 交易類型 『交易類型定義』值參考
redeem string 紅利資訊 JSON 格式 『紅利資訊』值參考
payment_name string 定期定額式/定期分期式扣款名稱
nois string 定期定額式/定期分期式扣繳期數
group_id string 1.定期定額式扣款編號
2.定期分期式扣款編號
bank_id string 銀行代碼
虛擬帳號資訊
expired_date string 有效日期(YYYYMMDDHHmmss)
虛擬帳號、超商代碼、無卡分期資訊
result_type integer 虛擬帳號、超商代碼 資料格式類型 『閘道內容回傳格式類型』值參考
result_content_type string 資料內容所屬支付名稱 『資料內容所屬支付名稱』值參考
result_content string 虛擬帳號、超商代碼 資料內容 『虛擬帳號回傳欄位』值參考
『ibon』值參考
『FamiPort』值參考
『Life-ET』值參考
『超商條碼繳費』值參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『非即時交易回傳資訊』回報欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
key string 交易驗証碼
prc string 主要交易回傳碼(retcode)
cardno string 銀行端口回傳碼
acode string 授權碼
card_type string 信用卡卡別 『信用卡別類型』值參考
issuing_bank string 發卡行
issuing_bank_uid string 發卡銀行代碼
is_agent_charge int 是否為經銷商代收費模式 『是否為經銷商代收費模式』值參考
transaction_mode integer 交易服務類型 『交易服務類型』值參考
supplier_name string 交易之金融服務商
supplier_code string 交易之金融服務商代碼 『金流供應商代碼』值參考
finishtime string 交易完成時間(YYYYMMDDHHmmss)
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
voucher_paid array 有償票券項目 每筆『有償票券項目』欄位參考
voucher_free array 無償票券項目 每筆『無償票券項目』欄位參考
price string 請求交易點數/金額
actual_price string 實際交易點數/金額
recharge_code string 交易產品代碼
love_cost string 愛心捐款金額
retmsg string 回傳訊息
pfn string 付費方法
trans_type integer 交易類型 『交易類型定義』值參考
redeem string 紅利資訊 JSON 格式 『紅利資訊』值參考
payment_name string 定期定額式/定期分期式扣款名稱
nois string 定期定額式/定期分期式扣繳期數
group_id string 1.定期定額式扣款編號
2.定期分期式扣款編號
bank_id string 銀行代碼
虛擬帳號資訊
expired_date string 有效日期(YYYYMMDDHHmmss)
虛擬帳號、超商代碼、無卡分期資訊
result_type integer 虛擬帳號、超商代碼 資料格式類型 『閘道內容回傳格式類型』值參考
result_content_type string 資料內容所屬支付名稱 『資料內容所屬支付名稱』值參考
result_content string 虛擬帳號、超商代碼 資料內容 『虛擬帳號回傳欄位』值參考
『ibon』值參考
『FamiPort』值參考
『Life-ET』值參考
『超商條碼繳費』值參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『訂單確認回傳資訊』回報欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
key string 交易驗証碼
prc string 主要交易回傳碼(retcode)
finishtime string 交易完成時間(YYYYMMDDHHmmss)
cardno string 銀行端口回傳碼
acode string 授權碼
card_type string 信用卡卡別 『信用卡別類型』值參考
issuing_bank string 發卡行
issuing_bank_uid string 發卡銀行代碼
is_agent_charge int 是否為經銷商代收費模式 『是否為經銷商代收費模式』值參考
transaction_mode integer 交易服務類型 『交易服務類型』值參考
supplier_name string 交易之金融服務商
supplier_code string 交易之金融服務商代碼 『金流供應商代碼』值參考
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
voucher_paid array 有償票券項目 每筆『有償票券項目』欄位參考
voucher_free array 無償票券項目 每筆『無償票券項目』欄位參考
price string 請求交易點數/金額
actual_price string 實際交易點數/金額
recharge_code string 交易產品代碼
love_cost string 愛心捐款金額
retmsg string 回傳訊息
pfn string 付費方法
trans_type integer 交易類型 『交易類型定義』值參考
redeem string 紅利資訊 JSON 格式 『紅利資訊』值參考
payment_name string 定期定額式/定期分期式扣款名稱
nois string 定期定額式/定期分期式扣繳期數
group_id string 1.定期定額式扣款編號
2.定期分期式扣款編號
bank_id string 銀行代碼
虛擬帳號資訊
expired_date string 有效日期(YYYYMMDDHHmmss)
虛擬帳號、超商代碼、無卡分期資訊
result_type integer 虛擬帳號、超商代碼 資料格式類型 『閘道內容回傳格式類型』值參考
result_content_type string 資料內容所屬支付名稱 『資料內容所屬支付名稱』值參考
result_content string 虛擬帳號、超商代碼 資料內容 『虛擬帳號回傳欄位』值參考
『ibon』值參考
『FamiPort』值參考
『Life-ET』值參考
『超商條碼繳費』值參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

交易查詢

<?php
/**
 * 經銷商串接-交易查詢
 */
final class AgentQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號(代特約商店發動)
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['uid'] = "95217";
        $rawData['key'] = "3425042d7d266e4aea5fd4653a0271db";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/queryorder'
        );
    }
    /**
     * AES 256 加密
     * @param array $fields
     * @param string $key
     * @return string
     */
    public function encrypt($fields, $key)
    {
        $data = json_encode($fields);
        $size = openssl_cipher_iv_length('AES-256-CBC');
        $iv   = openssl_random_pseudo_bytes($size);
        $data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        $data = base64_encode($iv . $data);
        return $data;
    }
    /**
     * 資料 POST 到主機
     * @param array $postData
     * @return mixed
     */
    public function post($postData = [])
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
    /**
     * 取得送出欄位資料
     * @return array
     */
    public function getPostData ()
    {
        $postData = array();
        $postData['agent_uid'] = $this->agentUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$AgentQuery = new AgentQuery();
$AgentQuery->run();
?>

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
    /// <summary>
    /// 經銷商串接-交易查詢
    /// </summary>
    public class AgentQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "518169081001";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";

        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentQuery simulator = new AgentQuery();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            dynamic rawData = new ExpandoObject();
            rawData.uid =  "95217";
            rawData.key =  "3425042d7d266e4aea5fd4653a0271db";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/queryorder";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.agentKey, IV);
            var svr_encode = Encrypt(svr_json, this.agentKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["agent_uid"] = this.agentUid;
            postData["service"] = svr_toUrlEncode;
            postData["encry_data"] = data_toUrlEncode;
            return postData;
        }
        /// <summary>
        /// AES 256 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <param name="byteIV"></param>
        /// <returns></returns>
        private string Encrypt(string data, string key, byte[] byteIV) {
            var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
            var enBytes = AES_Encrypt(data, byteKey, byteIV);
            return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
        }
        /// <summary>
        /// AES 256 加密處理
        /// </summary>
        /// <param name="original"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
            try {
                var data = Encoding.UTF8.GetBytes(original);

                var cipher = Aes.Create().CreateEncryptor(key, iv);

                var de = cipher.TransformFinalBlock(data, 0, data.Length);
                return de;
            } catch {
                return null;
            }
        }
        /// <summary>
        /// 轉換Bytes
        /// </summary>
        /// <param name="a"></param>
        /// <param name="arryB"></param>
        /// <returns></returns>
        private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
            List < byte > c = new List < byte > ();
            c.AddRange(a);
            arryB.ToList().ForEach(b => {
                c.AddRange(b);
            });
            return c.ToArray();
        }
        /// <summary>
        /// 產生AES的IV
        /// </summary>
        /// <returns></returns>
        private static byte[] GetBytesIV() {
            var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
            aes.KeySize = 256;
            aes.GenerateIV();
            return aes.IV;
        }
        /// <summary>
        /// 資料 POST 到主機
        /// </summary>
        /// <param name="pars"></param>
        /// <returns></returns>
        private string Post(NameValueCollection pars) {
            string result = string.Empty;
            string param = string.Empty;
            if (pars.Count > 0) {
                pars.AllKeys.ToList().ForEach(key => {
                    param += key + "=" + pars[key] + "&";
                });
                if (param[param.Length - 1] == '&') {
                    param = param.Remove(param.Length - 1);
                }
            }
            byte[] bs = Encoding.UTF8.GetBytes(param);

            try {
                HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = bs.Length;
                using(Stream reqStream = req.GetRequestStream()) {
                    reqStream.Write(bs, 0, bs.Length);
                }
                using(WebResponse wr = req.GetResponse()) {
                    Encoding myEncoding = Encoding.GetEncoding("UTF-8");
                    using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
                        result = myStreamReader.ReadToEnd();
                    }
                }

                req = null;
            } catch (WebException ex) {
                throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
            }
            return result;
        }
    }
    /// <summary>
    /// 串接服務請求欄位
    /// </summary>
    public class ServiceRequest {
        public string service_name { get; set; }
        public string cmd { get; set; }
    }
}

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
 * 經銷商串接-交易查詢
 * 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
 * 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
 * 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
 * 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
 */
public class AgentQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentQuery simulator = new AgentQuery();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("uid", "95217");
        rawData.put("key", "3425042d7d266e4aea5fd4653a0271db");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/queryorder");
        return rawData;
    }
    /**
     * AES 256 加密
     * @param rawData 原始資料
     * @param AesKey AES256金鑰字串
     * @return 轉換成Base64資料
     */
    public String encrypt(Map rawData, String AesKey) {

        try {
            ObjectMapper objMapper = new ObjectMapper();

            byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
            byte[] key = AesKey.getBytes(UTF_8);

            // 16 bytes is the IV size for AES256
            PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
                    new CBCBlockCipher(new AESEngine()));
            // Random iv
            SecureRandom rng = new SecureRandom();
            byte[] ivBytes = new byte[16];
            rng.nextBytes(ivBytes);

            cipher.init(true, new ParametersWithIV(new KeyParameter(key),
                    ivBytes));
            byte[] outBuf = new byte[cipher.getOutputSize(data.length)];

            int processed = cipher
                    .processBytes(data, 0, data.length, outBuf, 0);
            processed += cipher.doFinal(outBuf, processed);

            byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
            System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
            System.arraycopy(outBuf, 0, outBuf2, 16, processed);

            Base64.Encoder encoder = Base64.getEncoder();
            String base64 = encoder.encodeToString(outBuf2);
            return base64;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 資料 POST 到主機
     * @param qstr 串接資料
     * @return 服務回傳JSON資訊
     */
    public String post(String qstr) {
        String result = "";
        try {
            // 資料
            byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);

            URL iurl = new URL(this.url);
            SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
            sc.init(null, null, new java.security.SecureRandom());

            HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
            con.setSSLSocketFactory(sc.getSocketFactory());
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            con.setRequestProperty("Content-Length",
                    String.valueOf(qstr_bytes.length));
            con.setRequestProperty("Accept-Charset", "UTF-8");

            con.setDoOutput(true);
            con.setDoInput(true);

            con.getOutputStream()
                    .write(qstr.getBytes(Charset.forName("UTF-8")));
            con.getOutputStream().flush();

            BufferedReader in = new BufferedReader(new InputStreamReader(
                    con.getInputStream(), "UTF-8"));
            String inputLine;
            StringBuffer response = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine + "\r\n");
            }

            try {
                result = response.toString();
            } finally {
                in.close();
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return result;
    }
    /**
     * 取得送出欄位資料
     * @return POST完整資料
     */
    public String getPostData() {
        String postData = "";
        try {
            // Base64需要使用UrlEncode做傳輸
            String data_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.agentKey), "UTF-8");

            postData = "agent_uid=" + this.agentUid + "&service="
                    + svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return postData;
    }
}

const crypto = require('crypto');
const httpRequest = require('https');

/**
 * 經銷商串接-交易查詢
 */
function AgentQuery() {
    // 經銷商商務代號
    this.agentUid = "518169081001";
    // 經銷商金鑰或認證碼
    this.agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentQuery.prototype.getRawData = function () {
    return {
        uid: "95217",
        key: "3425042d7d266e4aea5fd4653a0271db",

    };
};
/**
 * 取得服務位置
 */
AgentQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/queryorder"
    };
};
/**
 * AES 256 加密
 */
AgentQuery.prototype.encrypt = function (fields, key) {
    let eData = JSON.stringify(fields);
    const blockSize = 16;
    const iv = crypto.randomBytes(blockSize);
    const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
    let tmpCipher = encryptor.update(Buffer.from(eData));
    let finalCipher = encryptor.final();
    const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
    let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
    return data;
};
/**
 * 資料 POST 到主機
 */
AgentQuery.prototype.post = function (postData) {
    return new Promise((res, rej) => {
        let options = {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            rejectUnauthorized: false
        };

        let send_process = httpRequest.request(this.url, options, (api_res) => {
            let res_data = "";
            api_res.on('data', (tmp_data) => {
                res_data += tmp_data;
            });
            api_res.on('end', () => {
                res(res_data);
            });
        });

        send_process.write(JSON.stringify(postData));
        send_process.end();
    });
};
/**
 * 取得送出欄位資料
 */
AgentQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentQuery = new AgentQuery();
AgentQuery.run();

# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes

"""經銷商串接-交易查詢
"""
class AgentQuery:
    # 經銷商商務代號
    agentUid = "518169081001";
    # 經銷商金鑰或認證碼
    agentKey = b"2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    # 特約商店商務代號
    storeUid = "289151880002"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/agent"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'uid': "95217",
            'key': "3425042d7d266e4aea5fd4653a0271db",
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/queryorder'
        }

    def encrypt(self, fields, key):
        """AES 256 加密

        Args:
            fields {dict}: 欄位資料
            key {bytes}: AES金鑰

        Returns:
            {string}: 加密資料
        """
        data = json.dumps(fields, separators=(',', ':'))
        data = Padding.pad(data.encode('utf-8'), AES.block_size)
        iv = get_random_bytes(AES.block_size)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        data = cipher.encrypt(data)
        data = base64.b64encode(iv + data)
        return data

    def post(self, postData):
        """資料 POST 到主機

        Args:
            postData {dict}: 欄位資料

        Returns:
            {string}: JSON資料
        """
        result = requests.post(self.url, postData)
        return result.text

    def getPostData(self):
        """取得送出欄位資料

        Returns:
            {dict}: 欄位資料
        """
        postData = {
            'agent_uid': self.agentUid,
            'service': self.encrypt(self.getService(), self.agentKey),
            'encry_data': self.encrypt(self.getRawData(), self.agentKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

AgentQuery = AgentQuery()
AgentQuery.run()

回傳 JSON 結構如下:

{
    "key": "3425042d7d266e4aea5fd4653a0271db",
    "prc": "250",
    "cardno": "493817******0003",
    "acode": "AA1234",
    "card_type": "1",
    "issuing_bank": "合作金庫",
    "issuing_bank_uid": "006",
    "is_agent_charge": 0,
    "transaction_mode": 1,
    "supplier_name": "高鉅科技",
    "supplier_code": "T0",
    "order_id": "1234567890",
    "user_id": "userid",
    "uid": 95217,
    "cost": 900,
    "currency": "TWD",
    "actual_cost": 900,
    "actual_currency": "TWD",
    "voucher_paid": [
        {
            "product_id": "P01",
            "serial_number": "P1634864897",
            "name": "好食券",
            "cost": 50,
            "issuer": "1",
            "refund_return_type": "1"
        }
    ],
    "voucher_free": [
        {
            "product_id": "F01",
            "serial_number": "F1634864897",
            "name": "VIP免費券",
            "cost": 50,
            "issuer": "1"
        }
    ],
    "price": 0,
    "actual_price": 0,
    "recharge_code": "",
    "love_cost": 0,
    "retmsg": "付款完成",
    "pay_mode_uid": 1,
    "pfn": "CREDITCARD",
    "trans_type": 1,
    "redeem": "",
    "finishtime": "20211022090918",
    "store_group_id": "",
    "group_id": "",
    "nois": "",
    "payment_name": "",
    "bank_id": "",
    "result_type": 4,
    "result_content_type": "CREDITCARD",
    "result_content": "{}",
    "expired_date": "",
    "appropriation_date": "20211208",
    "invoice_state": 6,
    "invoice_date": "20211022090918",
    "invoice_wordtrack": "SW",
    "invoice_number": "83037076",
    "invoice_rand_code": "8373",
    "invoice_seller_ban": "28915188",
    "invoice_buyer_ban": "",
    "invoice_left_qrcode": "SW830370761101022837300000359000003840000000028915188Zw9cxaRpHWtRiZAohYOP6g==:**********:3:3:1:好棒棒麻辣鍋湯包:1:1000:",
    "invoice_middle_barcode": "11010SW830370768373",
    "invoice_right_qrcode": "**VIP免費券:1:-50:好食券:1:-50",
    "invoice_title_type": 1,
    "invoice_title": "123",
    "invoice_print_type": 0,
    "invoice_print_device": 0,
    "invoice_amount": "900",
    "invoice_sales_amount": "900",
    "invoice_tax_amount": "0",
    "invoice_order_detail": "[{\"Description\":\"好棒棒麻辣鍋湯包\",\"Quantity\":\"1\",\"UnitPrice\":\"1000\",\"Amount\":\"1000\"},{\"Description\":\"VIP免費券\",\"Quantity\":\"1\",\"UnitPrice\":\"-50\",\"Amount\":\"-50\"},{\"Description\":\"好食券\",\"Quantity\":\"1\",\"UnitPrice\":\"-50\",\"Amount\":\"-50\"}]",
    "invoice_ratetype": 1,
    "invoice_input_type": 2,
    "invoice_cloud_type": "",
    "invoice_mobile_code": "",
    "invoice_tax_id": "",
    "invoice_natural_person": "",
    "invoice_m_post_zone": "",
    "invoice_m_address": "",
    "invoice_love_code": "1234",
    "invoice_b2b_title": "",
    "invoice_b2b_id": "",
    "invoice_b2b_post_zone": "",
    "invoice_b2b_address": "",
    "invoice_allowance": [
        {
            "uid": 95232,
            "amount": "900",
            "order_detail": "[{\"SeqNo\":\"0\",\"ItemID\":\"95232\",\"ItemName\":\"好棒棒麻辣鍋湯包\",\"Qty\":\"1\",\"TotalAmount\":\"1000\",\"RateType\":\"1\"},{\"SeqNo\":\"0\",\"ItemID\":\"95217\",\"ItemName\":\"VIP免費券\",\"Qty\":\"1\",\"TotalAmount\":\"-50\",\"RateType\":\"1\"},{\"SeqNo\":\"1\",\"ItemID\":\"95217\",\"ItemName\":\"好食券\",\"Qty\":\"1\",\"TotalAmount\":\"-50\",\"RateType\":\"1\"}]"
        }
    ],
    "refund_order": [
        {
            "uid": 95232,
            "prc": "230",
            "cost": 900,
            "currency": "TWD",
            "actual_cost": 900,
            "actual_currency": "TWD",
            "voucher_paid": [
                {
                    "product_id": "P01",
                    "serial_number": "P1634864897",
                    "name": "好食券",
                    "cost": 50,
                    "issuer": "1",
                    "refund_return_type": "1"
                }
            ],
            "retmsg": "退款完成",
            "finishtime": "20211022162732",
            "appropriation_date": "20211208",
            "invoice_state": 0,
            "invoice_date": "",
            "invoice_wordtrack": "",
            "invoice_number": "",
            "invoice_rand_code": "",
            "invoice_seller_ban": "",
            "invoice_buyer_ban": "",
            "invoice_left_qrcode": "",
            "invoice_middle_barcode": "",
            "invoice_right_qrcode": "",
            "invoice_title_type": 1,
            "invoice_title": "",
            "invoice_amount": "0",
            "invoice_sales_amount": "0",
            "invoice_tax_amount": "0",
            "invoice_order_detail": "[]",
            "invoice_ratetype": 1,
            "invoice_input_type": 2,
            "invoice_allowance": []
        }
    ],
    "cancel_order": [],
    "echo_0": "",
    "echo_1": "",
    "echo_2": "",
    "echo_3": "",
    "echo_4": ""
}

發動交易後,如果遲遲未接收回報,可透過此方法查詢訂單交易。

經銷商『交易查詢』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/queryorder"}
JSON格式,AES256加密資料
encry_data text 『交易查詢』欄位參考
JSON格式,AES256加密資料

『交易查詢』欄位

參數名稱 型態 說明 必須
uid string 訂單 uid
key string 查詢驗證碼

『交易查詢』回傳欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
key string 交易驗証碼
prc string 主要交易回傳碼(retcode)
finishtime string 交易完成時間(YYYYMMDDHHmmss)
cardno string 銀行端口回傳碼
acode string 授權碼
card_type string 信用卡卡別 『信用卡別類型』值參考
issuing_bank string 發卡行
issuing_bank_uid string 發卡銀行代碼
is_agent_charge int 是否為經銷商代收費模式 『是否為經銷商代收費模式』值參考
transaction_mode integer 交易服務類型 『交易服務類型』值參考
supplier_name string 交易之金融服務商
supplier_code string 交易之金融服務商代碼 『金流供應商代碼』值參考
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
voucher_paid array 有償票券項目 每筆『有償票券項目』欄位參考
voucher_free array 無償票券項目 每筆『無償票券項目』欄位參考
price string 請求交易點數/金額
actual_price string 實際交易點數/金額
recharge_code string 交易產品代碼
love_cost string 愛心捐款金額
retmsg string 回傳訊息
pfn string 付費方法
trans_type string 付款種類 『交易類型定義』值參考
redeem string 紅利資訊 JSON 格式 『紅利資訊』值參考
payment_name string 定期定額式/定期分期式扣款名稱
nois string 定期定額式/定期分期式扣繳期數
group_id string 1.定期定額式扣款編號
2.定期分期式扣款編號
bank_id string 虛擬帳號銀行代碼
expired_date string 有效日期(YYYYMMDDHHmmss)
虛擬帳號、超商代碼、無卡分期資訊
appropriation_date string 預計撥款日期(YYYYMMDD)
result_type integer 虛擬帳號、超商代碼 資料格式類型 『閘道內容回傳格式類型』值參考
result_content_type string 資料內容所屬支付名稱 『資料內容所屬支付名稱』值參考
result_content string 虛擬帳號、超商代碼 資料內容 『虛擬帳號回傳欄位』值參考
『ibon』值參考
『FamiPort』值參考
『Life-ET』值參考
『超商條碼繳費』值參考
refund_order array 退款訂單資訊(多筆格式) 每筆『交易查詢-退款資訊』欄位參考
cancel_order array 取消訂單資訊(多筆格式) 每筆『交易查詢-取消資訊』欄位參考
invoice_state integer 發票開立狀態 『電子發票開立狀態類型』值參考
invoice_date string 發票開立日期(YYYYMMDD)
invoice_wordtrack string 發票字軌
invoice_number string 發票號碼
invoice_rand_code string 電子發票隨機碼
invoice_seller_ban string 賣方統一編號
invoice_buyer_ban string 買方統一編號
invoice_left_qrcode string 電子發票左邊QrCode內容
invoice_middle_barcode string 電子發票中間Barcode內容(格式Code-39)
invoice_right_qrcode string 電子發票右邊QrCode內容
invoice_title_type integer 電子發票列印標題格式 『電子發票紙本列印標題類型』值參考
invoice_title string 電子發票列印標題格式
invoice_print_type integer 電子發票列印類型 『電子發票列印類型』值參考
invoice_print_device integer 電子發票列印設備 『電子發票列印設備』值參考
invoice_amount string 電子發票銷售總額
invoice_sales_amount string 電子發票銷售額
invoice_tax_amount string 電子發票稅額
invoice_order_detail string 電子發票全部產品明細(JSON格式) 『商品細項』值參考
invoice_ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
invoice_input_type integer 電子發票開立類型 『電子發票開立類型』值參考
invoice_cloud_type string 電子發票開立類型-雲端發票類型 『雲端發票類型』值參考
invoice_mobile_code string 當invoice_cloud_type為2時紀錄的手機條碼
invoice_tax_id string 當invoice_cloud_type為2時紀錄的統一編號
invoice_natural_person string 當invoice_cloud_type為3時紀錄的自然人憑證條碼
invoice_m_post_zone string 當invoice_cloud_type為4時紀錄中獎時紙本發票郵遞區號
invoice_m_address string 當invoice_cloud_type為4時紀錄中獎時紙本發票收件住址
invoice_love_code string 當invoice_input_type為2時紀錄的愛心碼
invoice_b2b_title string 當invoice_input_type為3時紀錄的發票抬頭
invoice_b2b_id string 當invoice_input_type為3時紀錄的統一編號
invoice_b2b_post_zone string 當invoice_input_type為3時紀錄的郵遞區號
invoice_b2b_address string 當invoice_input_type為3時紀錄的發票地址
invoice_allowance array 電子發票折讓資訊 每筆『電子發票折讓資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

發動交易後,如果遲遲未接收回報,可透過此方法查詢訂單交易。

交易退款

<?php
/**
 * 經銷商串接-交易退款-折價券模式
 */
final class AgentVoucherRefund
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號(代特約商店發動)
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['uid'] = "95047";
        $rawData['key'] = "85def7799fd15978cac14a44846f3a2a";
        $rawData['cost'] = 900;
        $rawData['voucher_paid'] = [
                                       [
                                        'product_id' => 'P01',
                                        'serial_number' => 'P1634634156'
                                       ]
                                   ];
        $rawData['invoice_state'] = 6;

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/refund'
        );
    }
    /**
     * AES 256 加密
     * @param array $fields
     * @param string $key
     * @return string
     */
    public function encrypt($fields, $key)
    {
        $data = json_encode($fields);
        $size = openssl_cipher_iv_length('AES-256-CBC');
        $iv   = openssl_random_pseudo_bytes($size);
        $data = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        $data = base64_encode($iv . $data);
        return $data;
    }
    /**
     * 資料 POST 到主機
     * @param array $postData
     * @return mixed
     */
    public function post($postData = [])
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
    /**
     * 取得送出欄位資料
     * @return array
     */
    public function getPostData ()
    {
        $postData = array();
        $postData['agent_uid'] = $this->agentUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->agentKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->agentKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$AgentVoucherRefund = new AgentVoucherRefund();
$AgentVoucherRefund->run();
?>

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Dynamic;
/// <summary>
/// 建議使用.net framework4.5以上版本
/// 1.請透過NuGet安裝Newtonsoft.Json,若.net framework小於4.5請安裝Newtonsoft.Json 7.0以下版本
/// 2.若貴司.net framework小於4 可能無法使用dynamic,若是自行組陣列
/// 3.若貴司.net framework小於3.5 可能無法使用AES類別,若是參閱微軟網站使用較舊方式進行加密
/// 4.若貴司.net framework小於3.5 可能沒有Linq可使用,故data只能組字串,Newtonsoft.Json也可能無法使用
/// </summary>
namespace MyPay {
    /// <summary>
    /// 經銷商串接-交易退款-折價券模式
    /// </summary>
    public class AgentVoucherRefund {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "518169081001";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";

        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherRefund simulator = new AgentVoucherRefund();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

            System.Console.WriteLine(result);
        }
        /// <summary>
        /// 取得串接欄位資料
        /// </summary>
        private dynamic GetRawData() {

            ArrayList voucherPaid = new ArrayList();

            dynamic voucherPaid = new ExpandoObject();
            voucherPaid.product_id = "P01";
            voucherPaid.serial_number = "P1634634156";
            voucherPaid.Add(voucherPaid);


            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.uid =  "95047";
            rawData.key =  "85def7799fd15978cac14a44846f3a2a";
            rawData.cost =  900;
            rawData.voucherPaid = voucherPaid;
            rawData.invoice_state =  6;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/refund";
            return rawData;
        }
        /// <summary>
        /// 取得送出欄位資料
        /// </summary>
        private NameValueCollection GetPostData() {
            string data_json = JsonConvert.SerializeObject(GetRawData(), Formatting.None);
            string svr_json = JsonConvert.SerializeObject(GetService(), Formatting.None);; //依API種類調整

            //產生AES向量
            var IV = GetBytesIV();

            //進行加密
            var data_encode = Encrypt(data_json, this.agentKey, IV);
            var svr_encode = Encrypt(svr_json, this.agentKey, IV);

            //請注意使用的 Http Post 套件是否會自動加上UrlEncode,本Post範例為原始方式,故須加上UrlEncode
            //若自行使用的套件會自動補上UrlEncode,則請忽略下面的UrlEncode,避免做了兩次UrlEncode
            string data_toUrlEncode = HttpUtility.UrlEncode(data_encode);
            string svr_toUrlEncode = HttpUtility.UrlEncode(svr_encode);

            NameValueCollection postData = new NameValueCollection();
            postData["agent_uid"] = this.agentUid;
            postData["service"] = svr_toUrlEncode;
            postData["encry_data"] = data_toUrlEncode;
            return postData;
        }
        /// <summary>
        /// AES 256 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <param name="byteIV"></param>
        /// <returns></returns>
        private string Encrypt(string data, string key, byte[] byteIV) {
            var byteKey = System.Text.Encoding.UTF8.GetBytes(key);
            var enBytes = AES_Encrypt(data, byteKey, byteIV);
            return Convert.ToBase64String(BytesAdd(byteIV, enBytes));
        }
        /// <summary>
        /// AES 256 加密處理
        /// </summary>
        /// <param name="original"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        private byte[] AES_Encrypt(string original, byte[] key, byte[] iv) {
            try {
                var data = Encoding.UTF8.GetBytes(original);

                var cipher = Aes.Create().CreateEncryptor(key, iv);

                var de = cipher.TransformFinalBlock(data, 0, data.Length);
                return de;
            } catch {
                return null;
            }
        }
        /// <summary>
        /// 轉換Bytes
        /// </summary>
        /// <param name="a"></param>
        /// <param name="arryB"></param>
        /// <returns></returns>
        private byte[] BytesAdd(byte[] a, params byte[][] arryB) {
            List < byte > c = new List < byte > ();
            c.AddRange(a);
            arryB.ToList().ForEach(b => {
                c.AddRange(b);
            });
            return c.ToArray();
        }
        /// <summary>
        /// 產生AES的IV
        /// </summary>
        /// <returns></returns>
        private static byte[] GetBytesIV() {
            var aes = System.Security.Cryptography.AesCryptoServiceProvider.Create();
            aes.KeySize = 256;
            aes.GenerateIV();
            return aes.IV;
        }
        /// <summary>
        /// 資料 POST 到主機
        /// </summary>
        /// <param name="pars"></param>
        /// <returns></returns>
        private string Post(NameValueCollection pars) {
            string result = string.Empty;
            string param = string.Empty;
            if (pars.Count > 0) {
                pars.AllKeys.ToList().ForEach(key => {
                    param += key + "=" + pars[key] + "&";
                });
                if (param[param.Length - 1] == '&') {
                    param = param.Remove(param.Length - 1);
                }
            }
            byte[] bs = Encoding.UTF8.GetBytes(param);

            try {
                HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(this.url);
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = bs.Length;
                using(Stream reqStream = req.GetRequestStream()) {
                    reqStream.Write(bs, 0, bs.Length);
                }
                using(WebResponse wr = req.GetResponse()) {
                    Encoding myEncoding = Encoding.GetEncoding("UTF-8");
                    using(StreamReader myStreamReader = new StreamReader(wr.GetResponseStream(), myEncoding)) {
                        result = myStreamReader.ReadToEnd();
                    }
                }

                req = null;
            } catch (WebException ex) {
                throw new WebException(ex.Message + "params : " + param, ex, ex.Status, ex.Response);
            }
            return result;
        }
    }
    /// <summary>
    /// 串接服務請求欄位
    /// </summary>
    public class ServiceRequest {
        public string service_name { get; set; }
        public string cmd { get; set; }
    }
}

import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URLEncoder;
import java.util.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.spongycastle.crypto.engines.AESEngine;
import org.spongycastle.crypto.modes.CBCBlockCipher;
import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import java.security.SecureRandom;
/**
 * 經銷商串接-交易退款-折價券模式
 * 1. jackson-core 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
 * 2. jackson-databind 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
 * 3. jackson-annotations 下載 https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
 * 4. Spongy Castle 下載 https://mvnrepository.com/artifact/com.madgag.spongycastle/core
 */
public class AgentVoucherRefund {
    /**
     * 經銷商商務代號
     */
    String agentUid = "518169081001";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherRefund simulator = new AgentVoucherRefund();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

    @SuppressWarnings(value = { "unchecked", "deprecation" })
    /**
     * 取得串接欄位資料
     * @return 串接原始資料
     */
    public Map getRawData() {

        ArrayList voucherPaid = new ArrayList();

        Map<Object, Object> voucherPaid = new HashMap<Object, Object>();
        voucherPaid.put("product_id", "P01");
        voucherPaid.put("serial_number", "P1634634156");
        voucherPaid.add(voucherPaid);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("uid", "95047");
        rawData.put("key", "85def7799fd15978cac14a44846f3a2a");
        rawData.put("cost", 900);
        rawData.put("voucherPaid", voucherPaid);
        rawData.put("invoice_state", 6);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/refund");
        return rawData;
    }
    /**
     * AES 256 加密
     * @param rawData 原始資料
     * @param AesKey AES256金鑰字串
     * @return 轉換成Base64資料
     */
    public String encrypt(Map rawData, String AesKey) {

        try {
            ObjectMapper objMapper = new ObjectMapper();

            byte[] data = objMapper.writeValueAsString(rawData).getBytes(UTF_8);
            byte[] key = AesKey.getBytes(UTF_8);

            // 16 bytes is the IV size for AES256
            PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
                    new CBCBlockCipher(new AESEngine()));
            // Random iv
            SecureRandom rng = new SecureRandom();
            byte[] ivBytes = new byte[16];
            rng.nextBytes(ivBytes);

            cipher.init(true, new ParametersWithIV(new KeyParameter(key),
                    ivBytes));
            byte[] outBuf = new byte[cipher.getOutputSize(data.length)];

            int processed = cipher
                    .processBytes(data, 0, data.length, outBuf, 0);
            processed += cipher.doFinal(outBuf, processed);

            byte[] outBuf2 = new byte[processed + 16]; // Make room for iv
            System.arraycopy(ivBytes, 0, outBuf2, 0, 16); // Add iv
            System.arraycopy(outBuf, 0, outBuf2, 16, processed);

            Base64.Encoder encoder = Base64.getEncoder();
            String base64 = encoder.encodeToString(outBuf2);
            return base64;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 資料 POST 到主機
     * @param qstr 串接資料
     * @return 服務回傳JSON資訊
     */
    public String post(String qstr) {
        String result = "";
        try {
            // 資料
            byte[] qstr_bytes = qstr.getBytes(StandardCharsets.UTF_8);

            URL iurl = new URL(this.url);
            SSLContext sc = SSLContext.getInstance("TLSv1.2"); // $NON-NLS-1$
            sc.init(null, null, new java.security.SecureRandom());

            HttpsURLConnection con = (HttpsURLConnection) iurl.openConnection();
            con.setSSLSocketFactory(sc.getSocketFactory());
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            con.setRequestProperty("Content-Length",
                    String.valueOf(qstr_bytes.length));
            con.setRequestProperty("Accept-Charset", "UTF-8");

            con.setDoOutput(true);
            con.setDoInput(true);

            con.getOutputStream()
                    .write(qstr.getBytes(Charset.forName("UTF-8")));
            con.getOutputStream().flush();

            BufferedReader in = new BufferedReader(new InputStreamReader(
                    con.getInputStream(), "UTF-8"));
            String inputLine;
            StringBuffer response = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine + "\r\n");
            }

            try {
                result = response.toString();
            } finally {
                in.close();
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return result;
    }
    /**
     * 取得送出欄位資料
     * @return POST完整資料
     */
    public String getPostData() {
        String postData = "";
        try {
            // Base64需要使用UrlEncode做傳輸
            String data_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getRawData(), this.agentKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.agentKey), "UTF-8");

            postData = "agent_uid=" + this.agentUid + "&service="
                    + svr_toUrlEncode + "&encry_data=" + data_toUrlEncode;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return postData;
    }
}


const crypto = require('crypto');
const httpRequest = require('https');

/**
 * 經銷商串接-交易退款-折價券模式
 */
function AgentVoucherRefund() {
    // 經銷商商務代號
    this.agentUid = "518169081001";
    // 經銷商金鑰或認證碼
    this.agentKey = "2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherRefund.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        uid: "95047",
        key: "85def7799fd15978cac14a44846f3a2a",
        cost: 900,
        voucher_paid: [
                          {
                           'product_id': "P01",
                           'serial_number': "P1634634156"
                          }
                      ],
        invoice_state: 6,

    };
};
/**
 * 取得服務位置
 */
AgentVoucherRefund.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/refund"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherRefund.prototype.encrypt = function (fields, key) {
    let eData = JSON.stringify(fields);
    const blockSize = 16;
    const iv = crypto.randomBytes(blockSize);
    const encryptor = crypto.createCipheriv('aes-256-cbc', key, iv);
    let tmpCipher = encryptor.update(Buffer.from(eData));
    let finalCipher = encryptor.final();
    const tempData = Buffer.concat([tmpCipher, finalCipher], tmpCipher.length + finalCipher.length);
    let data = Buffer.concat([iv, tempData], iv.length + tempData.length).toString('base64');
    return data;
};
/**
 * 資料 POST 到主機
 */
AgentVoucherRefund.prototype.post = function (postData) {
    return new Promise((res, rej) => {
        let options = {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            rejectUnauthorized: false
        };

        let send_process = httpRequest.request(this.url, options, (api_res) => {
            let res_data = "";
            api_res.on('data', (tmp_data) => {
                res_data += tmp_data;
            });
            api_res.on('end', () => {
                res(res_data);
            });
        });

        send_process.write(JSON.stringify(postData));
        send_process.end();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherRefund.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherRefund.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherRefund = new AgentVoucherRefund();
AgentVoucherRefund.run();


# -*- coding: utf-8 -*-
import json
import base64
import requests
from Crypto.Cipher import AES
from Crypto.Util import Padding
from Crypto.Random import get_random_bytes

"""經銷商串接-交易退款-折價券模式
"""
class AgentVoucherRefund:
    # 經銷商商務代號
    agentUid = "518169081001";
    # 經銷商金鑰或認證碼
    agentKey = b"2MrhtRYeF9wKZ4bKwzZoL8aZf26pWzIG";
    # 特約商店商務代號
    storeUid = "289151880002"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/agent"

    def getRawData(self):
        """取得串接欄位資料

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'uid': "95047",
            'key': "85def7799fd15978cac14a44846f3a2a",
            'cost': 900,
            'voucher_paid': [
                                {
                                 'product_id': "P01",
                                 'serial_number': "P1634634156"
                                }
                            ],
            'invoice_state': 6,
        }
        return rawData

    def getService(self):
        """取得服務位置

        Returns:
            {dict}: 服務位置資料
        """
        return {
            'service_name': 'api',
            'cmd': 'api/refund'
        }

    def encrypt(self, fields, key):
        """AES 256 加密

        Args:
            fields {dict}: 欄位資料
            key {bytes}: AES金鑰

        Returns:
            {string}: 加密資料
        """
        data = json.dumps(fields, separators=(',', ':'))
        data = Padding.pad(data.encode('utf-8'), AES.block_size)
        iv = get_random_bytes(AES.block_size)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        data = cipher.encrypt(data)
        data = base64.b64encode(iv + data)
        return data

    def post(self, postData):
        """資料 POST 到主機

        Args:
            postData {dict}: 欄位資料

        Returns:
            {string}: JSON資料
        """
        result = requests.post(self.url, postData)
        return result.text

    def getPostData(self):
        """取得送出欄位資料

        Returns:
            {dict}: 欄位資料
        """
        postData = {
            'agent_uid': self.agentUid,
            'service': self.encrypt(self.getService(), self.agentKey),
            'encry_data': self.encrypt(self.getRawData(), self.agentKey)
        }
        return postData

    def run(self):
        """執行
        """
        json = self.post(self.getPostData())
        print(json)

AgentVoucherRefund = AgentVoucherRefund()
AgentVoucherRefund.run()

回傳 JSON 結構如下:

{
    "row_data": {
        "uid": 95217,
        "refund_uid": 95232,
        "key": "3425042d7d266e4aea5fd4653a0271db",
        "prc": "230",
        "finishtime": "20211022162732",
        "order_id": "1234567890",
        "user_id": "userid",
        "cost": 900,
        "currency": "TWD",
        "actual_cost": 900,
        "voucher_paid": [
            {
                "product_id": "P01",
                "serial_number": "P1634864897",
                "name": "好食券",
                "cost": 50,
                "issuer": 1,
                "refund_return_type": 1
            }
        ],
        "actual_currency": "TWD",
        "retmsg": "退款完成",
        "pfn": "CREDITCARD",
        "payment_name": "",
        "nois": "",
        "group_id": "",
        "refund_type": 1,
        "expected_refund_date": "",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    },
    "key": "3425042d7d266e4aea5fd4653a0271db",
    "uid": "95217",
    "code": "B200",
    "msg": "執行成功"
}

若需要退款時,發動此API提出退款請求。支援即時退款且未超過退款期限內之支付方式皆可使用此方式發動退款。 支援即時退款的支付方式有信用卡、美國運通、LINEPay、Pi錢包、街口支付、微信支付、支付寶、悠遊付、現金、GooglePay、ApplePay。

經銷商『交易退款-折價券模式』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/refund"}
JSON格式,AES256加密資料
encry_data text 『交易退款-折價券模式』欄位參考
JSON格式,AES256加密資料

『交易退款-折價券模式』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
key string 交易驗証碼 必填
uid string 訂單編號(UID) 必填
cost string 退款金額(實際支付金額)
若使用折價券模式則需為全額退款
必填
voucher_paid array 有償折價券退款項目
注意:折價券模式,全額退款定義為(實際支付金額+所有有償折價券)
注意:若有使用折價券模式,則此欄位為必填
每筆『票券項目』欄位參考
invoice_state string 若有開立電子發票,指定電子發票使用作廢或折讓
注意:跨發票月份無法作廢
『電子發票退款時使用作廢或折讓』值參考
items array 退款項目
若使用電子發票,此欄位必填
退款項目之項目名稱必須和交易時之產品項目名稱相同
退款項目之總金額必須與退款金額一致
注意:若為全額退款時,不帶此欄位項目,系統會自動補齊
每筆『商品項目』欄位參考

『交易退款-折價券模式』回傳欄位

參數名稱 型態 說明 必須
key string 特約商店驗證碼 (store_token)
uid string 訂單編號(UID)
code string 處理狀態 B200 或 B500
msg string 回傳訊息
row_data object 退款資訊(即時退款才有此資訊) 『退款完成回傳資訊』欄位參考

『退款完成回傳資訊』欄位

參數名稱 型態 說明 必須
uid string 原MYPAYLINK 之交易流水號 $uid
refund_uid string 退款之交易流水號(若多次退款,每次皆會不同)
key string 交易驗証碼
prc string 主要交易回傳碼(retcode)
finishtime string 退款處理完成時間(YYYYMMDDHHmmss)
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 申請之退款金額
currency string 申請之退款幣別
actual_cost string 實際退款金額
voucher_paid array 退還之有償票券項目 每筆『有償票券項目』欄位參考
actual_currency string 實際退款幣別
retmsg string 回傳訊息
pfn string 付費方法
payment_name string 定期定額式/定期分期式扣款名稱
nois string 定期定額式/定期分期式扣繳期數
group_id string 1.定期定額式扣款編號
2.定期分期式扣款編號
refund_type string 退款類型(1.直接線上退款 2.手動退款(信用卡類) 3.手動退款(現金類)
expected_refund_date string 現金退款預計退款日(YYYYMMDD)
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

其他關聯欄位說明

關聯欄位

『商品項目』欄位

參數名稱 型態 說明 必須
id string 商品編號 必填
name string 商品名稱 必填
cost integer 商品單價 必填
amount integer 商品數量 必填
total integer 商品小計 必填
image_url string 商品圖片連結(僅LINEPay線上使用)

『有償票券項目』欄位

參數名稱 型態 說明 必須
product_id string 票券群組編號(最長限32 Bytes)
serial_number string 票券券號(特約商店下的每一個票券群組的票券券號必須是唯一)
name string 票券名稱
cost integer 票券金額
issuer string 發行者 『有價票券發行者』值參考
refund_return_type string 退款時,票券金額是否歸還 『退款時票券金額是否歸還』值參考

『無償票券項目』欄位

參數名稱 型態 說明 必須
product_id string 票券群組編號(最長限32 Bytes)
serial_number string 票券券號(特約商店下的每一個票券群組的票券券號必須是唯一)
name string 票券名稱
cost integer 票券金額
issuer string 發行者 『免費票券發行者』值參考

『虛擬帳號回傳欄位』欄位

參數名稱 型態 說明 必須
PinCode string 虛擬帳號
LimitDate string 繳費有效期限,格式YYYYMMDDHHmmss
BankCode string 銀行代碼

『ibon』欄位

參數名稱 型態 說明 必須
PinCode string 超商代碼(可用qrcode被掃)
LimitDate string 超商代碼繳費有效期限,格式YYYYMMDDHHmmss
BarCode1 string 三段條碼繳費條碼1(格式:Code-39 barcode)
BarCode2 string 三段條碼繳費條碼2(格式:Code-39 barcode)
BarCode3 string 三段條碼繳費條碼3(格式:Code-39 barcode)
BarcodeEndDate string 三段條碼繳費期限,格式YYYYMMDDHHmmss

『FamiPort』欄位

參數名稱 型態 說明 必須
PinCode string 繳費代碼(可憑此代碼至設備列印繳費單)
LimitDate string 繳費有效期限,格式YYYYMMDDHHmmss
BarCode1 string 三段條碼繳費條碼1(格式:Code-39 barcode)
BarCode2 string 三段條碼繳費條碼2(格式:Code-39 barcode)
BarCode3 string 三段條碼繳費條碼3(格式:Code-39 barcode)
BarcodeEndDate string 三段條碼繳費期限,格式YYYYMMDDHHmmss

『Life-ET』欄位

參數名稱 型態 說明 必須
PinCode string 代碼(不可用來繳費)
BarCode1 string 繳費條碼1(格式:Code-39 barcode)
BarCode2 string 繳費條碼2(格式:Code-39 barcode)
BarCode3 string 繳費條碼3(格式:Code-39 barcode)
LimitDate string 繳費有效期限,格式YYYYMMDDHHmmss

『超商條碼繳費』欄位

參數名稱 型態 說明 必須
BarCode1 string 繳費條碼1(格式:Code-39 barcode)
BarCode2 string 繳費條碼2(格式:Code-39 barcode)
BarCode3 string 繳費條碼3(格式:Code-39 barcode)
LimitDate string 繳費有效期限,格式YYYYMMDDHHmmss

『紅利資訊』欄位

參數名稱 型態 說明 必須
type string 紅利類型 『紅利資訊類型』值參考
used string 紅利折抵點數
amount string 自付金額

『票券項目』欄位

參數名稱 型態 說明 必須
product_id string 票券群組編號(最長限32 Bytes)
serial_number string 票券券號(特約商店下的每一個票券群組的票券券號必須是唯一)

『交易查詢-退款資訊』欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
prc string 主要交易回傳碼(retcode)
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
retmsg string 回傳訊息
finishtime string 交易完成時間(YYYYMMDDHHmmss)
appropriation_date string 預計撥款日期(YYYYMMDD)
invoice_state integer 發票開立狀態 『電子發票開立狀態類型』值參考
invoice_date string 發票開立日期(YYYYMMDD)
invoice_wordtrack string 發票字軌
invoice_number string 發票號碼
invoice_rand_code string 電子發票隨機碼
invoice_seller_ban string 賣方統一編號
invoice_buyer_ban string 買方統一編號
invoice_left_qrcode string 電子發票左邊QrCode內容
invoice_middle_barcode string 電子發票中間Barcode內容(格式Code-39)
invoice_right_qrcode string 電子發票右邊QrCode內容
invoice_title_type integer 電子發票列印標題格式 『電子發票紙本列印標題類型』值參考
invoice_title string 電子發票列印標題內容
invoice_print_type integer 電子發票列印類型 『電子發票列印類型』值參考
invoice_print_device integer 電子發票列印設備 『電子發票列印設備』值參考
invoice_amount string 電子發票銷售總額
invoice_sales_amount string 電子發票銷售額
invoice_tax_amount string 電子發票稅額
invoice_order_detail string 電子發票全部產品明細(JSON格式) 『商品細項』值參考
invoice_ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
invoice_input_type integer 電子發票開立類型 『電子發票開立類型』值參考
invoice_allowance array 電子發票折讓資訊 每筆『電子發票折讓資訊』欄位參考

『交易查詢-取消資訊』欄位

參數名稱 型態 說明 必須
uid string Payment Hub之交易流水號
prc string 主要交易回傳碼(retcode)
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
retmsg string 回傳訊息
finishtime string 交易完成時間(YYYYMMDDHHmmss)

『商品細項』欄位

參數名稱 型態 說明 必須
Description string 商品名稱 必填
Quantity string 數量 必填
UnitPrice string 單價 必填
Amount string 總金額 必填

『電子發票折讓資訊』欄位

參數名稱 型態 說明 必須
uid string 發生之退款交易流水號(UID)
amount integer 電子發票折讓金額
order_detail string 電子發票折讓明細(JSON格式) 『商品細項』值參考

值的定義

『證號類型』值內容

型態 說明 備註
1 integer 身份證字號(預設)
2 integer 統一證號
3 integer 護照號碼

『幣別類型』值內容

型態 說明 備註
TWD integer 新台幣(預設)
CNY integer 人民幣

『自動換匯』值內容

型態 說明 備註
0 integer 關閉(預設)
1 integer 開啟

『付款方式』值內容

型態 說明 備註
all string 全部可用支付方式(預設)
MobilePayAll string 指定下列線上行動支付方式
支付寶、Pi 拍錢包、LINEPay、微信、街口支付、悠遊付
CREDITCARD string 信用卡
CSTORECODE string 超商代碼
WEBATM string WEBATM
E_COLLECTION string 虛擬帳號
UNIONPAY string 銀聯卡
SVC string 點數卡(GASH ,Imoney)
ABROAD string 海外信用卡
ALIPAY string 支付寶
WECHAT string 微信支付
DIRECTDEBIT string 定期定額扣款
LINEPAYON string LINE Pay線上付款
LINEPAYOFF string LINE Pay線下付款
WECHATOFF string 微信支付線下
APPLEPAY string APPLE PAY
GOOGLEPAY string Google Pay
EACH string eACH交易
C_INSTALLMENT string 信用卡分期
C_REDEEM string 信用卡紅利
CARDLESS string 無卡分期
PION string Pi 拍錢包線上
PIOFF string Pi 拍錢包線下
AMEX string 美國運通
JKOON string 街口支付線上
JKOOFF string 街口支付線下
ALIPAYOFF string 支付寶線下
M_RECHARGE string 儲值交易
EASYWALLETON string 悠遊付線上
EASYWALLETOFF string 悠遊付線下
AFP string 後付款
BARCODE string 超商條碼繳費

『啟用快速結帳』值內容

型態 說明 備註
0 integer 關閉
1 integer 開啟(預設)

『交易類型』值內容

型態 說明 備註
1 string 網路交易(預設)(消費者直接輸入支付內容)
2 string 實體交易 (商戶面對消費者時,由商戶輸入支付內容做消費)

『電子發票是否開立狀態』值內容

型態 說明 備註
0 integer 不開立電子發票
1 integer 開立電子發票
2 integer 依系統設定(預設)

『電子發票稅率別』值內容

型態 說明 備註
1 integer 應稅(預設)
2 integer 零稅率
3 integer 免稅

『電子發票開立類型』值內容

型態 說明 備註
1 integer 雲端發票
2 integer 發票捐贈
3 integer 實體發票 1.重要提示,若選擇此模式,商戶需要自行列印實體發票交付給消費者,系統不會寄送mail通知與中獎後也不會通知給消費者。電子發票列印格式,請參考國稅局頒布標準。
2.使用paypage交易與開立發票同時進行時,絕對不可以使用此模式,因為系統會根據消費者在paypage畫面上的選擇,開立捐贈或雲端載具

『雲端發票類型』值內容

型態 說明 備註
2 integer 手機條碼
3 integer 自然人憑證條碼
4 integer 以E-Mail寄送

『電子發票欄位異動』值內容

型態 說明 備註
0 integer 可以異動(預設)
1 integer 不可異動

『含不含簡訊費』值內容

型態 說明 備註
1 integer 含手續費
0 integer 不含手續費(預設)

『含不含手續費類型』值內容

型態 說明 備註
1 integer 含手續費
0 integer 不含手續費(預設)

『驗證折價券方式』值內容

型態 說明 備註
0 string 不使用折價券模式(預設)
1 string 固定制
2 string 即時查詢制

『發票金額開立類型』值內容

型態 說明 備註
1 string 支付金額 (訂單金額 - 現金優惠券金額 - 免費優惠券金額) (預設)
2 string 支付金額 + 現金優惠券金額

『信用卡別類型』值內容

型態 說明 備註
0 string 無法辨識或支付方式為非信用卡類
1 string VISA
2 string MasterCard
3 string JCB
4 string AMEX

『交易服務類型』值內容

型態 說明 備註
0 integer 尚未進行閘道交易
1 integer 代收代付
2 integer 特店模式

『金流供應商代碼』值內容

型態 說明 備註
A1 string 裕富數位資融
A2 string 三環亞洲
B0 string 新光銀行
B1 string 永豐銀行
B2 string 合作金庫
B3 string 台北富邦
B4 string 玉山銀行
B5 string 台新銀行
B6 string 聯合信用卡處理中心
B7 string 台中商銀
B8 string 中國信託商業銀行
B9 string 上海商業儲蓄銀行
BA string 第一銀行
BB string 元大商業銀行
BC string 凱基銀行
BD string 國泰世華商業銀行
BE string 華泰商業銀行
BF string 兆豐銀行
BG string 環滙亞太
S0 string 全網行銷股份有限公司(FamiPort)
S1 string 安源資訊股份有限公司(ibon)
S2 string 萊爾富國際股份有限公司(Hi-Life)
T0 string 高鉅科技
T1 string 藍新金流
W0 string 統振
W1 string 遊戲橘子數位
W2 string 台灣連線(LINEPay)
W3 string 博經
W4 string 街口電子支付
W5 string 悠遊卡
W6 string 一卡通票證
W7 string iCash
W8 string 全支付(PXPay plus)
W9 string 拍付國際資訊(Pi錢包)
E0 string MYTIX

『交易類型定義』值內容

型態 說明 備註
1 integer 一般 (預設)
2 integer 分期
3 integer 紅利

『閘道內容回傳格式類型』值內容

型態 說明 備註
0 integer 無法辨識
1 integer 網址
2 integer 超連結本文
3 integer xml
4 integer json
5 integer csv
6 integer 串流

『資料內容所屬支付名稱』值內容

型態 說明 備註
E_COLLECTION string 虛擬帳號
IBON string iBON
FAMIPORT string FamiPort
LIFEET string LIFE-ET
WEBATM string WEBATM
CREDITCARD string 信用卡
UNIONPAY string 銀聯卡
SVC string 點數卡(GASH ,Imoney)
ABROAD string 海外信用卡
ALIPAY string 支付寶
WECHAT string 微信支付
LINEPAYON string LINE Pay線上付款
LINEPAYOFF string LINE Pay線下付款
WECHATOFF string 微信支付線下
APPLEPAY string APPLE PAY
GOOGLEPAY string Google Pay
EACH string eACH交易
CARDLESS string 無卡分期
PION string Pi 拍錢包線上
PIOFF string Pi 拍錢包線下
AMEX string 美國運通
JKOON string 街口支付線上
JKOOFF string 街口支付線下
ALIPAYOFF string 支付寶線下
M_RECHARGE string 儲值交易
EASYWALLETON string 悠遊付線上
EASYWALLETOFF string 悠遊付線下
AFP string 後付款
BARCODE string 超商條碼繳費

『有價票券發行者』值內容

型態 說明 備註
1 string 平台折價券(預設)
2 string 行銷合作夥伴折價券

『退款時票券金額是否歸還』值內容

型態 說明 備註
1 string 票券金額給予特店(預設)
2 string 票券金額能歸還消費者
3 string 票券金額歸還經銷商

『免費票券發行者』值內容

型態 說明 備註
1 string 平台折價券
2 string 行銷合作夥伴折價券
3 string 商店折價券

『紅利資訊類型』值內容

型態 說明 備註
1 integer 全額
2 integer 部分

『電子發票開立狀態類型』值內容

型態 說明 備註
0 integer 不處理或已無效(預設)
1 integer 等候處理中
2 integer 發票開立成功
3 integer 發票開立失敗(系統或特約商店發票相關設定不正確)
4 integer 作癈
5 integer 發票開立失敗(系統發生錯誤)
6 integer 折讓

『電子發票紙本列印標題類型』值內容

型態 說明 備註
1 integer 文字
2 integer 圖形(圖片網址)

『電子發票列印類型』值內容

型態 說明 備註
0 integer 不列印 自行處置
1 integer 列印 電子發票 + 商品明細
2 integer 只印電子發票
3 integer 只印商品明細

『電子發票列印設備』值內容

型態 說明 備註
0 integer 自行處理
1 integer SUNMI V2 PRO

『電子發票退款時使用作廢或折讓』值內容

型態 說明 備註
4 string 作廢或作廢重開 預設
6 string 折讓

『是否為經銷商代收費模式』值內容

型態 說明 備註
1 integer 是經銷商代收費模式
0 integer 不是經銷商代收費模式

附錄一:PFN(支付工具)參數表

資料傳遞可使用編號,也可以使用代碼 。 例如:pfn=27跟pfn=PION,一樣都是使用Pi 拍錢包線上付款支付工具。

編號 代碼 狀態 說明
1 CREDITCARD 啟用 信用卡
3 CSTORECODE 啟用 超商代碼
4 WEBATM 啟用 WEBATM
6 E_COLLECTION 啟用 虛擬帳號 (ATM轉帳)
9 ABROAD 啟用 海外信用卡(非台灣發行信用卡)
10 ALIPAY 啟用 支付寶
13 WECHAT 啟用 微信支付
14 DIRECTDEBIT 啟用 定期扣款
15 LINEPAYON 啟用 LINE線上付款(消費者主掃)
16 LINEPAYOFF 啟用 LINE線下付款(消費者被掃)
19 WECHATOFF 啟用 微信支付線下
20 APPLEPAY 啟用 Apple Pay
21 GOOGLEPAY 啟用 Google Pay
23 C_INSTALLMENT 啟用 信用卡分期
24 C_REDEEM 啟用 信用卡紅利
25 CARDLESS 啟用 無卡分期(由資融公司提供分期服務)
27 PION 啟用 Pi 拍錢包線上付款(消費者主掃)
28 PIOFF 啟用 Pi 拍錢包線下付款(消費者被掃)
29 AMEX 啟用 美國運通
31 JKOON 啟用 街口支付線上付款(消費者主掃)
32 JKOOF 啟用 街口支付線下付款(消費者被掃)
33 ALIPAYOFF 啟用 支付寶線下(消費者被掃)
34 M_RECHARGE 啟用 儲值
36 AFP 啟用 後付款
37 CASH 啟用 現金
38 EASYWALLETON 啟用 悠遊付線上付款(消費者主掃)
39 EASYWALLETOFF 啟用 悠遊付線下付款(消費者被掃)
40 EASYCARD 啟用 悠遊卡
41 IPASS 啟用 一卡通
42 ICASH 啟用 iCash
43 BARCODE 啟用 超商條碼繳費

附錄二:交易狀態代碼

以下回傳的狀態代碼均須處理,避免系統連線錯誤,MYPAY LINK回傳時,貴司系統無法判讀

狀態代碼 狀態說明 詳細說明
100 資料錯誤 MYPAYLINK收到資料,但是格式或資料錯誤
200 資料正確 MYPAYLINK收到正確資料,會接續下一步交易

220 取消成功 如申請取消,取消訂單狀態為取消成功
230 退款成功 如申請退款,申請退款成功時狀態。
245 授權成功 若使用信用卡類自行請款模式,則交易後為授權成功。之後進行請款動作,才會轉為付款成功(250)
247 請款進行中 若使用信用卡類自行請款模式,閘道為玉山或NCCC(聯信、凱基、元大)等批次處理,發動請款時轉為此狀態,等候金融服務商通知請款成功,才會轉為付款成功(250)
250 付款成功 此次交易,消費者付款成功
260 交易成功
尚未付款完成
超商代碼繳費-請等候消費者繳費入帳完成付款或消費者放棄交易,MYPAY LINK會再傳送一次結果:
250:代表消費者付款成功,此為最終結果
380:代表消費者沒有在時限內去繳費,逾期未去繳費,視同交易失敗,此為最終結果
265 訂單綁定 表示訂單編號生效,進入貸款頁面,但尚未註冊
最後會在回傳狀態
A0002:消費者放棄該筆交易,該筆交易視同交易失敗,為最終結果
275:無卡分期-請等候審查通過
270 交易成功
尚未付款完成
虛擬帳號-請等候消費者繳費入帳
完成付款或消費者放棄交易,MYPAY LINK會再傳送一次結果:
250:代表消費者付款成功,此為最終結果
380:代表消費者沒有在時限內去繳費,逾期未去繳費,視同交易失敗,此為最終結果
280 交易成功
尚未付款完成
儲值/WEBATM-線上待付款,等待狀態,等到使用者線上完成交易後MYPAY LINK會再傳送一次結果
250:代表消費者付款成功,此為最終結果
300:代表消費者付款失敗
282 訂單成立待後付款審核確認
尚未付款完成
後付款,等待狀態,等後付款審核通過通知
284:代表後付款審核通過
300:代表審核不通過
284 訂單成立後付款待請款
尚未付款完成
後付款,等待狀態,等特約商店出貨後,需發動請款告知後付款已出貨請款
250:代表後付款請款成功,此為最終結果
300:代表後付款請款失敗
290 交易成功
但資訊不符
交易成功,但資訊不符(包含金額不符,如多繳或少繳...等),該類型交易請特別注意

300 交易失敗 金流服務商回傳交易失敗或該筆交易超過風險控管限制規則
380 逾期交易 超商代碼或虛擬帳號交易,超過系統設定繳費期限
若經MYPAY LINK查詢驗證後,有機會在變更狀態
290:交易成功,但資訊不符
原因有可能是服務商的參數規則漏洞或是系統時間差異造成
400 系統錯誤訊息 若MYPAY LINK或上游服務商系統異常時
600 結帳完成 視為付款完成,此狀態為上游服務商確認訂單後的狀態,表示該筆訂單會撥款
透過MYPAY主動查詢或每日對帳機制
操作訂單功能內發動查詢功能
A0001 交易待確認 MYPAY LINK與金流服務商發生連線異常,待查詢後確認結果,會主動再次回傳交易結果
250:代表消費者確實付款完成
600:結帳完成
300:金流服務商回傳交易失敗或超過風險控管限制規則交易
A0002 放棄交易 畫面導向MYPAY LINK後,消費者即放棄該筆交易,該筆交易視同交易失敗,為最終結果
B200 執行成功 處理成功執行
B500 執行失敗 處理時,資料異常不予以處理

附錄三:設定調整

附錄四:資料加密方式說明

  1. 所有的API送出HTTPs請求之欄位中,service 和 encry_data 欄位皆進行 AES256+BASE64 加密處理。
  2. AES加密,格式為CBC,長度為256bits,金鑰長度32,IV長度16,傳遞內文為加密後組合IV並經過Base64轉換後傳出。
  3. IV資料建議隨機產生。

附錄五:API模擬串接服務

提供模擬使用HTTP Protocol,透過POST方式傳遞資料到MYPAY, 並且得到回傳結果。

附錄六:測試區測試用信用卡卡號

下面卡號僅限在測試區測試使用

聯合信用卡中心閘道(其中MasterCard/JCB可測分期與紅利)

Visa MasterCard JCB
卡號 4938170130000003 5430450100001219 3560500100001218
有效日期 1228 1218 1218
安全碼 985 214 023
3D交易密碼 nccc1234

永豐銀行信用卡

Visa MasterCard JCB
卡號 4058650600065507 5433760200078009 3566703300032801
有效日期 1022 1022 0922
安全碼 395 597 033

中國信託信用卡 (使用電子錢包功能適用)

Visa
一般交易 4003618704777729
有效日期 任意
安全碼 任意
3D交易密碼 1234567

高鉅模擬信用卡(成功卡)

Visa MasterCard JCB
一般交易 4761120010000492 5204247750001471 3566703300032801
有效日期 1122 1122 0922
安全碼 533 111 033

高鉅模擬信用卡(失敗卡)

MasterCard
一般交易 5204247750001471
有效日期 1122
安全碼 111

高鉅模擬信用卡(3D)

說明 卡號
3D交易 4003618704777729
有效日期 任意
安全碼 任意

凱基 (醫療費/捐款費用) 信用卡

Visa
一般交易 4907060600015101
有效日期 1226
安全碼 905

備註:(醫療費/捐款費用)信用卡所使用之訂單編號「order_id」(繳費單號)長度最長為16bytes。(此為上游限制)