NAV
php csharp java javascript python

修改歷程

版本 異動日期 修訂內容 位置
1.0 2021.01.01 新版文件
1.0.1 2023.04.07 新增開發前請先閱讀 20230407_01
1.0.2 2023.04.07 新增退券回傳通知資料 20230718_01
1.0.3 2024.04.18 新增票券售出、作廢、狀態查詢等功能 20240418_01

開發前請先閱讀

金鑰的注意事項

Q:金鑰的有效期限

A:MyPay的金鑰有效期限只有一年,如果要延長,請自行至金鑰管理系統延長

Q:金鑰可以在什麼時候延長

A:到期日7天前,都可以延長(不包含第7天),一但超過,系統自動產生新金鑰後,即不可再延長

Q:金鑰即將到期前7天時,系統新發的金鑰是否會於信件中夾帶

A:會

Q:金鑰在到期前何時會發信通知

A:定期發送金鑰到期通知的頻率為:60天/30天/20天,若 貴司皆無動作,則系統會於到期前七天產製新金鑰並發送email到 貴司技術窗口信箱,此時舊的金鑰,因還未過期還可以使用,一旦過期,貴司仍使用舊金鑰則會無法交易

交易結果的告知

Q:交易完成的導頁會有交易結果的參數嗎

A:不論是參數中的success_returl 或 failure_returl或是後臺設定的交易成功、失敗導頁網址,均不會給予交易結果參數

Q:何時會給予交易結果

A:MyPay將在接收上游結果後,會由附錄三這邊的設定,背景主動發動通知商家

Q:當我接到MyPay通知時該做什麼

A:請直接回應8888,如沒有回應,MyPay會通知5次,若5次內均得不到8888,系統會寄發信件給予商家的技術人員以及附錄三而外設定的人員

票券交易設計概要

安全性設計

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

MYTIX 目前提供之服務與格式

MYTIX 票券交易應用情境如下:

(1)購買票券交易:提供消費者購買票券頁面。

(2)購買票券交易查詢:查詢購買票券交易資訊。

(3)票券核銷線下交易:透過掃碼消費者提供之Qrcode,由Pos發動票券核銷交易。

(4)票券核銷線下交易查詢:查詢票券核銷線下交易的交易結果。

(5)票券核銷交易取消:30分鐘內,所核銷之票券,可取消票券核銷。

(6)票券核銷交易取消查詢:查詢票券核銷交易取消紀錄。

(7)票券售出:提供實體票券售出回報。

(8)票券售出交易查詢:查詢票券售出交易資訊。

(9)票券售出交易取消:30分鐘內,所售出之票券,可取消票券售出。

(10)票券售出交易取消查詢:查詢票券售出交易取消紀錄。

(11)票券作廢:提供實體票券作廢回報。

(12)票券作廢交易查詢:查詢票券作廢交易資訊。

(13)票券狀態查詢:查詢票券目前狀態。

(14)票券核銷線下交易Qrcode掃碼頁面:取得消費者使用票券消費頁面,當消費者選擇後,顯示Qrcode提供給商家掃碼。

(15)票券消費者退券頁面(消費者主動):取得消費者票券退券頁面,可讓消費者自行退劵,當天選擇退劵的票劵,統一於隔日11點後統一退款。

(16)票券轉贈(消費者主動):取得消費者轉贈頁面,轉贈給會員與非會員。被贈與者可提出Qrcode提供給商家掃碼。

(17)票券匣:提供消費者在票券匣內一次使用Qrcode掃碼、退券、轉贈。

(18)建立或修改發行商票券:由API發動建立或修改發行商票券之設定內容。

(19)查詢發行商票券:依指定條件查詢發行商票券之設定內容。

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

介接網址

特約商店模式

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

Client模式(限定功能)

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

資料加密方式

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

加密金鑰

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

文字編碼

一律使用UTF-8相容編碼

購買票券交易

<?php
/**
 * 經銷商串接-購買票券交易
 */
final class AgentVoucher
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['sales_store_uid'] = "289151880142";
        $rawData['user_data'] = [
                                 'user_id' => 'phper',
                                 'user_name' => '金城武',
                                 'user_real_name' => '金城武',
                                 'ip' => '127.0.0.1'
                                ];
        $rawData['order_id'] = "VS20221208105148";
        $rawData['pfn'] = "0";
        $rawData['cost'] = 100;
        $rawData['currency'] = "TWD";
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'service_id' => 'A01',
                                 'id' => 'MANOR001',
                                 'platform_fee' => 1,
                                 'platform_uid' => '289151881007',
                                 'sharing' => 
                                    [
                                     'headquarters' => '0.15',
                                     'sales' => '0.1',
                                     'reimbursement' => '0.75'
                                    ],
                                 'service_rule' => 
                                    [
                                     'price' => 50,
                                     'cost' => 50,
                                     'amount' => 2,
                                     'total_price' => 100,
                                     'total_cost' => 100,
                                     'trust_start_date' => '20221208',
                                     'trust_end_date' => '20231207',
                                     'validity_end_date' => '99991231',
                                     'is_custom_serial' => 1,
                                     'serial_numbers' => '["HA11670467908","HA21670467908"]',
                                     'service_type' => 1
                                    ]
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'service_id' => 'A01',
                                 'id' => 'MANOR004',
                                 'platform_fee' => 1,
                                 'platform_uid' => '289151881007',
                                 'sharing' => 
                                    [
                                     'headquarters' => '0.15',
                                     'sales' => '0.1',
                                     'reimbursement' => '0.75'
                                    ],
                                 'service_rule' => 
                                    [
                                     'price' => 50,
                                     'cost' => 0,
                                     'amount' => 2,
                                     'total_price' => 100,
                                     'total_cost' => 0,
                                     'trust_start_date' => '20221208',
                                     'trust_end_date' => '20231207',
                                     'validity_end_date' => '99991231',
                                     'is_custom_serial' => 1,
                                     'serial_numbers' => '["HB11670467908","HB21670467908"]',
                                     'service_type' => 1
                                    ]
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherservicepurchase'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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>
    /// 經銷商串接-購買票券交易
    /// </summary>
    public class AgentVoucher {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.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() {

            dynamic userData = new ExpandoObject();
            userData.user_id = "phper";
            userData.user_name = "金城武";
            userData.user_real_name = "金城武";
            userData.ip = "127.0.0.1";

            ArrayList items = new ArrayList();

            dynamic item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.service_id = "A01";
            item1.id = "MANOR001";
            item1.platform_fee = 1;
            item1.platform_uid = "289151881007";

            dynamic sharing1 = new ExpandoObject();
            sharing1.headquarters = "0.15";
            sharing1.sales = "0.1";
            sharing1.reimbursement = "0.75";
            item1.sharing = sharing1;

            dynamic serviceRule1 = new ExpandoObject();
            serviceRule1.price = 50;
            serviceRule1.cost = 50;
            serviceRule1.amount = 2;
            serviceRule1.total_price = 100;
            serviceRule1.total_cost = 100;
            serviceRule1.trust_start_date = "20221208";
            serviceRule1.trust_end_date = "20231207";
            serviceRule1.validity_end_date = "99991231";
            serviceRule1.is_custom_serial = 1;
            serviceRule1.serial_numbers = "[\"HA11670467908\",\"HA21670467908\"]";
            serviceRule1.service_type = 1;
            item1.service_rule = serviceRule1;
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.service_id = "A01";
            item2.id = "MANOR004";
            item2.platform_fee = 1;
            item2.platform_uid = "289151881007";

            dynamic sharing2 = new ExpandoObject();
            sharing2.headquarters = "0.15";
            sharing2.sales = "0.1";
            sharing2.reimbursement = "0.75";
            item2.sharing = sharing2;

            dynamic serviceRule2 = new ExpandoObject();
            serviceRule2.price = 50;
            serviceRule2.cost = 0;
            serviceRule2.amount = 2;
            serviceRule2.total_price = 100;
            serviceRule2.total_cost = 0;
            serviceRule2.trust_start_date = "20221208";
            serviceRule2.trust_end_date = "20231207";
            serviceRule2.validity_end_date = "99991231";
            serviceRule2.is_custom_serial = 1;
            serviceRule2.serial_numbers = "[\"HB11670467908\",\"HB21670467908\"]";
            serviceRule2.service_type = 1;
            item2.service_rule = serviceRule2;
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.sales_store_uid =  "289151880142";
            rawData.user_data = userData;
            rawData.order_id =  "VS20221208105148";
            rawData.pfn =  "0";
            rawData.cost =  100;
            rawData.currency =  "TWD";
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherservicepurchase";
            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 AgentVoucher {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.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() {

        Map<Object, Object> userData = new HashMap<Object, Object>();
        userData.put("user_id", "phper");
        userData.put("user_name", "金城武");
        userData.put("user_real_name", "金城武");
        userData.put("ip", "127.0.0.1");

        ArrayList items = new ArrayList();

        Map<Object, Object> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("service_id", "A01");
        item1.put("id", "MANOR001");
        item1.put("platform_fee", 1);
        item1.put("platform_uid", "289151881007");

        Map<Object, Object> sharing1 = new HashMap<Object, Object>();
        sharing1.put("headquarters", "0.15");
        sharing1.put("sales", "0.1");
        sharing1.put("reimbursement", "0.75");
        item1.put("sharing", sharing1);

        Map<Object, Object> serviceRule1 = new HashMap<Object, Object>();
        serviceRule1.put("price", 50);
        serviceRule1.put("cost", 50);
        serviceRule1.put("amount", 2);
        serviceRule1.put("total_price", 100);
        serviceRule1.put("total_cost", 100);
        serviceRule1.put("trust_start_date", "20221208");
        serviceRule1.put("trust_end_date", "20231207");
        serviceRule1.put("validity_end_date", "99991231");
        serviceRule1.put("is_custom_serial", 1);
        serviceRule1.put("serial_numbers", "[\"HA11670467908\",\"HA21670467908\"]");
        serviceRule1.put("service_type", 1);
        item1.put("service_rule", serviceRule1);
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("service_id", "A01");
        item2.put("id", "MANOR004");
        item2.put("platform_fee", 1);
        item2.put("platform_uid", "289151881007");

        Map<Object, Object> sharing2 = new HashMap<Object, Object>();
        sharing2.put("headquarters", "0.15");
        sharing2.put("sales", "0.1");
        sharing2.put("reimbursement", "0.75");
        item2.put("sharing", sharing2);

        Map<Object, Object> serviceRule2 = new HashMap<Object, Object>();
        serviceRule2.put("price", 50);
        serviceRule2.put("cost", 0);
        serviceRule2.put("amount", 2);
        serviceRule2.put("total_price", 100);
        serviceRule2.put("total_cost", 0);
        serviceRule2.put("trust_start_date", "20221208");
        serviceRule2.put("trust_end_date", "20231207");
        serviceRule2.put("validity_end_date", "99991231");
        serviceRule2.put("is_custom_serial", 1);
        serviceRule2.put("serial_numbers", "[\"HB11670467908\",\"HB21670467908\"]");
        serviceRule2.put("service_type", 1);
        item2.put("service_rule", serviceRule2);
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("sales_store_uid", "289151880142");
        rawData.put("user_data", userData);
        rawData.put("order_id", "VS20221208105148");
        rawData.put("pfn", "0");
        rawData.put("cost", 100);
        rawData.put("currency", "TWD");
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherservicepurchase");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucher() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucher.prototype.getRawData = function () {
    return {
        sales_store_uid: "289151880142",
        user_data: {
                    'user_id': "phper",
                    'user_name': "金城武",
                    'user_real_name': "金城武",
                    'ip': "127.0.0.1"
                   },
        order_id: "VS20221208105148",
        pfn: "0",
        cost: 100,
        currency: "TWD",
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'service_id': "A01",
                    'id': "MANOR001",
                    'platform_fee': 1,
                    'platform_uid': "289151881007",
                    'sharing': 
                       {
                        'headquarters': "0.15",
                        'sales': "0.1",
                        'reimbursement': "0.75"
                       },
                    'service_rule': 
                       {
                        'price': 50,
                        'cost': 50,
                        'amount': 2,
                        'total_price': 100,
                        'total_cost': 100,
                        'trust_start_date': "20221208",
                        'trust_end_date': "20231207",
                        'validity_end_date': "99991231",
                        'is_custom_serial': 1,
                        'serial_numbers': "[\"HA11670467908\",\"HA21670467908\"]",
                        'service_type': 1
                       }
                   },
                   {
                    'issuance_uid': "289151881006",
                    'service_id': "A01",
                    'id': "MANOR004",
                    'platform_fee': 1,
                    'platform_uid': "289151881007",
                    'sharing': 
                       {
                        'headquarters': "0.15",
                        'sales': "0.1",
                        'reimbursement': "0.75"
                       },
                    'service_rule': 
                       {
                        'price': 50,
                        'cost': 0,
                        'amount': 2,
                        'total_price': 100,
                        'total_cost': 0,
                        'trust_start_date': "20221208",
                        'trust_end_date': "20231207",
                        'validity_end_date': "99991231",
                        'is_custom_serial': 1,
                        'serial_numbers': "[\"HB11670467908\",\"HB21670467908\"]",
                        'service_type': 1
                       }
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucher.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherservicepurchase"
    };
};
/**
 * 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

"""經銷商串接-購買票券交易
"""
class AgentVoucher:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'sales_store_uid': "289151880142",
            'user_data': {
                          'user_id': "phper",
                          'user_name': "金城武",
                          'user_real_name': "金城武",
                          'ip': "127.0.0.1"
                         },
            'order_id': "VS20221208105148",
            'pfn': "0",
            'cost': 100,
            'currency': "TWD",
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'service_id': "A01",
                          'id': "MANOR001",
                          'platform_fee': 1,
                          'platform_uid': "289151881007",
                          'sharing': 
                             {
                              'headquarters': "0.15",
                              'sales': "0.1",
                              'reimbursement': "0.75"
                             },
                          'service_rule': 
                             {
                              'price': 50,
                              'cost': 50,
                              'amount': 2,
                              'total_price': 100,
                              'total_cost': 100,
                              'trust_start_date': "20221208",
                              'trust_end_date': "20231207",
                              'validity_end_date': "99991231",
                              'is_custom_serial': 1,
                              'serial_numbers': "[\"HA11670467908\",\"HA21670467908\"]",
                              'service_type': 1
                             }
                         },
                         {
                          'issuance_uid': "289151881006",
                          'service_id': "A01",
                          'id': "MANOR004",
                          'platform_fee': 1,
                          'platform_uid': "289151881007",
                          'sharing': 
                             {
                              'headquarters': "0.15",
                              'sales': "0.1",
                              'reimbursement': "0.75"
                             },
                          'service_rule': 
                             {
                              'price': 50,
                              'cost': 0,
                              'amount': 2,
                              'total_price': 100,
                              'total_cost': 0,
                              'trust_start_date': "20221208",
                              'trust_end_date': "20231207",
                              'validity_end_date': "99991231",
                              'is_custom_serial': 1,
                              'serial_numbers': "[\"HB11670467908\",\"HB21670467908\"]",
                              'service_type': 1
                             }
                         }
                     ],
        }
        return rawData

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

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

    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": "資料正確",
    "uid": "100052",
    "key": "0b1c6abdfea31cac31bda6a414dafd4f",
    "url": "https:\/\/ka.usecase.cc\/voucher\/100052.html"
}

提供消費者購買票券頁面
在使用範例程式碼測試時,請注意以下參數要替換
order_id
trust_start_date,必須大等於今天
trust_end_date,必須大於今天且大於trust_start_date
serial_numbers
user_id,如要測試不同消費者時,必須更換,如不更換將視同一個

經銷商『購買票券交易』參數說明

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

『購買票券交易』欄位

參數名稱 型態 說明 必須
sales_store_uid string 銷售點特約商店代碼 必填
order_id string 購買票券交易票券交易編號(唯一) 必填
pfn string 指定購買票券時,指定支付方式(不指定請帶0) 必填
user_data object 消費者資訊 必填
『消費者資訊』欄位參考
is_pre_issue integer 是否為預發行 『是否為預發行』值參考
cost string 總金額(此訂單應付的總金額) 必填
currency string 預設交易幣別(預設為TWD新台幣)
items array 物品資訊 必填
每筆『票券項目』欄位參考
theme string 指定佈景主題名稱
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
success_returl string 購買交易成功導頁網址
failure_returl string 購買交易失敗導頁網址

『購買票券交易』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
uid string 購買票券交易UID
key string 交易驗証碼
url string 交易網址(網址一分鐘內失效,只能使用一次)

『購買票券交易回傳資訊』回報欄位

參數名稱 型態 說明 必須
uid string 購買票券交易UID
key string 交易驗証碼
code string 目前狀態碼 『購買票券交易狀態碼』值參考
msg string 回傳訊息
finishtime string 交易完成時間(YYYYMMDDHHmmss)
order_id string 購買票券交易票券交易編號
user_id string 消費者帳號
cost string 原交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
pfn string 付費方法
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券電子發票資訊』回報欄位

參數名稱 型態 說明 必須
uid string 購買票券交易訂單UID
key string 交易驗証碼
order_id string 購買票券交易票券交易編號
cost float 交易金額
currency string 交易幣別
actual_cost float 實際交易金額
actual_currency string 實際交易幣別
state integer 發票開立狀態
0.不處理 1等候處理中,2發票處理成功 3.發票處理失敗 5.系統服務異常
『票券電子發票開立狀態類型』值參考
date string 發票開立日期(YYYYMMDD)
wordtrack string 發票字軌
number string 發票號碼
rand_code string 隨機碼
seller_ban string 賣方統編
buyer_ban string 買方統編
left_qrcode string 左邊QrCode(電子發票查詢碼)
middle_barcode string 中間Barcode (Code-39格式)
right_qrcode string 右邊QrCode(電子發票產品資訊-精簡版)
amount string 電子發票開立總額
sales_amount float 電子發票銷售額
tax_amount float 電子發票稅額
order_detail string 電子發票開立之產品詳細資訊(JSON格式) 『商品細項』值參考
ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
input_type integer 電子發票開立類型 『電子發票開立類型』值參考
cloud_type integer 電子發票開立類型-雲端發票類型 『雲端發票類型』值參考
mobile_code string 當cloud_type為2時紀錄的手機條碼
tax_id string 當cloud_type為2時紀錄的統一編號
natural_person string 當cloud_type為3時紀錄的自然人憑證條碼
m_post_zone string 當cloud_type為4時紀錄中獎時紙本發票郵遞區號
m_address string 當cloud_type為4時紀錄中獎時紙本發票收件住址
love_code string 當input_type為2時紀錄的愛心碼
b2b_title string 當input_type為3時紀錄的發票抬頭
b2b_id string 當input_type為3時紀錄的統一編號
b2b_post_zone string 當input_type為3時紀錄的郵遞區號
b2b_address string 當input_type為3時紀錄的發票地址
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

購買票券交易查詢

<?php
/**
 * 經銷商串接-購買票券交易查詢
 */
final class AgentVoucherQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VS20221011112610";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherservicequery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherQuery = new AgentVoucherQuery();
$AgentVoucherQuery->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 AgentVoucherQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherQuery simulator = new AgentVoucherQuery();
            //僅限走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.order_id =  "VS20221011112610";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherservicequery";
            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 AgentVoucherQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherQuery simulator = new AgentVoucherQuery();
        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("order_id", "VS20221011112610");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherservicequery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherQuery.prototype.getRawData = function () {
    return {
        order_id: "VS20221011112610",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherservicequery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherQuery.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 到主機
 */
AgentVoucherQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherQuery = new AgentVoucherQuery();
AgentVoucherQuery.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 AgentVoucherQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VS20221011112610",
        }
        return rawData

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

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

    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)

AgentVoucherQuery = AgentVoucherQuery()
AgentVoucherQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": 100051,
        "key": "3fd356d92fc78a05189248536e8c89c5",
        "code": "250",
        "msg": "付款完成",
        "finishtime": "20220422135946",
        "order_id": "VS20220422135855",
        "user_id": "phper",
        "cost": 100,
        "currency": "TWD",
        "actual_cost": 100,
        "actual_currency": "TWD",
        "pfn": "CREDITCARD",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    }
}

消費者購買數位票券時,透過信用卡等多種支付方式作線上直接購買票券。

經銷商『購買票券交易查詢』參數說明

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

『購買票券交易查詢』欄位

參數名稱 型態 說明 必須
order_id string 購買票券交易票券交易編號 必填

『購買票券交易查詢』回傳欄位

參數名稱 型態 說明 必須
code string 購買交易狀態碼
msg string 回傳訊息
content object 『購買票券交易查詢回傳』欄位參考

票券核銷線下交易

<?php
/**
 * 經銷商串接-票券核銷線下交易
 */
final class AgentVoucherOffline
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['reimbursement_store_uid'] = "289151880142";
        $rawData['order_id'] = "VO20221208105157";
        $rawData['pay_token'] = "MYTIX12345678ABCDEFGH";
        $rawData['pos_trade_time'] = "20221208105157";
        $rawData['pos_id'] = "HC00001A2B";
        $rawData['clerk_no'] = "A01";
        $rawData['echo_0'] = "noodles-98";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucheroffline'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherOffline = new AgentVoucherOffline();
$AgentVoucherOffline->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 AgentVoucherOffline {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherOffline simulator = new AgentVoucherOffline();
            //僅限走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.reimbursement_store_uid =  "289151880142";
            rawData.order_id =  "VO20221208105157";
            rawData.pay_token =  "MYTIX12345678ABCDEFGH";
            rawData.pos_trade_time =  "20221208105157";
            rawData.pos_id =  "HC00001A2B";
            rawData.clerk_no =  "A01";
            rawData.echo_0 =  "noodles-98";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucheroffline";
            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 AgentVoucherQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherQuery simulator = new AgentVoucherQuery();
        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("order_id", "VS20221011112610");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherservicequery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherOffline() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherOffline.prototype.getRawData = function () {
    return {
        reimbursement_store_uid: "289151880142",
        order_id: "VO20221208105157",
        pay_token: "MYTIX12345678ABCDEFGH",
        pos_trade_time: "20221208105157",
        pos_id: "HC00001A2B",
        clerk_no: "A01",
        echo_0: "noodles-98",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherOffline.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucheroffline"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherOffline.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 到主機
 */
AgentVoucherOffline.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherOffline.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherOffline.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherOffline = new AgentVoucherOffline();
AgentVoucherOffline.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 AgentVoucherOffline:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'reimbursement_store_uid': "289151880142",
            'order_id': "VO20221208105157",
            'pay_token': "MYTIX12345678ABCDEFGH",
            'pos_trade_time': "20221208105157",
            'pos_id': "HC00001A2B",
            'clerk_no': "A01",
            'echo_0': "noodles-98",
        }
        return rawData

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

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

    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)

AgentVoucherOffline = AgentVoucherOffline()
AgentVoucherOffline.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100022",
        "key": "9c2e173dda5318ee2c32d88e95b401ed",
        "order_id": "VO20220422170139",
        "code": "250",
        "msg": "核銷成功。",
        "finishtime": "20220422170147",
        "pay_token": "MYTIX1E5A41322AFBD5C0",
        "pos_trade_time": "20220422170139",
        "pos_id": "HC00001A2B",
        "clerk_no": "A01",
        "items": [
            {
                "issuance_uid": "289151881006",
                "id": "MANOR004",
                "material_code": "",
                "name": "莊園拿鐵咖啡(贈)",
                "products": [
                    {
                        "amount": 1,
                        "cost": 0,
                        "price": 50,
                        "total_cost": 0,
                        "total_price": 50
                    }
                ],
                "vouchers": [
                    {
                        "serial_no": "AZO-GLHKTCV6-D44O6L4K-7ZMLRHL59",
                        "cost": 0,
                        "price": 50
                    }
                ]
            }
        ],
        "echo_0": "noodles-98",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    }
}

數位票券:消費者挑選商品產生Qrcode,POS透過掃碼取得核銷交易碼,發動票券核銷線下交易。 實體票券:消費者提供實體票券,POS透過掃碼取得票券號碼,發動票券核銷線下交易。(票券狀態需為4.售出)

經銷商『票券核銷線下交易』參數說明

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

『票券核銷線下交易』欄位

參數名稱 型態 說明 必須
reimbursement_from_type int 核銷點類型 『票券核銷點類型』值參考
reimbursement_store_uid string 核銷特約商店商務代號 reimbursement_from_type =1為必填
reimbursement_dealer_no string 自訂核銷點編號 reimbursement_from_type=2為必填
issuance_uid string 委託發行商商務代號 使用實體券時必填
pay_token string 核銷交易碼
格式1:MYTIX12345678ABCDEFGH共21碼(通常為數位券)
格式2:"[\"WU00000001\",\"WU00000001\"]" (JSON 格式 通常為實體券或實體數位混合,混合時,若有數位券只使用限定一組(一個消費者被掃))
必填
order_id string 票券核銷線下交易票券處理編號(唯一) 必填
pos_trade_time string POS 端交易日期時間(格式為YYYYMMDDHHmmss)
pos_id string POS 機號或設備機號
clerk_no string 收銀員代碼
success_returl string 核銷成功導頁網址
failure_returl string 核銷失敗導頁網址
reimbursement_order_id string 核銷店家訂單單號
issue_invoice_state int 票券核銷發票開立類型 『票券核銷發票開立類型』值參考
invoice object 當發票開立類型為1自行開立時,需帶入相關資訊 『票券核銷交易發票資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券核銷線下交易』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 『票券核銷線下交易資訊回傳』欄位參考

票券核銷線下交易查詢

<?php
/**
 * 經銷商串接-票券核銷線下交易查詢
 */
final class AgentVoucherOfflineQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VO20221004115857";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherofflinequery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherOfflineQuery = new AgentVoucherOfflineQuery();
$AgentVoucherOfflineQuery->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 AgentVoucherOfflineQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherOfflineQuery simulator = new AgentVoucherOfflineQuery();
            //僅限走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.order_id =  "VO20221004115857";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherofflinequery";
            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 AgentVoucherOfflineQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherOfflineQuery simulator = new AgentVoucherOfflineQuery();
        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("order_id", "VO20221004115857");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherofflinequery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherOfflineQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherOfflineQuery.prototype.getRawData = function () {
    return {
        order_id: "VO20221004115857",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherOfflineQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherofflinequery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherOfflineQuery.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 到主機
 */
AgentVoucherOfflineQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherOfflineQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherOfflineQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherOfflineQuery = new AgentVoucherOfflineQuery();
AgentVoucherOfflineQuery.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 AgentVoucherOfflineQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VO20221004115857",
        }
        return rawData

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

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

    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)

AgentVoucherOfflineQuery = AgentVoucherOfflineQuery()
AgentVoucherOfflineQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100022",
        "key": "9c2e173dda5318ee2c32d88e95b401ed",
        "order_id": "VO20220422170139",
        "code": "250",
        "msg": "核銷成功。",
        "finishtime": "20220422170147",
        "pay_token": "MYTIX1E5A41322AFBD5C0",
        "pos_trade_time": "20220422170139",
        "pos_id": "HC00001A2B",
        "clerk_no": "A01",
        "items": [
            {
                "issuance_uid": "289151881006",
                "id": "MANOR004",
                "name": "莊園拿鐵咖啡(贈)",
                "products": [
                    {
                        "amount": 1,
                        "cost": 0,
                        "price": 50,
                        "total_cost": 0,
                        "total_price": 50
                    }
                ],
                "vouchers": [
                    {
                        "serial_no": "AZO-GLHKTCV6-D44O6L4K-7ZMLRHL59",
                        "cost": 0,
                        "price": 50
                    }
                ]
            }
        ],
        "echo_0": "noodles-98",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    }
}

查詢票券核銷線下交易的交易結果。

經銷商『票券核銷線下交易查詢』參數說明

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

『票券核銷線下交易查詢』欄位

參數名稱 型態 說明 必須
order_id string 票券核銷線下交易票券處理編號 必填

『票券核銷線下交易查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券核銷線下交易資訊回傳』欄位參考

票券核銷交易取消

<?php
/**
 * 經銷商串接-票券核銷交易取消
 */
final class AgentVoucherReverse
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VR20221208105201";
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'id' => 'H01',
                                 'serial_no' => 'A00052'
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'id' => 'H01',
                                 'serial_no' => 'A00053'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherreverse'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherReverse = new AgentVoucherReverse();
$AgentVoucherReverse->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 AgentVoucherReverse {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherReverse simulator = new AgentVoucherReverse();
            //僅限走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 item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.id = "H01";
            item1.serial_no = "A00052";
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.id = "H01";
            item2.serial_no = "A00053";
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VR20221208105201";
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherreverse";
            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 AgentVoucherReverse {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherReverse simulator = new AgentVoucherReverse();
        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> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("id", "H01");
        item1.put("serial_no", "A00052");
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("id", "H01");
        item2.put("serial_no", "A00053");
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VR20221208105201");
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherreverse");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherReverse() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherReverse.prototype.getRawData = function () {
    return {
        order_id: "VR20221208105201",
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'id': "H01",
                    'serial_no': "A00052"
                   },
                   {
                    'issuance_uid': "289151881006",
                    'id': "H01",
                    'serial_no': "A00053"
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherReverse.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherreverse"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherReverse.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 到主機
 */
AgentVoucherReverse.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherReverse.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherReverse.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherReverse = new AgentVoucherReverse();
AgentVoucherReverse.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 AgentVoucherReverse:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VR20221208105201",
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'id': "H01",
                          'serial_no': "A00052"
                         },
                         {
                          'issuance_uid': "289151881006",
                          'id': "H01",
                          'serial_no': "A00053"
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherReverse = AgentVoucherReverse()
AgentVoucherReverse.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功。",
    "content": {
        "uid": "100017",
        "key": "569f18f82f7d82e473860124ea532888",
        "order_id": "VR20220422151024",
        "reverse_date": "20220429142230",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": "",
        "items": [
            {
                "issuance_uid": "289151881006",
                "id": "MANOR004",
                "serial_no": "AZO-GLHKTCV6-D44O6L4K-EMIMRPLYZ",
                "code": "250",
                "msg": "取消核銷成功"
            }
        ]
    }
}

30分鐘內,所核銷之票券,可取消票券核銷。

經銷商『票券核銷交易取消』參數說明

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

『票券核銷交易取消』欄位

參數名稱 型態 說明 必須
order_id string 票券核銷取消票券處理編號(唯一) 必填
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
items array 取消票券核銷資料 必填
每筆『票券取消項目』欄位參考

『票券核銷交易取消』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券核銷交易取消查詢』欄位參考

票券核銷交易取消查詢

<?php
/**
 * 經銷商串接-票券核銷交易取消查詢
 */
final class AgentVoucherReverseQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VR20221031093012";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherreversequery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherReverseQuery = new AgentVoucherReverseQuery();
$AgentVoucherReverseQuery->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 AgentVoucherReverseQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherReverseQuery simulator = new AgentVoucherReverseQuery();
            //僅限走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.order_id =  "VR20221031093012";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherreversequery";
            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 AgentVoucherReverseQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherReverseQuery simulator = new AgentVoucherReverseQuery();
        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("order_id", "VR20221031093012");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherreversequery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherReverseQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherReverseQuery.prototype.getRawData = function () {
    return {
        order_id: "VR20221031093012",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherReverseQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherreversequery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherReverseQuery.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 到主機
 */
AgentVoucherReverseQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherReverseQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherReverseQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherReverseQuery = new AgentVoucherReverseQuery();
AgentVoucherReverseQuery.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 AgentVoucherReverseQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VR20221031093012",
        }
        return rawData

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

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

    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)

AgentVoucherReverseQuery = AgentVoucherReverseQuery()
AgentVoucherReverseQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100017",
        "key": "569f18f82f7d82e473860124ea532888",
        "order_id": "VR20220422151024",
        "reverse_date": "20220429142230",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": "",
        "items": [
            {
                "issuance_uid": "289151881006",
                "id": "MANOR004",
                "serial_no": "AZO-GLHKTCV6-D44O6L4K-EMIMRPLYZ",
                "code": "250",
                "msg": "取消核銷成功"
            }
        ]
    }
}

查詢票券核銷交易取消紀錄。

經銷商『票券核銷線下交易查詢』參數說明

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

『票券核銷交易取消查詢』欄位

參數名稱 型態 說明 必須
order_id string 票券核銷取消票券處理編號 必填

『票券核銷交易取消查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券核銷交易取消查詢』欄位參考

票券售出

<?php
/**
 * 經銷商串接-票券售出
 */
final class AgentVoucherSold
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VS20240418165204";
        $rawData['sales_from_type'] = 2;
        $rawData['sales_dealer_no'] = "A0001";
        $rawData['sales_order_id'] = "T20240418165204";
        $rawData['trust_start_date'] = "20240418";
        $rawData['trust_end_date'] = "20260417";
        $rawData['issue_invoice_state'] = 1;
        $rawData['invoice'] = [
                               'number' => 'AB12345678',
                               'date' => '20240418165204'
                              ];
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088012'
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088020'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/vouchersold'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherSold = new AgentVoucherSold();
$AgentVoucherSold->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 AgentVoucherSold {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherSold simulator = new AgentVoucherSold();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            dynamic invoice = new ExpandoObject();
            invoice.number = "AB12345678";
            invoice.date = "20240418165204";

            ArrayList items = new ArrayList();

            dynamic item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.no = "2051088012";
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.no = "2051088020";
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VS20240418165204";
            rawData.sales_from_type =  2;
            rawData.sales_dealer_no =  "A0001";
            rawData.sales_order_id =  "T20240418165204";
            rawData.trust_start_date =  "20240418";
            rawData.trust_end_date =  "20260417";
            rawData.issue_invoice_state =  1;
            rawData.invoice = invoice;
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/vouchersold";
            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 AgentVoucherSold {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherSold simulator = new AgentVoucherSold();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        Map<Object, Object> invoice = new HashMap<Object, Object>();
        invoice.put("number", "AB12345678");
        invoice.put("date", "20240418165204");

        ArrayList items = new ArrayList();

        Map<Object, Object> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("no", "2051088012");
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("no", "2051088020");
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VS20240418165204");
        rawData.put("sales_from_type", 2);
        rawData.put("sales_dealer_no", "A0001");
        rawData.put("sales_order_id", "T20240418165204");
        rawData.put("trust_start_date", "20240418");
        rawData.put("trust_end_date", "20260417");
        rawData.put("issue_invoice_state", 1);
        rawData.put("invoice", invoice);
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/vouchersold");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherSold() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherSold.prototype.getRawData = function () {
    return {
        order_id: "VS20240418165204",
        sales_from_type: 2,
        sales_dealer_no: "A0001",
        sales_order_id: "T20240418165204",
        trust_start_date: "20240418",
        trust_end_date: "20260417",
        issue_invoice_state: 1,
        invoice: {
                  'number': "AB12345678",
                  'date': "20240418165204"
                 },
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088012"
                   },
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088020"
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherSold.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/vouchersold"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherSold.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 到主機
 */
AgentVoucherSold.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherSold.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherSold.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherSold = new AgentVoucherSold();
AgentVoucherSold.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 AgentVoucherSold:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VS20240418165204",
            'sales_from_type': 2,
            'sales_dealer_no': "A0001",
            'sales_order_id': "T20240418165204",
            'trust_start_date': "20240418",
            'trust_end_date': "20260417",
            'issue_invoice_state': 1,
            'invoice': {
                        'number': "AB12345678",
                        'date': "20240418165204"
                       },
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088012"
                         },
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088020"
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherSold = AgentVoucherSold()
AgentVoucherSold.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100076",
        "key": "948c3aa0e08665a06836926a0d635954",
        "order_id": "VS20240419144323",
        "sales_date": "20240419144346",
        "items": [
            {
                "issuance_uid": "289151881006",
                "unit_type": 1,
                "no": "2051088152",
                "ticket": {
                    "custom_serial_no": "2051088152",
                    "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC"
                },
                "book": []
            }
        ],
        "sales_order_id": "T20240419144323",
        "issue_invoice_state": 1,
        "invoice": {
            "number": "AB12345678",
            "date": "20240419144323"
        },
        "trust_start_date": "20240419",
        "trust_end_date": "20260418",
        "sales_from_type": 2,
        "sales_store_uid": "",
        "sales_dealer_no": "A0001",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    }
}

提供實體票券售出後,回報票券售出。(票券狀態1.建立時才可回報售出)

經銷商『票券售出』參數說明

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

『票券售出』欄位

參數名稱 型態 說明 必須
order_id string 票券售出票券處理編號(唯一) 必填
sales_from_type int 銷售點類型 必填
『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號 sales_from_type=1為必填
sales_dealer_no string 自訂銷售點編號 sales_from_type=2為必填
trust_start_date string 票券履約保證起始日(格式:YYYYMMDD) 必填
trust_end_date string 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD) 必填
api_mode int 票券掃碼方式 『票券售出票券掃碼方式』值參考
items array 票券銷售資料 必填
每筆『票券售出項目』欄位參考
sales_order_id string 銷售店家訂單單號
issue_invoice_state int 票券售出發票開立類型 『票券售出發票開立類型』值參考
invoice object 當發票開立類型為1自行開立時,需帶入相關資訊 『票券售出交易發票資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券售出』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 票券售出交易內容 『票券售出交易內容』欄位參考

票券售出交易查詢

<?php
/**
 * 經銷商串接-票券售出交易查詢
 */
final class AgentVoucherSoldQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VS20221031093012";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/vouchersoldquery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherSoldQuery = new AgentVoucherSoldQuery();
$AgentVoucherSoldQuery->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 AgentVoucherSoldQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherSoldQuery simulator = new AgentVoucherSoldQuery();
            //僅限走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.order_id =  "VS20221031093012";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/vouchersoldquery";
            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 AgentVoucherSoldQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherSoldQuery simulator = new AgentVoucherSoldQuery();
        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("order_id", "VS20221031093012");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/vouchersoldquery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherSoldQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherSoldQuery.prototype.getRawData = function () {
    return {
        order_id: "VS20221031093012",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherSoldQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/vouchersoldquery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherSoldQuery.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 到主機
 */
AgentVoucherSoldQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherSoldQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherSoldQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherSoldQuery = new AgentVoucherSoldQuery();
AgentVoucherSoldQuery.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 AgentVoucherSoldQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VS20221031093012",
        }
        return rawData

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

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

    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)

AgentVoucherSoldQuery = AgentVoucherSoldQuery()
AgentVoucherSoldQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "code": "B200",
        "msg": "執行成功",
        "uid": "100076",
        "key": "948c3aa0e08665a06836926a0d635954",
        "order_id": "VS20240419144323",
        "sales_date": "20240419144346",
        "items": [
            {
                "issuance_uid": "289151881006",
                "unit_type": 1,
                "no": "2051088152",
                "ticket": {
                    "custom_serial_no": "2051088152",
                    "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC"
                },
                "book": []
            }
        ],
        "sales_order_id": "T20240419144323",
        "issue_invoice_state": 1,
        "invoice": {
            "number": "AB12345678",
            "date": "20240419144323"
        },
        "trust_start_date": "20240419",
        "trust_end_date": "20260418",
        "sales_from_type": 2,
        "sales_store_uid": "",
        "sales_dealer_no": "A0001",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": ""
    }
}

提供票券售出交易之訂單查詢。

經銷商『票券售出交易查詢』參數說明

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

『票券售出交易查詢』欄位

參數名稱 型態 說明 必須
order_id string 票券售出票券處理編號 必填

『票券售出交易查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券售出交易內容』欄位參考

票券售出交易取消

<?php
/**
 * 經銷商串接-票券售出交易取消
 */
final class AgentVoucherSoldReverse
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VSR20240418165205";
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088039'
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088047'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/vouchersoldreverse'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherSoldReverse = new AgentVoucherSoldReverse();
$AgentVoucherSoldReverse->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 AgentVoucherSoldReverse {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherSoldReverse simulator = new AgentVoucherSoldReverse();
            //僅限走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 item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.no = "2051088039";
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.no = "2051088047";
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VSR20240418165205";
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/vouchersoldreverse";
            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 AgentVoucherSoldReverse {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherSoldReverse simulator = new AgentVoucherSoldReverse();
        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> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("no", "2051088039");
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("no", "2051088047");
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VSR20240418165205");
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/vouchersoldreverse");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherSoldReverse() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherSoldReverse.prototype.getRawData = function () {
    return {
        order_id: "VSR20240418165205",
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088039"
                   },
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088047"
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherSoldReverse.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/vouchersoldreverse"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherSoldReverse.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 到主機
 */
AgentVoucherSoldReverse.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherSoldReverse.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherSoldReverse.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherSoldReverse = new AgentVoucherSoldReverse();
AgentVoucherSoldReverse.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 AgentVoucherSoldReverse:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VSR20240418165205",
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088039"
                         },
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088047"
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherSoldReverse = AgentVoucherSoldReverse()
AgentVoucherSoldReverse.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100026",
        "key": "fc195aea975ad710bc01b9b5b8234c42",
        "order_id": "VSR20240419145148",
        "reverse_date": "20240419145203",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": "",
        "items": [
            {
                "issuance_uid": "289151881006",
                "unit_type": 1,
                "no": "2051088152",
                "ticket": {
                    "custom_serial_no": "2051088152",
                    "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC",
                    "book_no": "",
                    "sales_date": "20240419144346",
                    "status": 4
                },
                "book": [],
                "code": "250",
                "msg": "取消售出成功"
            }
        ]
    }
}

30分鐘內,所售出之票券,可取消票券售出。

經銷商『票券售出交易取消』參數說明

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

『票券售出交易取消』欄位

參數名稱 型態 說明 必須
order_id string 票券售出取消票券處理編號(唯一) 必填
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
api_mode int 票券掃碼方式 『票券售出票券掃碼方式』值參考
items array 取消票券售出資料 必填
每筆『票券售出取消項目』欄位參考

『票券售出交易取消』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券售出交易取消查詢』欄位參考

票券售出交易取消查詢

<?php
/**
 * 經銷商串接-票券售出交易取消查詢
 */
final class AgentVoucherSoldReverseQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VSR20221031093012";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/vouchersoldreversequery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherSoldReverseQuery = new AgentVoucherSoldReverseQuery();
$AgentVoucherSoldReverseQuery->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 AgentVoucherSoldReverseQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherSoldReverseQuery simulator = new AgentVoucherSoldReverseQuery();
            //僅限走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.order_id =  "VSR20221031093012";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/vouchersoldreversequery";
            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 AgentVoucherSoldReverseQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherSoldReverseQuery simulator = new AgentVoucherSoldReverseQuery();
        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("order_id", "VSR20221031093012");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/vouchersoldreversequery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherSoldReverseQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherSoldReverseQuery.prototype.getRawData = function () {
    return {
        order_id: "VSR20221031093012",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherSoldReverseQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/vouchersoldreversequery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherSoldReverseQuery.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 到主機
 */
AgentVoucherSoldReverseQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherSoldReverseQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherSoldReverseQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherSoldReverseQuery = new AgentVoucherSoldReverseQuery();
AgentVoucherSoldReverseQuery.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 AgentVoucherSoldReverseQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VSR20221031093012",
        }
        return rawData

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

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

    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)

AgentVoucherSoldReverseQuery = AgentVoucherSoldReverseQuery()
AgentVoucherSoldReverseQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "uid": "100026",
        "key": "fc195aea975ad710bc01b9b5b8234c42",
        "order_id": "VSR20240419145148",
        "reverse_date": "20240419145203",
        "echo_0": "",
        "echo_1": "",
        "echo_2": "",
        "echo_3": "",
        "echo_4": "",
        "items": [
            {
                "issuance_uid": "289151881006",
                "unit_type": 1,
                "no": "2051088152",
                "ticket": {
                    "custom_serial_no": "2051088152",
                    "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-1NQUYYBQC",
                    "book_no": "",
                    "sales_date": "20240419144346",
                    "status": 4
                },
                "book": [],
                "code": "250",
                "msg": "取消售出成功"
            }
        ]
    }
}

提供票券售出交易取消之訂單查詢。

經銷商『票券售出交易取消查詢』參數說明

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

『票券售出交易取消查詢』欄位

參數名稱 型態 說明 必須
order_id string 票券售出取消票券處理編號 必填

『票券售出交易取消查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券售出交易取消查詢』欄位參考

票券作廢

<?php
/**
 * 經銷商串接-票券作廢
 */
final class AgentVoucherInvalid
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VI20240418165206";
        $rawData['invalid_from_type'] = 2;
        $rawData['invalid_dealer_no'] = "A0001";
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088055'
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088063'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherinvalid'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherInvalid = new AgentVoucherInvalid();
$AgentVoucherInvalid->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 AgentVoucherInvalid {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherInvalid simulator = new AgentVoucherInvalid();
            //僅限走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 item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.no = "2051088055";
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.no = "2051088063";
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VI20240418165206";
            rawData.invalid_from_type =  2;
            rawData.invalid_dealer_no =  "A0001";
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherinvalid";
            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 AgentVoucherInvalid {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherInvalid simulator = new AgentVoucherInvalid();
        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> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("no", "2051088055");
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("no", "2051088063");
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VI20240418165206");
        rawData.put("invalid_from_type", 2);
        rawData.put("invalid_dealer_no", "A0001");
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherinvalid");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherInvalid() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherInvalid.prototype.getRawData = function () {
    return {
        order_id: "VI20240418165206",
        invalid_from_type: 2,
        invalid_dealer_no: "A0001",
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088055"
                   },
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088063"
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherInvalid.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherinvalid"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherInvalid.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 到主機
 */
AgentVoucherInvalid.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherInvalid.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherInvalid.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherInvalid = new AgentVoucherInvalid();
AgentVoucherInvalid.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 AgentVoucherInvalid:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VI20240418165206",
            'invalid_from_type': 2,
            'invalid_dealer_no': "A0001",
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088055"
                         },
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088063"
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherInvalid = AgentVoucherInvalid()
AgentVoucherInvalid.run()

回傳 JSON 結構如下:


提供票券回報作廢註記。(票券狀態1.建立 4.售出才可回報作廢)

經銷商『票券作廢』參數說明

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

『票券作廢』欄位

參數名稱 型態 說明 必須
order_id string 票券作廢票券處理編號(唯一) 必填
invalid_from_type int 作廢點類型 必填
『票券作廢點類型』值參考
invalid_store_uid string 作廢特約商店商務代號 invalid_from_type=1為必填
invalid_dealer_no string 自訂作廢點編號 invalid_from_type=2為必填
items array 票券作廢資料 必填
每筆『票券作廢項目』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券作廢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 票券作廢交易內容 『票券作廢交易內容』欄位參考

票券作廢交易查詢

<?php
/**
 * 經銷商串接-票券作廢交易查詢
 */
final class AgentVoucherInvalidQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VI20221031093012";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherinvalidquery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherInvalidQuery = new AgentVoucherInvalidQuery();
$AgentVoucherInvalidQuery->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 AgentVoucherInvalidQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherInvalidQuery simulator = new AgentVoucherInvalidQuery();
            //僅限走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.order_id =  "VI20221031093012";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherinvalidquery";
            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 AgentVoucherInvalidQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherInvalidQuery simulator = new AgentVoucherInvalidQuery();
        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("order_id", "VI20221031093012");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherinvalidquery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherInvalidQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherInvalidQuery.prototype.getRawData = function () {
    return {
        order_id: "VI20221031093012",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherInvalidQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherinvalidquery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherInvalidQuery.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 到主機
 */
AgentVoucherInvalidQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherInvalidQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherInvalidQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherInvalidQuery = new AgentVoucherInvalidQuery();
AgentVoucherInvalidQuery.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 AgentVoucherInvalidQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VI20221031093012",
        }
        return rawData

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

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

    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)

AgentVoucherInvalidQuery = AgentVoucherInvalidQuery()
AgentVoucherInvalidQuery.run()

回傳 JSON 結構如下:


提供票券作廢交易之訂單查詢。

經銷商『票券作廢交易查詢』參數說明

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

『票券作廢交易查詢』欄位

參數名稱 型態 說明 必須
order_id string 票券作廢票券處理編號 必填

『票券作廢交易查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 查詢內容 『票券作廢交易內容』欄位參考

票券狀態查詢

<?php
/**
 * 經銷商串接-票券狀態查詢
 */
final class AgentVoucherStatusQuery
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['items'] = [
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088071'
                                ],
                                [
                                 'issuance_uid' => '289151881006',
                                 'no' => '2051088080'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherstatusquery'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherStatusQuery = new AgentVoucherStatusQuery();
$AgentVoucherStatusQuery->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 AgentVoucherStatusQuery {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherStatusQuery simulator = new AgentVoucherStatusQuery();
            //僅限走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 item1 = new ExpandoObject();
            item1.issuance_uid = "289151881006";
            item1.no = "2051088071";
            items.Add(item1);

            dynamic item2 = new ExpandoObject();
            item2.issuance_uid = "289151881006";
            item2.no = "2051088080";
            items.Add(item2);


            dynamic rawData = new ExpandoObject();
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherstatusquery";
            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 AgentVoucherStatusQuery {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherStatusQuery simulator = new AgentVoucherStatusQuery();
        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> item1 = new HashMap<Object, Object>();
        item1.put("issuance_uid", "289151881006");
        item1.put("no", "2051088071");
        items.add(item1);

        Map<Object, Object> item2 = new HashMap<Object, Object>();
        item2.put("issuance_uid", "289151881006");
        item2.put("no", "2051088080");
        items.add(item2);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherstatusquery");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherStatusQuery() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherStatusQuery.prototype.getRawData = function () {
    return {
        items: [
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088071"
                   },
                   {
                    'issuance_uid': "289151881006",
                    'no': "2051088080"
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherStatusQuery.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherstatusquery"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherStatusQuery.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 到主機
 */
AgentVoucherStatusQuery.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherStatusQuery.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherStatusQuery.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherStatusQuery = new AgentVoucherStatusQuery();
AgentVoucherStatusQuery.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 AgentVoucherStatusQuery:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'items': [
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088071"
                         },
                         {
                          'issuance_uid': "289151881006",
                          'no': "2051088080"
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherStatusQuery = AgentVoucherStatusQuery()
AgentVoucherStatusQuery.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": [
        {
            "issuance_uid": "289151881006",
            "unit_type": 1,
            "no": "2051088071",
            "ticket": {
                "status": 31,
                "custom_serial_no": "2051088071",
                "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-AG5IQAIUM",
                "book_no": "",
                "sales_from_type": 2,
                "sales_store_uid": "",
                "sales_dealer_no": "A0001",
                "reimbursement_from_type": 2,
                "reimbursement_store_uid": "",
                "reimbursement_dealer_no": "A0002",
                "invalid_from_type": 1,
                "invalid_store_uid": "",
                "invalid_dealer_no": ""
            },
            "book": []
        },
        {
            "issuance_uid": "289151881006",
            "unit_type": 1,
            "no": "2051088080",
            "ticket": {
                "status": 31,
                "custom_serial_no": "2051088080",
                "serial_no": "VEU9GUOO-D67NPAWV-A4444AD4DB4BUQ9-157ZN69FN",
                "book_no": "",
                "sales_from_type": 2,
                "sales_store_uid": "",
                "sales_dealer_no": "A0001",
                "reimbursement_from_type": 2,
                "reimbursement_store_uid": "",
                "reimbursement_dealer_no": "A0002",
                "invalid_from_type": 1,
                "invalid_store_uid": "",
                "invalid_dealer_no": ""
            },
            "book": []
        }
    ]
}

提供查詢票券目前最新之票券狀態。

經銷商『票券狀態查詢』參數說明

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

『票券狀態查詢』欄位

參數名稱 型態 說明 必須
items array 票券狀態查詢項目 必填
每筆『票券狀態查詢項目』欄位參考

『票券狀態查詢』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content array 內容 每筆『票券狀態資訊回傳』欄位參考

票券核銷線下交易Qrcode掃碼頁面

<?php
/**
 * 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
 */
final class AgentVoucherOfflineQrcodePage
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['user_id'] = "phper";
        $rawData['qrcode_type'] = "2";
        $rawData['page_type'] = "1";
        $rawData['issuance_uid'] = [
                                    "289151881006"
                                   ];
        $rawData['homepage_url'] = "https://www.mypay.com.tw/";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherofflineqrcodepage'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherOfflineQrcodePage = new AgentVoucherOfflineQrcodePage();
$AgentVoucherOfflineQrcodePage->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>
    /// 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
    /// </summary>
    public class AgentVoucherOfflineQrcodePage {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherOfflineQrcodePage simulator = new AgentVoucherOfflineQrcodePage();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList issuanceUid = new ArrayList();

            issuanceUid.Add("289151881006");


            dynamic rawData = new ExpandoObject();
            rawData.user_id =  "phper";
            rawData.qrcode_type =  "2";
            rawData.page_type =  "1";
            rawData.issuance_uid = issuanceUid;
            rawData.homepage_url =  "https://www.mypay.com.tw/";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherofflineqrcodepage";
            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;
/**
 * 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
 * 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 AgentVoucherOfflineQrcodePage {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherOfflineQrcodePage simulator = new AgentVoucherOfflineQrcodePage();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList issuanceUid = new ArrayList();

        issuanceUid.add(new String("289151881006"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("user_id", "phper");
        rawData.put("qrcode_type", "2");
        rawData.put("page_type", "1");
        rawData.put("issuance_uid", issuanceUid);
        rawData.put("homepage_url", "https://www.mypay.com.tw/");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherofflineqrcodepage");
        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) {
            System.out.println(e.getMessage());
        }
        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');

/**
 * 經銷商串接-票券核銷線下交易Qrcode掃碼頁面
 */
function AgentVoucherOfflineQrcodePage() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherOfflineQrcodePage.prototype.getRawData = function () {
    return {
        user_id: "phper",
        qrcode_type: "2",
        page_type: "1",
        issuance_uid: [
                       "289151881006"
                      ],
        homepage_url: "https://www.mypay.com.tw/",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherOfflineQrcodePage.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherofflineqrcodepage"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherOfflineQrcodePage.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 到主機
 */
AgentVoucherOfflineQrcodePage.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherOfflineQrcodePage.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherOfflineQrcodePage.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherOfflineQrcodePage = new AgentVoucherOfflineQrcodePage();
AgentVoucherOfflineQrcodePage.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

"""經銷商串接-票券核銷線下交易Qrcode掃碼頁面
"""
class AgentVoucherOfflineQrcodePage:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'user_id': "phper",
            'qrcode_type': "2",
            'page_type': "1",
            'issuance_uid': [
                             "289151881006"
                            ],
            'homepage_url': "https://www.mypay.com.tw/",
        }
        return rawData

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

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

    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)

AgentVoucherOfflineQrcodePage = AgentVoucherOfflineQrcodePage()
AgentVoucherOfflineQrcodePage.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "url": "https:\/\/ka.usecase.cc\/voucher\/qrcode\/54acf767.html"
}

取得消費者使用票券消費頁面,當消費者選擇後,顯示Qrcode提供給商家掃碼。

經銷商『票券核銷線下交易Qrcode掃碼頁面』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/voucherofflineqrcodepage"}
JSON格式,AES256加密資料
encry_data text 『票券核銷線下交易Qrcode掃碼頁面』欄位參考
JSON格式,AES256加密資料

『票券核銷線下交易Qrcode掃碼頁面』欄位

參數名稱 型態 說明 必須
user_id string 消費者帳號 必填
qrcode_type string Qrcode內容模式 『Qrcode內容模式』值參考
page_type string 票券顯示模式 『票券顯示模式』值參考
issuance_uid array 以委託發行商顯示票券之委託發行商商務代號
1.資訊商發動,可以帶不同的委託發行商
2.委託發行商發動,只能自己本身委託發行商
reimbursement_store_uid string 以可核銷之特約商店顯示票券之核銷特約商店商務代號
theme string 指定佈景主題名稱
homepage_url string 返回首頁連結

『票券核銷線下交易Qrcode掃碼頁面』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
url string 消費網址

票券消費者退券頁面(消費者主動)

/**
 * 經銷商串接-票券退券(消費者主動)
 */
final class AgentVoucherUserRefund
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_uid'] = "VU20221208105205";
        $rawData['user_id'] = "phper";
        $rawData['page_type'] = "1";
        $rawData['issuance_uid'] = [
                                    "289151881006"
                                   ];
        $rawData['homepage_url'] = "https://www.mypay.com.tw/";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucheruserrefundpage'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

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

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 AgentVoucherUserRefund {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherUserRefund simulator = new AgentVoucherUserRefund();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList issuanceUid = new ArrayList();

        issuanceUid.add(new String("289151881006"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_uid", "VU20221208105205");
        rawData.put("user_id", "phper");
        rawData.put("page_type", "1");
        rawData.put("issuance_uid", issuanceUid);
        rawData.put("homepage_url", "https://www.mypay.com.tw/");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucheruserrefundpage");
        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) {
            System.out.println(e.getMessage());
        }
        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;
    }
}

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 AgentVoucherUserRefund {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherUserRefund simulator = new AgentVoucherUserRefund();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList issuanceUid = new ArrayList();

            issuanceUid.Add("289151881006");


            dynamic rawData = new ExpandoObject();
            rawData.order_uid =  "VU20221208105205";
            rawData.user_id =  "phper";
            rawData.page_type =  "1";
            rawData.issuance_uid = issuanceUid;
            rawData.homepage_url =  "https://www.mypay.com.tw/";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucheruserrefundpage";
            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; }
    }
}

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

/**
 * 經銷商串接-票券退券(消費者主動)
 */
function AgentVoucherUserRefund() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherUserRefund.prototype.getRawData = function () {
    return {
        order_uid: "VU20221208105205",
        user_id: "phper",
        page_type: "1",
        issuance_uid: [
                       "289151881006"
                      ],
        homepage_url: "https://www.mypay.com.tw/",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherUserRefund.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucheruserrefundpage"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherUserRefund.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 到主機
 */
AgentVoucherUserRefund.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherUserRefund.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherUserRefund.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherUserRefund = new AgentVoucherUserRefund();
AgentVoucherUserRefund.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 AgentVoucherUserRefund:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_uid': "VU20221208105205",
            'user_id': "phper",
            'page_type': "1",
            'issuance_uid': [
                             "289151881006"
                            ],
            'homepage_url': "https://www.mypay.com.tw/",
        }
        return rawData

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

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

    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)

AgentVoucherUserRefund = AgentVoucherUserRefund()
AgentVoucherUserRefund.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "url": "https:\/\/ka.usecase.cc\/voucher\/refund\/54acf767.html"
}

店家發動API,取得退劵網址,消費者登入後,自行選取需要退劵的品項,待退劵完畢後,若有導轉網址,5秒鐘後會自行導轉

注意事項:實際退款時間為隔日11點後陸續退款

經銷商『票券消費者退劵頁面』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/voucheruserrefundpage"}
JSON格式,AES256加密資料
encry_data text 『票券消費者退券頁面』欄位參考
JSON格式,AES256加密資料

『票券消費者退劵頁面』欄位

參數名稱 型態 說明 必須
order_uid string 票券退券交易票券處理編號(唯一)
user_id string 消費者帳號 必填
page_type string 票券顯示模式 『票券顯示模式』值參考
issuance_uid array 以委託發行商顯示票券之委託發行商商務代號
1.資訊商發動,可以帶不同的委託發行商
2.委託發行商發動,只能自己本身委託發行商
theme string 指定佈景主題名稱
homepage_url string 返回首頁連結
success_returl string 成功退劵畫面
failure_returl string 退劵失敗畫面

『票券退券交易』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『退券執行狀態碼』值參考
msg string 回傳訊息
content object 退劵回傳系項資訊 『退劵回傳細項資訊』值參考

『消費者票券退券執行結果』回傳欄位

參數名稱 型態 說明 備註
order_id string 退券訂單編號 如果消費是從票券匣退券,則由系統自動配號
uid string 票券退券交易UID
key string 驗証碼
code string 退券狀態碼
msg string 狀態碼訊息
refund_date string 退券完成時間(YYYYMMDDHHIISS)
items array 退券產品 『退券產品資料』值參考

『退券產品資料』回傳欄位

參數名稱 型態 說明 備註
sales_store_uid string 銷售點特約商店代碼
headquarters_agent_uid string 總部商務代號
issuance_uid string 委託發行商商務代號
id string 票券產品編號
serial_no string 票券序號
price string 定價
cost string 單價
name string 產品名稱
material_code string 委託發行商的商品料號

票券轉贈(消費者主動)

<?php
/**
 * 經銷商串接-票券轉贈(消費者主動)
 */
final class AgentVoucherGift
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VG20221208105207";
        $rawData['user_id'] = "phper";
        $rawData['page_type'] = "1";
        $rawData['issuance_uid'] = [
                                    "289151881006"
                                   ];
        $rawData['homepage_url'] = "https://www.mypay.com.tw/";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/vouchergift'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherGift = new AgentVoucherGift();
$AgentVoucherGift->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 AgentVoucherGift {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherGift simulator = new AgentVoucherGift();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList issuanceUid = new ArrayList();

            issuanceUid.Add("289151881006");


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VG20221208105207";
            rawData.user_id =  "phper";
            rawData.page_type =  "1";
            rawData.issuance_uid = issuanceUid;
            rawData.homepage_url =  "https://www.mypay.com.tw/";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/vouchergift";
            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 AgentVoucherGift {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherGift simulator = new AgentVoucherGift();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList issuanceUid = new ArrayList();

        issuanceUid.add(new String("289151881006"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VG20221208105207");
        rawData.put("user_id", "phper");
        rawData.put("page_type", "1");
        rawData.put("issuance_uid", issuanceUid);
        rawData.put("homepage_url", "https://www.mypay.com.tw/");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/vouchergift");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherGift() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherGift.prototype.getRawData = function () {
    return {
        order_id: "VG20221208105207",
        user_id: "phper",
        page_type: "1",
        issuance_uid: [
                       "289151881006"
                      ],
        homepage_url: "https://www.mypay.com.tw/",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherGift.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/vouchergift"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherGift.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 到主機
 */
AgentVoucherGift.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherGift.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherGift.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherGift = new AgentVoucherGift();
AgentVoucherGift.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 AgentVoucherGift:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VG20221208105207",
            'user_id': "phper",
            'page_type': "1",
            'issuance_uid': [
                             "289151881006"
                            ],
            'homepage_url': "https://www.mypay.com.tw/",
        }
        return rawData

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

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

    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)

AgentVoucherGift = AgentVoucherGift()
AgentVoucherGift.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "url": "https:\/\/mytix.usecase.cc\/voucher\/gift\/6bfe4cac.html",
        "uid": "100100",
        "key": "4626ebbd99541c0b139bc5bd478d2861"
    }
}

發動API後,消費者取得連結,並連結到票券轉贈頁面。透過指定的手機號碼,轉贈給予會員與非會員。當轉贈完成,依照簡訊設定,由MYTIX發送,或由委託發行商自行發送(MYTIX會發送『票券轉贈簡訊通知』)。 會員則依票券核銷線下交易Qrcode掃碼頁面功能進行核銷,非會員則在簡訊通知後,透過指定連結並解輸入手機號碼號,進行Qrcode掃碼頁面功能。

『票券轉贈(消費者主動)』欄位

參數名稱 型態 說明 必須
order_id string 票券轉贈交易票券處理編號(唯一) 必填
user_id string 消費者帳號 必填
page_type string 票券顯示模式 必填
『票券顯示模式』值參考
issuance_uid array 以委託發行商顯示票券之委託發行商商務代號
1.資訊商發動,可以帶不同的委託發行商
2.委託發行商發動,只能自己本身委託發行商
必填
success_returl string 成功轉贈畫面
failure_returl string 轉贈失敗畫面
homepage_url string 返回首頁連結
theme string 指定佈景主題名稱
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券轉贈(消費者主動)』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 票券轉贈回傳細項資訊 『票券轉贈回傳細項資訊』欄位參考

『票券轉贈簡訊通知』回報欄位

參數名稱 型態 說明 必須
sms_type integer 簡訊通知類型
1.票券轉贈簡訊通知
content object 簡訊通知內容 『票券轉贈簡訊通知』欄位參考

票券匣

1.發動API後,取得票券匣連結,消費者可在此操作票券匣。票券匣整合了Qrcode掃碼、退券、轉贈功能以及使用紀錄。
2.如要查看退劵執行回傳通知內容請查詢『消費者票券退券執行結果』

<?php
/**
 * 經銷商串接-票券匣
 */
final class AgentVoucherBoxes
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['order_id'] = "VB20221208105209";
        $rawData['user_id'] = "phper";
        $rawData['page_type'] = "1";
        $rawData['issuance_uid'] = [
                                    "289151881006"
                                   ];
        $rawData['homepage_url'] = "https://www.mypay.com.tw/";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherboxes'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherBoxes = new AgentVoucherBoxes();
$AgentVoucherBoxes->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 AgentVoucherBoxes {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherBoxes simulator = new AgentVoucherBoxes();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList issuanceUid = new ArrayList();

            issuanceUid.Add("289151881006");


            dynamic rawData = new ExpandoObject();
            rawData.order_id =  "VB20221208105209";
            rawData.user_id =  "phper";
            rawData.page_type =  "1";
            rawData.issuance_uid = issuanceUid;
            rawData.homepage_url =  "https://www.mypay.com.tw/";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherboxes";
            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 AgentVoucherBoxes {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherBoxes simulator = new AgentVoucherBoxes();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList issuanceUid = new ArrayList();

        issuanceUid.add(new String("289151881006"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("order_id", "VB20221208105209");
        rawData.put("user_id", "phper");
        rawData.put("page_type", "1");
        rawData.put("issuance_uid", issuanceUid);
        rawData.put("homepage_url", "https://www.mypay.com.tw/");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherboxes");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherBoxes() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherBoxes.prototype.getRawData = function () {
    return {
        order_id: "VB20221208105209",
        user_id: "phper",
        page_type: "1",
        issuance_uid: [
                       "289151881006"
                      ],
        homepage_url: "https://www.mypay.com.tw/",

    };
};
/**
 * 取得服務位置
 */
AgentVoucherBoxes.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherboxes"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherBoxes.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 到主機
 */
AgentVoucherBoxes.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherBoxes.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherBoxes.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherBoxes = new AgentVoucherBoxes();
AgentVoucherBoxes.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 AgentVoucherBoxes:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'order_id': "VB20221208105209",
            'user_id': "phper",
            'page_type': "1",
            'issuance_uid': [
                             "289151881006"
                            ],
            'homepage_url': "https://www.mypay.com.tw/",
        }
        return rawData

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

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

    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)

AgentVoucherBoxes = AgentVoucherBoxes()
AgentVoucherBoxes.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "url": "https:\/\/mytix.usecase.cc\/voucher\/boxes\/0279496f.html",
        "uid": "100060",
        "key": "35b4dd522d1280dcb1d63718dcbeed0f"
    }
}


『票券匣』欄位

參數名稱 型態 說明 必須
order_id string 票券匣處理編號(唯一) 必填
user_id string 消費者帳號 必填
page_type string 票券顯示模式 必填
『票券顯示模式』值參考
issuance_uid array 以委託發行商顯示票券之委託發行商商務代號
1.資訊商發動,可以帶不同的委託發行商
2.委託發行商發動,只能自己本身委託發行商
必填
homepage_url string 返回首頁連結
theme string 佈景主題名稱
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券匣』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content object 票券轉贈回傳細項資訊 『票券匣回傳細項資訊』欄位參考

『票券匣轉贈簡訊通知』回報欄位

參數名稱 型態 說明 必須
sms_type integer 簡訊通知類型
2.票券匣轉贈簡訊通知
content object 簡訊通知內容 『票券匣轉贈簡訊通知』欄位參考

建立或修改發行商票券

<?php
/**
 * 經銷商串接-建立或修改發行商票券
 */
final class AgentVoucherDataCreator
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['issuance_uid'] = "289151881006";
        $rawData['items'] = [
                                [
                                 'product_id' => 'MANOR008',
                                 'area_type' => 2,
                                 'is_paid' => 1,
                                 'detail' => 
                                    [
                                     'is_on' => 1,
                                     'is_gift' => 1,
                                     'material_code' => 'MC08',
                                     'product_name' => '金沙咖啡',
                                     'product_description' => '600(L)可調整冰塊甜度',
                                     'declaration' => '<b>咖啡使用規則</b>'
                                    ]
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherdatacreator'
        );
    }
    /**
     * 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, 2);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        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;
    }
}

$AgentVoucherDataCreator = new AgentVoucherDataCreator();
$AgentVoucherDataCreator->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 AgentVoucherDataCreator {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://ka.usecase.cc/api/agent";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            AgentVoucherDataCreator simulator = new AgentVoucherDataCreator();
            //僅限走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.product_id = "MANOR008";
            item.area_type = 2;
            item.is_paid = 1;

            dynamic detail = new ExpandoObject();
            detail.is_on = 1;
            detail.is_gift = 1;
            detail.material_code = "MC08";
            detail.product_name = "金沙咖啡";
            detail.product_description = "600(L)可調整冰塊甜度";
            detail.declaration = "<b>咖啡使用規則</b>";
            item.detail = detail;
            items.Add(item);


            dynamic rawData = new ExpandoObject();
            rawData.issuance_uid =  "289151881006";
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherdatacreator";
            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 AgentVoucherDataCreator {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherDataCreator simulator = new AgentVoucherDataCreator();
        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("product_id", "MANOR008");
        item.put("area_type", 2);
        item.put("is_paid", 1);

        Map<Object, Object> detail = new HashMap<Object, Object>();
        detail.put("is_on", 1);
        detail.put("is_gift", 1);
        detail.put("material_code", "MC08");
        detail.put("product_name", "金沙咖啡");
        detail.put("product_description", "600(L)可調整冰塊甜度");
        detail.put("declaration", "<b>咖啡使用規則</b>");
        item.put("detail", detail);
        items.add(item);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("issuance_uid", "289151881006");
        rawData.put("items", items);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherdatacreator");
        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) {
            System.out.println(e.getMessage());
        }
        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 AgentVoucherDataCreator() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherDataCreator.prototype.getRawData = function () {
    return {
        issuance_uid: "289151881006",
        items: [
                   {
                    'product_id': "MANOR008",
                    'area_type': 2,
                    'is_paid': 1,
                    'detail': 
                       {
                        'is_on': 1,
                        'is_gift': 1,
                        'material_code': "MC08",
                        'product_name': "金沙咖啡",
                        'product_description': "600(L)可調整冰塊甜度",
                        'declaration': "<b>咖啡使用規則</b>"
                       }
                   }
               ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherDataCreator.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherdatacreator"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherDataCreator.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 到主機
 */
AgentVoucherDataCreator.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherDataCreator.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherDataCreator.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherDataCreator = new AgentVoucherDataCreator();
AgentVoucherDataCreator.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 AgentVoucherDataCreator:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'issuance_uid': "289151881006",
            'items': [
                         {
                          'product_id': "MANOR008",
                          'area_type': 2,
                          'is_paid': 1,
                          'detail': 
                             {
                              'is_on': 1,
                              'is_gift': 1,
                              'material_code': "MC08",
                              'product_name': "金沙咖啡",
                              'product_description': "600(L)可調整冰塊甜度",
                              'declaration': "<b>咖啡使用規則</b>"
                             }
                         }
                     ],
        }
        return rawData

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

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

    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)

AgentVoucherDataCreator = AgentVoucherDataCreator()
AgentVoucherDataCreator.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": [
        {
            "code": "251",
            "msg": "更新成功",
            "product_id": "MANOR008"
        }
    ]
}

透過API,建立發行商票券之設定內容或修改發行商票券設定之內容。

經銷商『建立或修改發行商票券』參數說明

欄位 型態 說明
agent_uid string(16) 經銷商商務代號
service text {"service_name": "api", "cmd": "api\/voucherdatacreator"}
JSON格式,AES256加密資料
encry_data text 『建立或修改發行商票券』欄位參考
JSON格式,AES256加密資料

『建立或修改發行商票券』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
items array 票券資訊 必填
每筆『發行商票券資訊』欄位參考

『建立或修改發行商票券』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content array 建立或修改結果回傳 每筆『發行商票券資訊』欄位參考

查詢發行商票券

<?php
/**
 * 經銷商串接-查詢發行商票券
 */
final class AgentVoucherDataInquirer
{
    /**
     * 經銷商商務代號
     * @var string
     */
    public $agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     * @var string
     */
    public $agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://ka.usecase.cc/api/agent";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['issuance_uid'] = "289151881006";
        $rawData['type'] = 1;
        $rawData['product_ids'] = [
                                   "MANOR008"
                                  ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/voucherdatainquirer'
        );
    }
    /**
     * 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;
    }
}

$AgentVoucherDataInquirer = new AgentVoucherDataInquirer();
$AgentVoucherDataInquirer->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 AgentVoucherDataInquirer {
        /// <summary>
        /// 經銷商商務代號
        /// </summary>
        public string agentUid = "289151881007";
        /// <summary>
        /// 經銷商金鑰或認證碼
        /// </summary>
        public string agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";

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

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

            ArrayList productIds = new ArrayList();

            productIds.Add("MANOR008");


            dynamic rawData = new ExpandoObject();
            rawData.issuance_uid =  "289151881006";
            rawData.type =  1;
            rawData.product_ids = productIds;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/voucherdatainquirer";
            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 AgentVoucherDataInquirer {
    /**
     * 經銷商商務代號
     */
    String agentUid = "289151881007";
    /**
     * 經銷商金鑰或認證碼
     */
    String agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    /**
     * 串接交易位置
     */
    String url = "https://ka.usecase.cc/api/agent";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        AgentVoucherDataInquirer simulator = new AgentVoucherDataInquirer();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList productIds = new ArrayList();

        productIds.add(new String("MANOR008"));


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("issuance_uid", "289151881006");
        rawData.put("type", 1);
        rawData.put("product_ids", productIds);

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/voucherdatainquirer");
        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 AgentVoucherDataInquirer() {
    // 經銷商商務代號
    this.agentUid = "289151881007";
    // 經銷商金鑰或認證碼
    this.agentKey = "GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    // 串接交易位置
    this.url = "https://ka.usecase.cc/api/agent";
};
/**
 * 取得串接欄位資料
 */
AgentVoucherDataInquirer.prototype.getRawData = function () {
    return {
        issuance_uid: "289151881006",
        type: 1,
        product_ids: [
                      "MANOR008"
                     ],

    };
};
/**
 * 取得服務位置
 */
AgentVoucherDataInquirer.prototype.getService = function () {
    return {
        service_name: "api",
        cmd: "api/voucherdatainquirer"
    };
};
/**
 * AES 256 加密
 */
AgentVoucherDataInquirer.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 到主機
 */
AgentVoucherDataInquirer.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();
    });
};
/**
 * 取得送出欄位資料
 */
AgentVoucherDataInquirer.prototype.getPostData = function () {
    return {
        "agent_uid": this.agentUid,
        "service": this.encrypt(this.getService(), this.agentKey),
        "encry_data": this.encrypt(this.getRawData(), this.agentKey)
    };
};
/**
 * 執行
 */
AgentVoucherDataInquirer.prototype.run = async function () {
    json = await this.post(this.getPostData())
    console.log(json);
};

AgentVoucherDataInquirer = new AgentVoucherDataInquirer();
AgentVoucherDataInquirer.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 AgentVoucherDataInquirer:
    # 經銷商商務代號
    agentUid = "289151881007";
    # 經銷商金鑰或認證碼
    agentKey = b"GXmljj5l1ZoqaYEgVYJJgryXWNbzVqz4";
    # 串接交易位置
    url = "https://ka.usecase.cc/api/agent"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'issuance_uid': "289151881006",
            'type': 1,
            'product_ids': [
                            "MANOR008"
                           ],
        }
        return rawData

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

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

    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)

AgentVoucherDataInquirer = AgentVoucherDataInquirer()
AgentVoucherDataInquirer.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": [
        {
            "area_type": 2,
            "product_id": "MANOR008",
            "is_paid": 1,
            "detail": {
                "is_on": 1,
                "material_code": "MC08",
                "product_name": "金沙咖啡",
                "declaration": "<b>咖啡使用規則<\/b>"
            }
        }
    ]
}

透過API,取得指定之委託發行商票券設定之內容。

經銷商『查詢發行商票券』參數說明

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

『查詢發行商票券』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
type int 查詢類型 必填
『查詢發行商票券』值參考
product_ids array 查詢之票券產品編號
如果未指定,則回傳全部票券

『查詢發行商票券』回傳欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
content array 查詢到的票券產品編號 每筆『發行商票券資訊』欄位參考

其他關聯欄位說明

關聯欄位

『消費者資訊』欄位

參數名稱 型態 說明 必須
user_id string 消費者帳號 必填
user_name string 消費者姓名
user_real_name string 消費者真實姓名
user_english_name string 消費者英文名稱
user_address_post_zone string 消費者地址郵遞區號
user_address string 消費者帳單地址
user_sn_type string 1:身分證,2:統一證號,3:護照號碼 付款人為本國人為1,外國人2 or 3
user_sn string 付款人身分證/統一證號/護照號碼
user_phone string 消費者家用電話
user_cellphone_code string 消費者行動電話國碼
user_cellphone string 消費者行動電話
user_email string 消費者 E-Mail
user_birthday string 消費者生日
ip string 消費者來源 IP 必填

『票券項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號
service_id string 委託發行商票券服務編號(依MYTIX設定之編號),取得位置系統設定->票劵儲直系統->委託發行商票券服務檢視 必填
id string 高鉅後台產生或發行商角色提供,
發行商請從系統設定->票劵儲直系統->委託發行商票券名稱取得

票券產品編號(最長限32 Bytes)
限英數字([a-zA-Z0-9])
1.票券服務-一般票券 限用通用券、區域券、單店券
必填
platform_fee float 平台服務費(每張票券)
platform_uid string 平台服務費收取商務代號
sharing object 每張票券分潤比例
委託發行商 + 總部 + 銷售點 + 核銷點 需等於 1
必填
『票券分潤』欄位參考
service_rule object 票券服務規則(依票券服務類型帶入處理規則) 必填
『票券服務-一般票券』欄位參考
『票券服務-月費』欄位參考
『票券服務-課程』欄位參考
『票券服務-貨運』欄位參考

『票券分潤』欄位

參數名稱 型態 說明 必須
issuance float 委託發行商分潤 必填
headquarters float 總部分潤 必填
sales float 銷售點分潤 必填
reimbursement float 核銷點分潤 必填

『票券服務-一般票券』欄位

參數名稱 型態 說明 必須
price float 此批發行票券的每張票券面額 必填
cost float 此批發行票券的每張票券內含價值
(如為無償票券,則金額請帶0)
必填
amount integer 購買票券數量 必填
total_price float 此批票券的面額總和
(定價)
必填
total_cost float 此批票券內含價值總和
(售價)
(如為無償票券,則金額請帶0)
必填
trust_start_date string 票券履約保證起始日 必填
trust_end_date string 票券履約保證結束日(履約保證時間必須超過一年) 必填
validity_end_date string 票券優惠結束日(格式YYYYmmdd)
如為無償,超過此日不可核銷
如為有償,可核銷,但應該要告知消費者優惠券結束日
必填
is_custom_serial integer 是否使用客製票券序號
0. 沒有 1.有
必填
serial_numbers string 客製票券序號JSON資料
注意:
1.客製票券序號不能重複,且限英數字([a-zA-Z0-9])
2.長度最長32bytes
3.若購賣票券交易狀態為交易失敗、未進行交易等確定不可再進行交易,客製券號可進行回收再利用
4.如無回收未用客製票券序號機制,則請忽略3的實作,不重複即可
service_type integer 記名類型 必填
『票券服務(一般票券)記名類型』值參考

『票券服務-月費』欄位

參數名稱 型態 說明 必須
service_type integer 記名類型 必填
『票券服務(月費)記名類型』值參考
area_type integer 適用區域類型 必填
『票券服務(月費)適用區域類型』值參考

『票券服務-課程』欄位

參數名稱 型態 說明 必須
service_type integer 記名類型 必填
『票券服務(課程)記名類型』值參考
area_type integer 適用區域類型 必填
『票券服務(課程)適用區域類型』值參考

『票券服務-貨運』欄位

參數名稱 型態 說明 必須
service_type integer 記名類型 必填
『票券服務(貨運)記名類型』值參考
area_type integer 適用區域類型 必填
『票券服務(貨運)適用區域類型』值參考

『購買票券交易查詢回傳』欄位

參數名稱 型態 說明 必須
uid string 購買票券交易UID
key string 交易驗証碼
code string 目前狀態碼 『購買票券交易狀態碼』值參考
msg string 回傳訊息
finishtime string 交易完成時間(YYYYMMDDHHmmss)
order_id string 購買票券交易票券交易編號
user_id string 消費者帳號
cost string 原交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
pfn string 付費方法
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券核銷線下交易資訊回傳』欄位

參數名稱 型態 說明 必須
uid string 票券核銷線下交易UID
key string 交易驗証碼
order_id string 票券核銷線下交易票券處理編號
code string 票券核銷線下交易狀態碼 『票券交易狀態碼』值參考
msg string 核銷交易訊息
finishtime string MYTIX交易完成時間(格式為YYYYMMDDHHmmss)
pay_token string 核銷交易碼(例:MYTIX12345678ABCDEFGH共21碼)
pos_trade_time string POS 端交易日期時間(格式為YYYYMMDDHHmmss)
pos_id string POS 機號或設備機號
clerk_no string 收銀員代碼
items array 消費票券項目 每筆『票券核銷線下交易產品資訊』欄位參考
reimbursement_from_type int 核銷點類型 『票券核銷點類型』值參考
reimbursement_store_uid string 核銷特約商店商務代號
reimbursement_dealer_no string 自訂核銷點編號
issuance_uid string 委託發行商商務代號
reimbursement_order_id string 核銷店家訂單單號
issue_invoice_state int 票券核銷發票開立類型 『票券核銷發票開立類型』值參考
invoice object 當發票開立類型為1自行開立時,需帶入相關資訊 『票券核銷交易發票資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券核銷線下交易產品資訊』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號
id string 票券產品編號
material_code string 商品料號
name string 票券名稱
products array 產品金額資訊 每筆『票券核銷線下交易產品金額資訊』欄位參考
vouchers array 單張票券資訊 每筆『單張票券資訊』欄位參考

『票券核銷線下交易產品金額資訊』欄位

參數名稱 型態 說明 必須
amount integer 數量
cost float 購買單價
price float 購買定價
total_cost float 購買單價小計
total_price float 購買定價小計

『單張票券資訊』欄位

參數名稱 型態 說明 必須
serial_no string 系統票券序號
custom_serial_no string 自訂票券序號
book_no string 票券本號
sales_from_type int 銷售點類型 必填
『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號 sales_from_type=1為必填
sales_dealer_no string 自訂銷售點編號 sales_from_type=2為必填
cost float 購買單價
price float 購買定價

『票券核銷交易發票資訊』欄位

參數名稱 型態 說明 必須
number string 發票號碼
date string 發票開立日期(格式:YYYYMMDDHHmmss)

『票券取消項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號
id string 票券產品編號(最長限32 Bytes) 必填
serial_no string 票券號碼 必填

『票券核銷交易取消查詢』欄位

參數名稱 型態 說明 必須
uid string 取消票券核銷交易UID
key string 交易驗証碼
order_id string 票券核銷取消票券處理編號
reverse_date string 取消核銷完成日期時間(格式為YYYYMMDDHHmmss)
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
items array 查詢內容 每筆『取消票券核銷資訊回傳』欄位參考

『取消票券核銷資訊回傳』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商
id string 票券產品編號(最長限32 Bytes)
serial_no string 票券號碼
code string 狀態碼 『票券核銷交易取消狀態碼』值參考
msg string 狀態訊息

『退劵回傳細項資訊』值內容

參數名稱 型態 說明 必須
url string 網址
uid string 票券退券交易UID
key string 驗証碼

『發行商票券資訊』欄位

參數名稱 型態 說明 必須
product_id string 票券產品編號(最長限32 Bytes)(唯一)
限英數字([a-zA-Z0-9])
若此編號已經建立過,則只更新detail欄位內資訊
必填
area_type integer 適用區域類型(此欄位新增後無法異動) 必填
『適用區域類型』值參考
is_paid integer 票券價值類型(此欄位新增後無法異動) 必填
『票券價值類型』值參考
detail object 票券細部資訊 必填
『單店券資訊』欄位參考
『通用券資訊』欄位參考
『區域券資訊』欄位參考

『單店券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 必填
『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱 必填
product_description string 票券產品敘述
declaration string 宣告內容,只允許下列html tag,h6,ul,li,b 必填
store_uid string 可核銷特約商店商務代號 必填

『通用券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 必填
『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱 必填
product_description string 票券產品敘述
declaration string 宣告內容,只允許下列html tag,h6,ul,li,b 必填

『區域券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 必填
『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱 必填
product_description string 票券產品敘述
declaration string 宣告內容,只允許下列html tag,h6,ul,li,b 必填
used_name string 群體名稱 必填
store_uids array 可核銷特約商店商務代號 必填

『發行商票券資訊』欄位

參數名稱 型態 說明 必須
code string 處理狀態碼 『發行商票券處理狀態碼』值參考
msg string 狀態說明
product_id string 票券產品編號

『發行商票券資訊』欄位

參數名稱 型態 說明 必須
area_type integer 適用區域類型 『適用區域類型』值參考
product_id string 票券產品編號
is_paid integer 票券價值類型 『票券價值類型』值參考
detail object 『單店券資訊』欄位參考
『通用券資訊』欄位參考
『區域券資訊』欄位參考

『單店券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱
product_description string 票券產品敘述
declaration string 宣告內容
store_uid string 可核銷特約商店商務代號

『通用券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱
product_description string 票券產品敘述
declaration string 宣告內容

『區域券資訊』欄位

參數名稱 型態 說明 必須
is_on integer 上下架狀態 『票券上下架狀態』值參考
is_gift integer 是否可轉贈 『票券是否可轉贈』值參考
material_code string 委託發行商的商品料號
product_name string 票券名稱
product_description string 票券產品敘述
declaration string 宣告內容
used_name string 群體名稱
store_uids array 可核銷特約商店商務代號

『商品細項』欄位

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

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

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

『票券轉贈回傳細項資訊』欄位

參數名稱 型態 說明 必須
url string 網址
uid string 票券轉贈交易UID
key string 驗証碼

『票券轉贈簡訊通知』欄位

參數名稱 型態 說明 必須
uid string 票券轉贈交易UID
key string 交易驗証碼
order_id string 票券轉贈交易票券處理編號
cellphone_code string 被轉贈者手機國碼
cellphone string 被轉贈者手機號碼
is_member integer 被轉贈票券是否為記名 『被轉贈票券是否為記名』值參考
gift_url string 不記名票券領取與使用網址
items array 轉贈票券項目 每筆『票券轉贈交易產品資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券轉贈交易產品資訊』欄位

參數名稱 型態 說明 必須
id string 票券產品編號
name string 票券名稱
material_code string 委託發行商的商品料號
products array 產品金額資訊 每筆『票券轉贈交易產品金額資訊』欄位參考

『票券轉贈交易產品金額資訊』欄位

參數名稱 型態 說明 必須
amount integer 數量
cost float 購買單價
price float 購買定價
total_cost float 購買單價小計
total_price float 購買定價小計

『票券轉贈回傳細項資訊』欄位

參數名稱 型態 說明 必須
url string 網址
uid string 票券轉贈交易UID
key string 驗証碼

『票券匣轉贈簡訊通知』欄位

參數名稱 型態 說明 必須
uid string 票券匣交易UID
key string 交易驗証碼
order_id string 票券匣處理編號
sys_order_id string 票券匣轉贈交易票券處理編號
cellphone_code string 被轉贈者手機國碼
cellphone string 被轉贈者手機號碼
is_member integer 被轉贈票券是否為記名 『被轉贈票券是否為記名』值參考
gift_url string 不記名票券領取與使用網址
items array 轉贈票券項目 每筆『票券轉贈交易產品資訊』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券售出項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
no string 自訂票券號碼或本號 必填

『票券售出交易發票資訊』欄位

參數名稱 型態 說明 必須
number string 發票號碼
date string 發票開立日期(格式:YYYYMMDDHHmmss)

『票券售出交易內容』欄位

參數名稱 型態 說明 必須
uid string 票券銷售交易訂單UID
key string 交易驗証碼
order_id string 票券銷售票券處理編號
sales_date string 售出處理完成日期時間(格式為YYYYMMDDHHmmss)
items array 內容 每筆『票券售出資訊回傳』欄位參考
sales_order_id string 銷售店家訂單單號
issue_invoice_state int 票券售出發票開立類型 『票券售出發票開立類型』值參考
invoice object 當發票開立類型為1自行開立時,需帶入相關資訊 『票券售出交易發票資訊』欄位參考
trust_start_date string 票券履約保證起始日(格式:YYYYMMDD)
trust_end_date string 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD)
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券售出資訊回傳』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商
unit_type int 單位類型 『票券實體券單位』值參考
no string 自訂票券號碼或本號碼
ticket object 若單位為券時,票券資訊 『單位為券,票券資訊』欄位參考
book array 若單位為本時,票券資訊清單 每筆『單位為本,票券資訊』欄位參考

『單位為券,票券資訊』欄位

參數名稱 型態 說明 必須
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
cost float 購買單價
price float 購買定價

『單位為本,票券資訊』欄位

參數名稱 型態 說明 必須
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
cost float 購買單價
price float 購買定價

『票券售出取消項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
no string 自訂票券號碼或本號 必填

『票券售出交易取消查詢』欄位

參數名稱 型態 說明 必須
uid string 取消票券售出交易訂單UID
key string 交易驗証碼
order_id string 票券售出取消票券處理編號
reverse_date string 取消售出完成日期時間(格式為YYYYMMDDHHmmss)
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
items array 查詢內容 每筆『取消票券售出資訊回傳』欄位參考

『取消票券售出資訊回傳』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商
unit_type int 單位類型 『票券單位』值參考
no string 自訂票券號碼或本號碼
ticket object 若單位為券時,票券資訊 『單位為券,票券資訊』欄位參考
book array 若單位為本時,票券資訊清單 每筆『單位為本,票券資訊』欄位參考
code string 狀態碼 『票券售出交易取消狀態碼』值參考
msg string 狀態訊息

『單位為券,票券資訊』欄位

參數名稱 型態 說明 必須
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
book_no string 自訂票券本號
sales_date string 售出處理完成日期時間(格式為YYYYMMDDHHmmss)
status int 取消售出前之票券狀態
cost float 購買單價
price float 購買定價

『單位為本,票券資訊』欄位

參數名稱 型態 說明 必須
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
sales_date string 售出處理完成日期時間(格式為YYYYMMDDHHmmss)
status int 取消售出前之票券狀態
cost float 購買單價
price float 購買定價

『票券售出交易內容』欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
uid string 票券銷售交易訂單UID
key string 交易驗証碼
order_id string 票券銷售票券處理編號
sales_date string 銷售處理完成日期時間(格式為YYYYMMDDHHmmss)
items array 內容 每筆『票券售出資訊回傳』欄位參考
sales_order_id string 銷售店家訂單單號
issue_invoice_state int 票券售出發票開立類型 『票券售出發票開立類型』值參考
invoice object 當發票開立類型為1自行開立時,需帶入相關資訊 『票券售出交易發票資訊』欄位參考
trust_start_date string 票券履約保證起始日(格式:YYYYMMDD)
trust_end_date string 票券履約保證結束日(履約保證時間必須超過一年)(格式:YYYYMMDD)
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券作廢項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
no string 自訂票券號碼或本號 必填

『票券作廢交易內容』欄位

參數名稱 型態 說明 必須
uid string 票券作廢交易訂單UID
key string 交易驗証碼
order_id string 票券作廢票券處理編號
invalid_date string 作廢處理完成日期時間(格式為YYYYMMDDHHmmss)
items array 內容 每筆『票券作廢資訊回傳』欄位參考
book_used array 若單位為本時,作廢失敗且原因為票券有使用過之票券清單
(一本如果有一張被使用就不能作廢)
每筆『單位為本時,有使用過之票券清單』欄位參考
invalid_from_type int 作廢點類型 『票券作廢點類型』值參考
invalid_store_uid string 作廢特約商店商務代號
invalid_dealer_no string 自訂作廢點編號
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券作廢資訊回傳』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商
unit_type int 單位類型 『票券實體券單位』值參考
no string 自訂票券號碼或本號碼
ticket object 若單位為券時,作廢成功票券資訊 『票券作廢資訊回傳』欄位參考
book array 若單位為本時,作廢成功票券資訊清單 每筆『單位為本,作廢成功票券資訊』欄位參考

『單位為本時,有使用過之票券清單』欄位

參數名稱 型態 說明 必須
book_no string 本號
items array 已使用券資訊 每筆『單位為本時,有使用過之票券清單』欄位參考

『票券作廢資訊回傳』欄位

參數名稱 型態 說明 必須
status int 作廢前之票券狀態
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
cost float 購買單價
price float 購買定價

『單位為本,作廢成功票券資訊』欄位

參數名稱 型態 說明 必須
status int 作廢前之票券狀態
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
cost float 購買單價
price float 購買定價

『單位為本時,有使用過之票券清單』欄位

參數名稱 型態 說明 必須
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
reimbursement_from_type int 核銷點類型 『票券核銷點類型』值參考
reimbursement_store_uid string 核銷特約商店商務代號
reimbursement_dealer_no string 自訂核銷點編號
cost float 購買單價
price float 購買定價

『票券作廢交易內容』欄位

參數名稱 型態 說明 必須
code string 執行狀態碼 『票券執行狀態碼』值參考
msg string 執行狀態訊息
uid string 票券作廢交易訂單UID
key string 交易驗証碼
order_id string 票券作廢票券處理編號
invalid_date string 作廢處理完成日期時間(格式為YYYYMMDDHHmmss)
items array 內容 每筆『票券作廢資訊回傳』欄位參考
book_used array 若單位為本時,作廢失敗且原因為票券有使用過之票券清單
(一本如果有一張被使用就不能作廢)
每筆『單位為本時,有使用過之票券清單』欄位參考
invalid_from_type int 作廢點類型 『票券作廢點類型』值參考
invalid_store_uid string 作廢特約商店商務代號
invalid_dealer_no string 自訂作廢點編號
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5

『票券狀態查詢項目』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商商務代號 必填
no string 自訂票券號碼或本號 必填

『票券狀態資訊回傳』欄位

參數名稱 型態 說明 必須
issuance_uid string 委託發行商
unit_type int 單位類型 『票券實體券單位』值參考
no string 自訂票券號碼或本號碼
ticket object 若單位為券時,票券資訊 『單位為券-票券資訊回傳』欄位參考
book array 若單位為本時,票券資訊清單 每筆『單位為本-每張票券資訊回傳』欄位參考

『單位為券-票券資訊回傳』欄位

參數名稱 型態 說明 必須
status int 票券狀態 『票券流程狀態碼』值參考
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
book_no string 自訂票券本號
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
reimbursement_from_type int 核銷點類型 『票券核銷點類型』值參考
reimbursement_store_uid string 核銷特約商店商務代號
reimbursement_dealer_no string 自訂核銷點編號
invalid_from_type int 作廢點類型 『票券作廢點類型』值參考
invalid_store_uid string 作廢特約商店商務代號
invalid_dealer_no string 自訂作廢點編號
cost float 購買單價
price float 購買定價

『單位為本-每張票券資訊回傳』欄位

參數名稱 型態 說明 必須
status int 票券狀態 『票券流程狀態碼』值參考
custom_serial_no string 自訂票券號碼
serial_no string 系統票券號碼
sales_from_type int 銷售點類型 『票券銷售點類型』值參考
sales_store_uid string 銷售特約商店商務代號
sales_dealer_no string 自訂銷售點編號
reimbursement_from_type int 核銷點類型 『票券核銷點類型』值參考
reimbursement_store_uid string 核銷特約商店商務代號
reimbursement_dealer_no string 自訂核銷點編號
invalid_from_type int 作廢點類型 『票券作廢點類型』值參考
invalid_store_uid string 作廢特約商店商務代號
invalid_dealer_no string 自訂作廢點編號
cost float 購買單價
price float 購買定價

值的定義

『是否為預發行』值內容

型態 說明 備註
0 integer 即時發行(預設)

『票券執行狀態碼』值內容

型態 說明 備註
100 string 資料不正確
400 string 系統錯誤
B200 string 執行成功
B500 string 執行失敗

『購買票券交易狀態碼』值內容

型態 說明 備註
100 string 資料不正確
200 string 資料正確
210 string 交易處理中
250 string 交易成功
260 string 交易進行中(超商代碼繳費)
270 string 交易進行中(虛擬帳號)
280 string 交易進行中(WEBATM等導頁式交易)
290 string 交易成功,但金額不符
300 string 交易失敗
380 string 交易逾時
400 string 系統錯誤
500 string 中斷交易(閘道)
600 string 交易成功且結帳 (信用卡)
A0001 string 中斷交易(金流)
A0002 string 未完成交易

『票券服務(一般票券)記名類型』值內容

型態 說明 備註
1 integer 記名票券(預設)
2 integer 不記名票券

『票券服務(月費)記名類型』值內容

型態 說明 備註
1 integer 記名票券(預設)

『適用區域類型』值內容

型態 說明 備註
1 integer 單店券(預設)
2 integer 通用券
3 integer 區域券

『票券服務(月費)適用區域類型』值內容

型態 說明 備註
1 integer 單店券(預設)
2 integer 通用券
3 integer 區域券

『票券服務(課程)記名類型』值內容

型態 說明 備註
1 integer 記名票券(預設)

『票券服務(課程)適用區域類型』值內容

型態 說明 備註
1 integer 單店券(預設)
2 integer 通用券
3 integer 區域券

『票券服務(貨運)記名類型』值內容

型態 說明 備註
2 integer 不記名票券(預設)

『票券服務(貨運)適用區域類型』值內容

型態 說明 備註
1 integer 單店券(預設)

『票券交易狀態碼』值內容

型態 說明 備註
250 string 核銷成功
300 string 核銷失敗

『票券核銷點類型』值內容

型態 說明 備註
1 int MYTIX特約商店(預設)
2 int 自訂核銷點編號

『票券核銷發票開立類型』值內容

型態 說明 備註
0 int 不開立(預設)
1 int 自行開立

『票券核銷交易取消狀態碼』值內容

型態 說明 備註
250 string 取消核銷成功
300 string 取消核銷失敗

『Qrcode內容模式』值內容

型態 說明 備註
2 string Token字串
1 string JSON格式(預設)

『票券顯示模式』值內容

型態 說明 備註
1 string 以委託發行商顯示票券
2 string 以可核銷之特約商店顯示票券

『票券價值類型』值內容

型態 說明 備註
1 integer 有償
0 integer 無償

『發行商票券處理狀態碼』值內容

型態 說明 備註
250 string 建立成功
251 string 修改成功
300 string 建立失敗
301 string 修改失敗

『票券上下架狀態』值內容

型態 說明 備註
1 integer 上架(預設)
0 integer 下架

『票券是否可轉贈』值內容

型態 說明 備註
1 integer 可轉贈(預設)
0 integer 不可轉贈

『查詢發行商票券』值內容

型態 說明 備註
1 integer 指定票券產品編號(預設)
2 integer 只有上架票券
3 integer 所有票券

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

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

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

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

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

型態 說明 備註
0 integer 未使用電子發票開立
1 integer 雲端發票
2 integer 發票捐贈
3 integer 實體發票

『雲端發票類型』值內容

型態 說明 備註
0 integer 未使用雲端發票類型
2 integer 手機條碼
3 integer 自然人憑證條碼
4 integer 以E-Mail寄送

『票券顯示模式』值內容

型態 說明 備註
1 string 以委託發行商顯示票券

『被轉贈票券是否為記名』值內容

型態 說明 備註
1 integer
0 integer 不是

『票券顯示模式』值內容

型態 說明 備註
1 string 以委託發行商顯示票券

『票券銷售點類型』值內容

型態 說明 備註
1 int MYTIX特約商店(預設)
2 int 自訂銷售點編號

『票券售出票券掃碼方式』值內容

型態 說明 備註
1 int 以本或券單一掃碼方式(預設)
2 int 掃碼首券表示整本券方式

『票券售出發票開立類型』值內容

型態 說明 備註
0 int 不開立(預設)
1 int 自行開立

『票券執行狀態碼』值內容

型態 說明 備註
100 string 資料不正確
400 string 系統錯誤
B200 string 執行成功
B500 string 執行失敗
B501 string 執行失敗,資料不正確

『票券實體券單位』值內容

型態 說明 備註
1 int
2 int

『票券單位』值內容

型態 說明 備註
0 int 無法辨識
1 int
2 int

『票券售出交易取消狀態碼』值內容

型態 說明 備註
250 string 取消售出成功
300 string 取消售出失敗

『票券作廢點類型』值內容

型態 說明 備註
1 int MYTIX特約商店(預設)
2 int 自訂作廢點編號

『票券流程狀態碼』值內容

型態 說明 備註
1 int 建立
2 int 綁定
3 int 轉贈
4 int 售出
5 int 作廢
31 int 票券核銷
32 int 票券移轉
33 int 票券退券
34 int 退款進行中
35 int 轉贈進行中

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

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

編號 代碼 狀態 說明
1 CREDITCARD 啟用 信用卡
3 CSTORECODE 啟用 超商代碼
4 WEBATM 啟用 WEBATM
6 E_COLLECTION 啟用 虛擬帳號 (ATM轉帳)

附錄三:設定調整

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

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

附錄五:API模擬串接服務

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