NAV
php csharp java javascript python

修改歷程

版本 異動日期 修訂內容 位置
1.0 2021.01.01 新版文件
1.0.1 2023.04.07 新增開發前請先閱讀 20230407_01

開發前請先閱讀

金鑰的注意事項

Q:金鑰的有效期限

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

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

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

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

A:會

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

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

交易結果的告知

Q:何時會給予交易結果

A:當mypay接收到交易的http request後,會立即回應交易結果於http response body,除此之外,MyPay也會由附錄三這邊的設定,背景主動發動通知商家

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

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

綁卡注意事項

Q:測試區為何一直失敗

A:因為測試區目前只有中信有支援,因此如果是特別測試綁卡功能,請通知客服人員幫您切換至相關設定

Q:已請客服人員切換相關設定了,為何還是綁卡失敗

A:上游銀行因系統問題,有可能會出現綁卡失敗的狀況,可以稍晚再試試

MYPAY電子錢包交易設計概要

安全性設計

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

MYPAY 目前提供之服務與格式

MYPAY電子錢包交易:

(1)MYPAY電子錢包綁定:發動電子錢包綁定,消費者在MYPAY綁定電子錢包後,特約商店接收虛擬卡號。

(2)MYPAY電子錢包交易:透過虛擬卡號,發動電子錢包交易。

(3)MYPAY電子錢包請款取消授權:電子錢包交易極為信用卡類型交易,若使用自行請款模式,交易狀態為授權完成(245)時,則可以發動此電子錢包取消授權,用以取消交易,並釋出消費者圈存金額。

(4)MYPAY電子錢包授權請款:電子錢包交易極為信用卡類型交易,若使用自行請款模式,交易狀態為授權完成(245)時,則可以發動此電子錢包授權請款,用以完成交易。 發動只限定一次。可全額或部分請款。

(5)MYPAY電子錢包解除綁定:解除指定帳號電子錢包綁定。

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

介接網址

特約商店模式

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

Client模式(限定功能)

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

資料加密方式

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

加密金鑰

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

文字編碼

一律使用UTF-8相容編碼

MYPAY電子錢包綁定

<?php
/**
 * 特約商店串接-MYPAY電子錢包綁定
 */
final class StoreEWalletBind
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['user_id'] = "phper";
        $rawData['user_sn'] = "A123456789";
        $rawData['user_cellphone_code'] = "886";
        $rawData['user_cellphone'] = "918123123";
        $rawData['user_real_name'] = "金城武";
        $rawData['user_email'] = "[email protected]";
        $rawData['user_english_name'] = "Takeshi Kaneshiro";
        $rawData['user_address'] = "台中市西區台灣大道二段573號6樓E室";
        $rawData['pfn'] = "CREDITCARD";
        $rawData['ip'] = "127.0.0.1";
        $rawData['success_returl'] = "http://www.mypay.com.tw/";
        $rawData['failure_returl'] = "http://www.google.com.tw/";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/ewalletbind'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreEWalletBind = new StoreEWalletBind();
$StoreEWalletBind->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>
    /// 特約商店串接-MYPAY電子錢包綁定
    /// </summary>
    public class StoreEWalletBind {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreEWalletBind simulator = new StoreEWalletBind();
            //僅限走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.store_uid = this.storeUid;
            rawData.user_id =  "phper";
            rawData.user_sn =  "A123456789";
            rawData.user_cellphone_code =  "886";
            rawData.user_cellphone =  "918123123";
            rawData.user_real_name =  "金城武";
            rawData.user_email =  "[email protected]";
            rawData.user_english_name =  "Takeshi Kaneshiro";
            rawData.user_address =  "台中市西區台灣大道二段573號6樓E室";
            rawData.pfn =  "CREDITCARD";
            rawData.ip =  "127.0.0.1";
            rawData.success_returl =  "http://www.mypay.com.tw/";
            rawData.failure_returl =  "http://www.google.com.tw/";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/ewalletbind";
            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.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, 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["store_uid"] = this.storeUid;
            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;
/**
 * 特約商店串接-MYPAY電子錢包綁定
 * 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 StoreEWalletBind {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreEWalletBind simulator = new StoreEWalletBind();
        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("store_uid", this.storeUid);
        rawData.put("user_id", "phper");
        rawData.put("user_sn", "A123456789");
        rawData.put("user_cellphone_code", "886");
        rawData.put("user_cellphone", "918123123");
        rawData.put("user_real_name", "金城武");
        rawData.put("user_email", "[email protected]");
        rawData.put("user_english_name", "Takeshi Kaneshiro");
        rawData.put("user_address", "台中市西區台灣大道二段573號6樓E室");
        rawData.put("pfn", "CREDITCARD");
        rawData.put("ip", "127.0.0.1");
        rawData.put("success_returl", "http://www.mypay.com.tw/");
        rawData.put("failure_returl", "http://www.google.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/ewalletbind");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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');

/**
 * 特約商店串接-MYPAY電子錢包綁定
 */
function StoreEWalletBind() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreEWalletBind.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        user_id: "phper",
        user_sn: "A123456789",
        user_cellphone_code: "886",
        user_cellphone: "918123123",
        user_real_name: "金城武",
        user_email: "[email protected]",
        user_english_name: "Takeshi Kaneshiro",
        user_address: "台中市西區台灣大道二段573號6樓E室",
        pfn: "CREDITCARD",
        ip: "127.0.0.1",
        success_returl: "http://www.mypay.com.tw/",
        failure_returl: "http://www.google.com.tw/",

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

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

"""特約商店串接-MYPAY電子錢包綁定
"""
class StoreEWalletBind:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'user_id': "phper",
            'user_sn': "A123456789",
            'user_cellphone_code': "886",
            'user_cellphone': "918123123",
            'user_real_name': "金城武",
            'user_email': "[email protected]",
            'user_english_name': "Takeshi Kaneshiro",
            'user_address': "台中市西區台灣大道二段573號6樓E室",
            'pfn': "CREDITCARD",
            'ip': "127.0.0.1",
            'success_returl': "http://www.mypay.com.tw/",
            'failure_returl': "http://www.google.com.tw/",
        }
        return rawData

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

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

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

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

StoreEWalletBind = StoreEWalletBind()
StoreEWalletBind.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "url": "http:\/\/pay.k20-mypay.tw\/ewallet\/101517.html"
}

特約商店發動MYPAY電子錢包交易綁定,消費者在MYPAY綁定電子錢包後,MYPAY會將綁定的電子錢包虛擬卡號通知特約商店。

特約商店可透過電子錢包虛擬卡號發動交易。消費者若取消電子錢包綁定時,MYPAY也會通知特約商店。

特約商店『MYPAY電子錢包綁定』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/ewalletbind"}
JSON格式,AES256加密資料
encry_data text 『MYPAY電子錢包綁定』欄位參考
JSON格式,AES256加密資料

『MYPAY電子錢包綁定』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
user_id string 消費者帳號 必填
user_name string 消費者姓名
user_real_name string 消費者真實姓名
user_english_name string 消費者英文姓名
user_zipcode string 消費者郵遞區號
user_address string 消費者帳單地址
user_sn_type string 證號類型 『證號類型』值參考
user_sn string 付款人身分證/統一證號/護照號碼
user_phone string 消費者家用電話
user_cellphone_code string 消費者行動電話國碼
user_cellphone string 消費者行動電話
user_email string 消費者 E-Mail
user_birthday string 消費者生日
ip string 消費者來源 IP 必填
pfn string 綁定支付方式 『付款方式』值參考
success_returl string 綁定成功導頁網址
failure_returl string 綁定失敗導頁網址

『MYPAY電子錢包綁定』回傳欄位

參數名稱 型態 說明 必須
code string 交易回傳碼 『電子錢包執行狀態碼』值參考
msg string 回傳訊息
url string 交易網址

『電子錢包虛擬卡號回傳資訊』回報欄位

參數名稱 型態 說明 必須
pfn string 支付類型
cardno string 綁定卡號 (僅顯示前六後四)
user_id string 消費者帳號
cellphone_code string 用以取消綁定之手機國碼
cellphone string 用以取消綁定之手機號碼
virtual_pan string 虛擬卡號
enable string 是否啟用 0.關閉 1.啟用

MYPAY電子錢包交易

<?php
/**
 * 特約商店串接-直接交易-MYPAY電子錢包交易
 */
final class StoreEWallet
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['items'] = [
                                [
                                 'id' => '1',
                                 'name' => '商品名稱',
                                 'cost' => '10',
                                 'amount' => '1',
                                 'total' => '10'
                                ]
                            ];
        $rawData['cost'] = "10";
        $rawData['user_id'] = "phper";
        $rawData['order_id'] = "1234567890";
        $rawData['ip'] = "127.0.0.1";
        $rawData['pfn'] = "EWALLET";
        $rawData['data_json'] = "{\"virtualPan\":\"7b5ba7bf23ca4b3f8bcd11caac5b2de6\",\"userId\":\"phper\",\"bizId\":\"289151880002\"}";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/transaction'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreEWallet = new StoreEWallet();
$StoreEWallet->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>
    /// 特約商店串接-直接交易-MYPAY電子錢包交易
    /// </summary>
    public class StoreEWallet {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreEWallet simulator = new StoreEWallet();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList items = new ArrayList();

            dynamic item = new ExpandoObject();
            item.id = "1";
            item.name = "商品名稱";
            item.cost = "10";
            item.amount = "1";
            item.total = "10";
            items.Add(item);


            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.items = items;
            rawData.cost =  "10";
            rawData.user_id =  "phper";
            rawData.order_id =  "1234567890";
            rawData.ip =  "127.0.0.1";
            rawData.pfn =  "EWALLET";
            rawData.data_json =  "{\"virtualPan\":\"7b5ba7bf23ca4b3f8bcd11caac5b2de6\",\"userId\":\"phper\",\"bizId\":\"289151880002\"}";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/transaction";
            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.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, 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["store_uid"] = this.storeUid;
            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;
/**
 * 特約商店串接-直接交易-MYPAY電子錢包交易
 * 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 StoreEWallet {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreEWallet simulator = new StoreEWallet();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList items = new ArrayList();

        Map<Object, Object> item = new HashMap<Object, Object>();
        item.put("id", "1");
        item.put("name", "商品名稱");
        item.put("cost", "10");
        item.put("amount", "1");
        item.put("total", "10");
        items.add(item);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("items", items);
        rawData.put("cost", "10");
        rawData.put("user_id", "phper");
        rawData.put("order_id", "1234567890");
        rawData.put("ip", "127.0.0.1");
        rawData.put("pfn", "EWALLET");
        rawData.put("data_json", "{\"virtualPan\":\"7b5ba7bf23ca4b3f8bcd11caac5b2de6\",\"userId\":\"phper\",\"bizId\":\"289151880002\"}");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/transaction");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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');

/**
 * 特約商店串接-直接交易-MYPAY電子錢包交易
 */
function StoreEWallet() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreEWallet.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        items: [
                   {
                    'id': "1",
                    'name': "商品名稱",
                    'cost': "10",
                    'amount': "1",
                    'total': "10"
                   }
               ],
        cost: "10",
        user_id: "phper",
        order_id: "1234567890",
        ip: "127.0.0.1",
        pfn: "EWALLET",
        data_json: "{\"virtualPan\":\"7b5ba7bf23ca4b3f8bcd11caac5b2de6\",\"userId\":\"phper\",\"bizId\":\"289151880002\"}",

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

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

"""特約商店串接-直接交易-MYPAY電子錢包交易
"""
class StoreEWallet:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'items': [
                         {
                          'id': "1",
                          'name': "商品名稱",
                          'cost': "10",
                          'amount': "1",
                          'total': "10"
                         }
                     ],
            'cost': "10",
            'user_id': "phper",
            'order_id': "1234567890",
            'ip': "127.0.0.1",
            'pfn': "EWALLET",
            'data_json': "{\"virtualPan\":\"7b5ba7bf23ca4b3f8bcd11caac5b2de6\",\"userId\":\"phper\",\"bizId\":\"289151880002\"}",
        }
        return rawData

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

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

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

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

StoreEWallet = StoreEWallet()
StoreEWallet.run()

回傳 JSON 結構如下:

{
    "invoice_state": 0,
    "invoice_state_msg": "不處理",
    "invoice_date": "",
    "invoice_wordtrack": "",
    "invoice_number": "",
    "invoice_rand_code": "",
    "invoice_seller_ban": "",
    "invoice_buyer_ban": "",
    "invoice_left_qrcode": "",
    "invoice_middle_barcode": "",
    "invoice_right_qrcode": "",
    "invoice_title_type": 1,
    "invoice_title": "",
    "invoice_print_type": 0,
    "invoice_print_device": 0,
    "invoice_amount": "",
    "invoice_sales_amount": "",
    "invoice_tax_amount": "",
    "invoice_order_detail": "",
    "invoice_ratetype": 1,
    "invoice_input_type": 0,
    "invoice_cloud_type": 0,
    "invoice_mobile_code": "",
    "invoice_tax_id": "",
    "invoice_natural_person": "",
    "invoice_m_post_zone": "",
    "invoice_m_address": "",
    "invoice_love_code": "",
    "invoice_b2b_title": "",
    "invoice_b2b_id": "",
    "invoice_b2b_post_zone": "",
    "invoice_b2b_address": "",
    "code": "250",
    "msg": "執行成功。",
    "uid": 101520,
    "key": "bca469b4b021feaaaffc2599d8d073e0",
    "finishtime": "20220125095612",
    "cardno": "400361******7729",
    "acode": "929114",
    "card_type": "1",
    "issuing_bank": "中國信託",
    "issuing_bank_uid": "822",
    "transaction_mode": "1",
    "supplier_name": "中國信託商業銀行",
    "supplier_code": "B8",
    "order_id": "1234567890",
    "user_id": "phper",
    "cost": 10,
    "currency": "TWD",
    "actual_cost": 10,
    "actual_currency": "TWD",
    "pfn": "CREDITCARD",
    "trans_type": 1,
    "result_type": 4,
    "result_content_type": "CREDITCARD",
    "result_content": "{\n    \"ACode\": \"929114\",\n    \"TradeNo\": \"101520\",\n    \"Status\": 0,\n    \"OrderTotalCost\": \"10\"\n}",
    "echo_0": "",
    "echo_1": "",
    "echo_2": "",
    "echo_3": "",
    "echo_4": ""
}

當消費者想直接交易時,特約商店可以使用虛擬卡號直接發動MYPAY電子錢包交易,即進行扣款動作。

特約商店『MYPAY電子錢包交易』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/transaction"}
JSON格式,AES256加密資料
encry_data text 『MYPAY電子錢包交易』欄位參考
JSON格式,AES256加密資料

『直接交易-MYPAY電子錢包交易』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
cost string 訂單總金額 必填
currency string 預設交易幣別(預設為TWD新台幣)
order_id string 訂單編號 必填
items array 訂單內物品數 每筆『商品項目』欄位參考
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
pfn string 付費方法 (EWALLET)
discount string 折價金額 (預設0)
shipping_fee string 運費
user_id string 消費者帳號 必填
user_name string 消費者姓名
user_real_name string 消費者真實姓名
user_english_name string 消費者英文名稱
user_zipcode string 消費者郵遞區號
user_address string 消費者地址
user_sn_type string 證號類型 『證號類型』值參考
user_sn string 付款人身分證/統一證號/護照號碼
user_phone string 消費者家用電話
user_cellphone_code string 消費者行動電話國碼
user_cellphone string 消費者行動電話
user_email string 消費者 E-Mail
user_birthday string 消費者生日
ip string 消費者來源 IP 必填
issue_invoice_state integer 開立發票 『電子發票是否開立狀態』值參考
invoice_ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
invoice_input_type integer 電子發票開立類型 『電子發票開立類型』值參考
invoice_cloud_type integer 「雲端發票」類型 當invoice_input_type為1,此狀態才有效
『雲端發票類型』值參考
invoice_tax_id string 統一編號 當invoice_input_type為1,此欄位才有效,非必要
invoice_mobile_code string 手機條碼 當invoice_cloud_type為2,此欄位才有效
invoice_natural_person string 自然人憑證條碼 當invoice_cloud_type為3,此欄位才有效
invoice_m_post_zone string EMail 紙本寄送郵遞區號 當invoice_cloud_type為4,此欄位才有效,非必須
invoice_m_address string EMail 紙本寄送住址 當invoice_cloud_type為4,此欄位才有效,非必須
invoice_love_code string 愛心碼 當invoice_input_type為2,此欄位才有效
invoice_b2b_title string 發票抬頭 當invoice_input_type為3時,此欄位才有效
invoice_b2b_id string 統一編號 當invoice_input_type為3時,此欄位才有效
invoice_b2b_post_zone string 發票郵遞區號 當invoice_input_type為3時,此欄位才有效,非必須
invoice_b2b_address string 發票地址 當invoice_input_type為3時,此欄位才有效
agent_sms_fee_type integer 經銷商代收費是否含簡訊費 (0.不含 1.含) 『含不含簡訊費』值參考
agent_charge_fee_type integer 經銷商代收費是否含手續費 (0.不含 1.含) 『含不含手續費類型』值參考
agent_charge_fee string 經銷商代收費
is_agent_charge integer 是否為經銷商代收費模式
若 is_agent_charge 有指定,以指定優先
若欄位agent_charge_fee有費用,或經銷商代收費是含簡訊費、或經銷商代收費含手續費,則預設為1
若欄位agent_charge_fee無費用,且經銷商代收費不含簡訊費、或經銷商代收費不含手續費或參欄位都未使用則預設為0
『是否為經銷商代收費模式』值參考
creditcard_is_automatic_payment string 電子錢包交易時,是否使用自動請款模式(預設自動請款)
非所有收單銀行均有配合
『信用卡自動請款類型』值參考
data_json string MYPAY電子錢包格式(JSON格式) 『MYPAY電子錢包資料』值參考

『直接交易-MYPAY電子錢包交易』回傳欄位

參數名稱 型態 說明 必須
code string 交易狀態代碼
msg string 回傳訊息
uid string Payment Hub之交易流水號
key string 交易驗証碼
finishtime string 交易完成時間(YYYYMMDDHHmmss)
cardno string 銀行端口回傳碼
acode string 授權碼
card_type integer 信用卡卡別 『信用卡別類型』值參考
issuing_bank string 發卡行
issuing_bank_uid string 發卡銀行代碼
transaction_mode integer 交易服務類型 『交易服務類型』值參考
supplier_name string 交易之金融服務商
supplier_code string 交易之金融服務商代碼
order_id string 貴特店系統的訂單編號
user_id string 消費者帳號
cost string 總交易金額
currency string 原交易幣別
actual_cost string 實際交易金額
actual_currency string 實際交易幣別
pfn string 付費方法 『回傳付款方式』值參考
trans_type integer 交易類型 『交易類型定義』值參考
result_type string 回傳結果資料類型 『閘道內容回傳格式類型』值參考
result_content_type string 回傳資料內容類型 『資料內容所屬支付名稱』值參考
result_content string 回傳結果
echo_0 string 自訂回傳參數 1
echo_1 string 自訂回傳參數 2
echo_2 string 自訂回傳參數 3
echo_3 string 自訂回傳參數 4
echo_4 string 自訂回傳參數 5
invoice_state integer 發票開立狀態 『電子發票開立狀態類型』值參考
invoice_state_msg string 發票開立狀態訊息
invoice_date string 發票開立日期(YYYYMMDDHHmmss)
invoice_wordtrack string 發票字軌
invoice_number string 發票號碼
invoice_rand_code string 電子發票隨機碼
invoice_seller_ban string 賣方統一編號
invoice_buyer_ban string 買方統一編號
invoice_left_qrcode string 電子發票左邊QrCode內容
invoice_middle_barcode string 電子發票中間Barcode內容(格式Code-39)
invoice_right_qrcode string 電子發票右邊QrCode內容
invoice_title_type integer 電子發票列印標題格式 『電子發票紙本列印標題類型』值參考
invoice_title string 電子發票列印標題格式
invoice_print_type integer 電子發票列印類型 『電子發票列印類型』值參考
invoice_print_device integer 電子發票列印設備 『電子發票列印設備』值參考
invoice_amount string 電子發票銷售總額
invoice_sales_amount string 電子發票銷售額
invoice_tax_amount string 電子發票稅額
invoice_order_detail string 電子發票全部產品明細(JSON格式) 『商品細項』值參考
invoice_ratetype integer 電子發票稅率別 『電子發票稅率別』值參考
invoice_input_type integer 電子發票開立類型 『電子發票開立類型』值參考
invoice_cloud_type integer 電子發票開立類型-雲端發票類型 『雲端發票類型』值參考
invoice_mobile_code string 當invoice_cloud_type為2時紀錄的手機條碼
invoice_tax_id string 當invoice_cloud_type為2時紀錄的統一編號
invoice_natural_person string 當invoice_cloud_type為3時紀錄的自然人憑證條碼
invoice_m_post_zone string 當invoice_cloud_type為4時紀錄中獎時紙本發票郵遞區號
invoice_m_address string 當invoice_cloud_type為4時紀錄中獎時紙本發票收件住址
invoice_love_code string 當invoice_input_type為2時紀錄的愛心碼
invoice_b2b_title string 當invoice_input_type為3時紀錄的發票抬頭
invoice_b2b_id string 當invoice_input_type為3時紀錄的統一編號
invoice_b2b_post_zone string 當invoice_input_type為3時紀錄的郵遞區號
invoice_b2b_address string 當invoice_input_type為3時紀錄的發票地址

MYPAY電子錢包請款取消授權

<?php
/**
 * 特約商店串接-電子錢包請款取消授權
 */
final class StoreCreditcardCancelAuthorized
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['uid'] = "103274";
        $rawData['key'] = "c1482acd0f7b459ee17b12c29660d582";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/cancelauthorization'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreCreditcardCancelAuthorized = new StoreCreditcardCancelAuthorized();
$StoreCreditcardCancelAuthorized->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 StoreCreditcardCancelAuthorized {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCreditcardCancelAuthorized simulator = new StoreCreditcardCancelAuthorized();
            //僅限走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.store_uid = this.storeUid;
            rawData.uid =  "103274";
            rawData.key =  "c1482acd0f7b459ee17b12c29660d582";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/cancelauthorization";
            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.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, 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["store_uid"] = this.storeUid;
            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 StoreCreditcardCancelAuthorized {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCreditcardCancelAuthorized simulator = new StoreCreditcardCancelAuthorized();
        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("store_uid", this.storeUid);
        rawData.put("uid", "103274");
        rawData.put("key", "c1482acd0f7b459ee17b12c29660d582");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/cancelauthorization");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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 StoreCreditcardCancelAuthorized() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCreditcardCancelAuthorized.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        uid: "103274",
        key: "c1482acd0f7b459ee17b12c29660d582",

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

StoreCreditcardCancelAuthorized = new StoreCreditcardCancelAuthorized();
StoreCreditcardCancelAuthorized.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 StoreCreditcardCancelAuthorized:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'uid': "103274",
            'key': "c1482acd0f7b459ee17b12c29660d582",
        }
        return rawData

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

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

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

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

StoreCreditcardCancelAuthorized = StoreCreditcardCancelAuthorized()
StoreCreditcardCancelAuthorized.run()

回傳 JSON 結構如下:

{
  "code": "B200",
  "msg": "執行成功,取消授權完成",
  "content": {
    "key": "c1482acd0f7b459ee17b12c29660d582",
    "prc": "300",
    "cardno": "493817******0003",
    "acode": "185804",
    "card_type": "1",
    "issuing_bank": "合作金庫",
    "issuing_bank_uid": "006",
    "transaction_mode": 1,
    "supplier_name": "凱基銀行",
    "supplier_code": "BC",
    "order_id": "1234567890",
    "user_id": "phper",
    "uid": 103274,
    "cost": 10,
    "currency": "TWD",
    "actual_cost": 10,
    "actual_currency": "TWD",
    "voucher_paid": [],
    "voucher_free": [],
    "price": 0,
    "actual_price": 0,
    "recharge_code": "",
    "love_cost": 0,
    "retmsg": "交易失敗",
    "pay_mode_uid": 1,
    "pfn": "CREDITCARD",
    "trans_type": 1,
    "redeem": "",
    "installment": "",
    "finishtime": "",
    "store_group_id": "",
    "group_id": "",
    "nois": "",
    "payment_name": "",
    "bank_id": "",
    "result_type": 4,
    "result_content_type": "CREDITCARD",
    "result_content": "{}",
    "expired_date": "",
    "appropriation_date": "",
    "invoice_state": 0,
    "invoice_date": "20220301151856",
    "invoice_wordtrack": "JH",
    "invoice_number": "00000011",
    "invoice_rand_code": "9899",
    "invoice_seller_ban": "28915188",
    "invoice_buyer_ban": "",
    "invoice_left_qrcode": "JH00000011111030198990000000a0000000a0000000028915188qKBLmT8adunB+e9m7isLNQ==:**********:1:1:1:倚天劍模型:1:10:",
    "invoice_middle_barcode": "11104JH000000119899",
    "invoice_right_qrcode": "**",
    "invoice_title_type": 1,
    "invoice_title": "123",
    "invoice_print_type": 0,
    "invoice_print_device": 0,
    "invoice_amount": "10",
    "invoice_sales_amount": "10",
    "invoice_tax_amount": "0",
    "invoice_order_detail": "[{\"Description\":\"倚天劍模型\",\"Quantity\":\"1\",\"UnitPrice\":\"10\",\"Amount\":\"10\"}]",
    "invoice_ratetype": 1,
    "invoice_input_type": 1,
    "invoice_cloud_type": 2,
    "invoice_mobile_code": "\/NFVIAZP",
    "invoice_tax_id": "",
    "invoice_natural_person": "",
    "invoice_m_post_zone": "",
    "invoice_m_address": "",
    "invoice_love_code": "",
    "invoice_b2b_title": "",
    "invoice_b2b_id": "",
    "invoice_b2b_post_zone": "",
    "invoice_b2b_address": "",
    "invoice_allowance": [
      {
        "uid": 103274,
        "amount": "10",
        "order_detail": "[{\"SeqNo\":\"0\",\"ItemID\":\"103274\",\"ItemName\":\"倚天劍模型\",\"Qty\":\"1\",\"TotalAmount\":\"10\",\"RateType\":\"1\"}]"
      }
    ],
    "refund_order": [],
    "cancel_order": [],
    "echo_0": "",
    "echo_1": "",
    "echo_2": "",
    "echo_3": "",
    "echo_4": ""
  }
}

MYPAY電子錢包請款取消授權,若使用自行請款模式,當交易狀態為授權完成(245)時,則可以發動此電子錢包來進行取消授權,用以取消交易,並釋出消費者圈存金額。

特約商店『電子錢包請款取消授權』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/cancelauthorization"}
JSON格式,AES256加密資料
encry_data text 『電子錢包請款取消授權』欄位參考
JSON格式,AES256加密資料

『電子錢包請款取消授權』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店編號 必填
uid string 交易流水號
key string 交易驗証碼

『電子錢包請款取消授權』回傳欄位

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

MYPAY電子錢包授權請款

<?php
/**
 * 特約商店串接-MYPAY電子錢包授權請款
 */
final class StoreCreditcardRequestPayment
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['uid'] = "103283";
        $rawData['key'] = "54886f30612771f8f10d94499a41a347";
        $rawData['cost'] = 9;
        $rawData['items'] = [
                                [
                                 'id' => '1',
                                 'name' => '商品名稱',
                                 'cost' => '1',
                                 'amount' => '1',
                                 'total' => '1'
                                ]
                            ];

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/authorizedrequestpayment'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreCreditcardRequestPayment = new StoreCreditcardRequestPayment();
$StoreCreditcardRequestPayment->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>
    /// 特約商店串接-MYPAY電子錢包授權請款
    /// </summary>
    public class StoreCreditcardRequestPayment {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreCreditcardRequestPayment simulator = new StoreCreditcardRequestPayment();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            ArrayList items = new ArrayList();

            dynamic item = new ExpandoObject();
            item.id = "1";
            item.name = "商品名稱";
            item.cost = "1";
            item.amount = "1";
            item.total = "1";
            items.Add(item);


            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.uid =  "103283";
            rawData.key =  "54886f30612771f8f10d94499a41a347";
            rawData.cost =  9;
            rawData.items = items;

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/authorizedrequestpayment";
            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.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, 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["store_uid"] = this.storeUid;
            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;
/**
 * 特約商店串接-MYPAY電子錢包授權請款
 * 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 StoreCreditcardRequestPayment {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreCreditcardRequestPayment simulator = new StoreCreditcardRequestPayment();
        String json = simulator.post(simulator.getPostData());
        System.out.print(json);
    }

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

        ArrayList items = new ArrayList();

        Map<Object, Object> item = new HashMap<Object, Object>();
        item.put("id", "1");
        item.put("name", "商品名稱");
        item.put("cost", "1");
        item.put("amount", "1");
        item.put("total", "1");
        items.add(item);


        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("store_uid", this.storeUid);
        rawData.put("uid", "103283");
        rawData.put("key", "54886f30612771f8f10d94499a41a347");
        rawData.put("cost", 9);
        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/authorizedrequestpayment");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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');

/**
 * 特約商店串接-MYPAY電子錢包授權請款
 */
function StoreCreditcardRequestPayment() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreCreditcardRequestPayment.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        uid: "103283",
        key: "54886f30612771f8f10d94499a41a347",
        cost: 9,
        items: [
            {
                'id': "1",
                'name': "商品名稱",
                'cost': "1",
                'amount': "1",
                'total': "1"
            }
        ],

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

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

"""特約商店串接-MYPAY電子錢包授權請款
"""
class StoreCreditcardRequestPayment:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'uid': "103283",
            'key': "54886f30612771f8f10d94499a41a347",
            'cost': 9,
            'items': [
                         {
                          'id': "1",
                          'name': "商品名稱",
                          'cost': "1",
                          'amount': "1",
                          'total': "1"
                         }
                     ],
        }
        return rawData

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

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

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

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

StoreCreditcardRequestPayment = StoreCreditcardRequestPayment()
StoreCreditcardRequestPayment.run()

回傳 JSON 結構如下:

{
  "code": "B200",
  "msg": "執行成功,請款處理進行中。",
  "content": {
    "key": "54886f30612771f8f10d94499a41a347",
    "prc": "247",
    "cardno": "493817******0003",
    "acode": "063218",
    "card_type": "1",
    "issuing_bank": "合作金庫",
    "issuing_bank_uid": "006",
    "transaction_mode": 1,
    "supplier_name": "凱基銀行",
    "supplier_code": "BC",
    "order_id": "1234567890",
    "user_id": "phper",
    "uid": 103283,
    "cost": 10,
    "currency": "TWD",
    "actual_cost": 0,
    "actual_currency": "TWD",
    "voucher_paid": [],
    "voucher_free": [],
    "price": 0,
    "actual_price": 0,
    "recharge_code": "",
    "love_cost": 0,
    "retmsg": "請款進行中",
    "pay_mode_uid": 1,
    "pfn": "CREDITCARD",
    "trans_type": 1,
    "redeem": "",
    "installment": "",
    "finishtime": "",
    "store_group_id": "",
    "group_id": "",
    "nois": "",
    "payment_name": "",
    "bank_id": "",
    "result_type": 4,
    "result_content_type": "CREDITCARD",
    "result_content": "{}",
    "expired_date": "",
    "appropriation_date": "",
    "invoice_state": 0,
    "invoice_date": "20220301160234",
    "invoice_wordtrack": "JH",
    "invoice_number": "00000014",
    "invoice_rand_code": "4224",
    "invoice_seller_ban": "28915188",
    "invoice_buyer_ban": "",
    "invoice_left_qrcode": "JH00000014111030142240000000a0000000a0000000028915188DdkbPtMzNyH4rp0qk7dRig==:**********:1:1:1:商品名稱:1:10:",
    "invoice_middle_barcode": "11104JH000000144224",
    "invoice_right_qrcode": "**",
    "invoice_title_type": 1,
    "invoice_title": "123",
    "invoice_print_type": 0,
    "invoice_print_device": 0,
    "invoice_amount": "10",
    "invoice_sales_amount": "10",
    "invoice_tax_amount": "0",
    "invoice_order_detail": "[{\"Description\":\"商品名稱\",\"Quantity\":\"1\",\"UnitPrice\":\"10\",\"Amount\":\"10\"}]",
    "invoice_ratetype": 1,
    "invoice_input_type": 1,
    "invoice_cloud_type": 2,
    "invoice_mobile_code": "\/NFVIAZP",
    "invoice_tax_id": "",
    "invoice_natural_person": "",
    "invoice_m_post_zone": "",
    "invoice_m_address": "",
    "invoice_love_code": "",
    "invoice_b2b_title": "",
    "invoice_b2b_id": "",
    "invoice_b2b_post_zone": "",
    "invoice_b2b_address": "",
    "invoice_allowance": [],
    "refund_order": [],
    "cancel_order": [],
    "echo_0": "",
    "echo_1": "",
    "echo_2": "",
    "echo_3": "",
    "echo_4": ""
  }
}

電子錢包交易,若使用自行請款模式,交易狀態為授權完成(245)時,則可以發動此MYPAY電子錢包授權請款,用以完成交易。發動只限定一次。可全額或部分請款。

特約商店『MYPAY電子錢包授權請款』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/authorizedrequestpayment"}
JSON格式,AES256加密資料
encry_data text 『電子錢包請款取消授權』欄位參考
JSON格式,AES256加密資料

『MYPAY電子錢包授權請款』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店編號 必填
uid string 交易流水號
key string 交易驗証碼
cost integer 總請款金額
items array 不想請款的產品項目(商品名稱必須與原交易時商品名稱相同)
如果部分金額不想請款才需要使用,也就是說如果原訂單金額是100,只想請款40,那不想請款的那60元必須代入
每筆『商品項目』欄位參考

『MYPAY電子錢包授權請款』回傳欄位

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

MYPAY電子錢包解除綁定

<?php
/**
 * 特約商店串接-MYPAY電子錢包解除綁定
 */
final class StoreEWalletDisabler
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";
    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['user_id'] = "phper";
        $rawData['pfn'] = "CREDITCARD";
        $rawData['reason'] = "系統自動取消";

        return $rawData;
    }
    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/ewalletdisabler'
        );
    }
    /**
     * 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['store_uid'] = $this->storeUid;
        $postData['service'] = $this->encrypt($this->getService(), $this->storeKey);
        $postData['encry_data'] = $this->encrypt($this->getRawData(), $this->storeKey);
        return $postData;
    }
    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }
}

$StoreEWalletDisabler = new StoreEWalletDisabler();
$StoreEWalletDisabler->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>
    /// 特約商店串接-MYPAY電子錢包解除綁定
    /// </summary>
    public class StoreEWalletDisabler {
        /// <summary>
        /// 特約商店商務代號
        /// </summary>
        public string storeUid = "289151880002";
        /// <summary>
        /// 特約商店金鑰或認證碼
        /// </summary>
        public string storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
        /// <summary>
        /// 串接交易位置
        /// </summary>
        public string url = "https://pay.usecase.cc/api/init";
        /// <summary>
        /// 執行
        /// </summary>
        static void Main() {
            StoreEWalletDisabler simulator = new StoreEWalletDisabler();
            //僅限走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.store_uid = this.storeUid;
            rawData.user_id =  "phper";
            rawData.pfn =  "CREDITCARD";
            rawData.reason =  "系統自動取消";

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/ewalletdisabler";
            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.storeKey, IV);
            var svr_encode = Encrypt(svr_json, this.storeKey, 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["store_uid"] = this.storeUid;
            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;
/**
 * 特約商店串接-MYPAY電子錢包解除綁定
 * 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 StoreEWalletDisabler {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreEWalletDisabler simulator = new StoreEWalletDisabler();
        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("store_uid", this.storeUid);
        rawData.put("user_id", "phper");
        rawData.put("pfn", "CREDITCARD");
        rawData.put("reason", "系統自動取消");

        return rawData;
    }
    /**
     * 取得服務位置
     * @return 串接服務資料
     */
    public Map getService() {
        Map<Object, Object> rawData = new HashMap<Object, Object>();
        rawData.put("service_name", "api");
        rawData.put("cmd", "api/ewalletdisabler");
        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.storeKey), "UTF-8");
            String svr_toUrlEncode = URLEncoder.encode(
                    this.encrypt(this.getService(), this.storeKey), "UTF-8");

            postData = "store_uid=" + this.storeUid + "&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');

/**
 * 特約商店串接-MYPAY電子錢包解除綁定
 */
function StoreEWalletDisabler() {
    // 特約商店商務代號
    this.storeUid = "289151880002";
    // 特約商店金鑰或認證碼
    this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    // 串接交易位置
    this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreEWalletDisabler.prototype.getRawData = function () {
    return {
        store_uid: this.storeUid,
        user_id: "phper",
        pfn: "CREDITCARD",
        reason: "系統自動取消",

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

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

"""特約商店串接-MYPAY電子錢包解除綁定
"""
class StoreEWalletDisabler:
    # 特約商店商務代號
    storeUid = "289151880002"
    # 特約商店金鑰或認證碼
    storeKey = b"KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx"
    # 串接交易位置
    url = "https://pay.usecase.cc/api/init"

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'user_id': "phper",
            'pfn': "CREDITCARD",
            'reason': "系統自動取消",
        }
        return rawData

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

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

    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 = {
            'store_uid': self.storeUid,
            'service': self.encrypt(self.getService(), self.storeKey),
            'encry_data': self.encrypt(self.getRawData(), self.storeKey)
        }
        return postData

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

StoreEWalletDisabler = StoreEWalletDisabler()
StoreEWalletDisabler.run()

回傳 JSON 結構如下:

{
    "code": "B200",
    "msg": "執行成功",
    "content": {
        "pfn": "CREDITCARD",
        "cardno": "400361******7729",
        "user_id": "phper",
        "cellphone_code": "886",
        "cellphone": "918123123",
        "virtual_pan": "b06419d0aaafb9683e163635a56bbadf",
        "enable": "0"
    }
}

透過API指定消費者帳號做解除電子錢包綁定

特約商店『MYPAY電子錢包解除綁定』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name": "api", "cmd": "api\/ewalletdisabler"}
JSON格式,AES256加密資料
encry_data text 『MYPAY電子錢包解除綁定』欄位參考
JSON格式,AES256加密資料

『MYPAY電子錢包解除綁定』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店商務代號 必填
user_id string 消費者帳號 必填
pfn string 綁定支付方式 必填
『付款方式』值參考
reason string 取消電子錢包綁定之原因 必填

『MYPAY電子錢包解除綁定』回傳欄位

參數名稱 型態 說明 必須
code string 交易回傳碼 『電子錢包執行狀態碼』值參考
msg string 回傳訊息
content null 交易網址 『電子錢包虛擬卡號回傳資訊』值參考

電子錢包虛擬卡號回傳資訊』回報欄位

參數名稱 型態 說明 必須
pfn string 支付類型
cardno string 綁定卡號 (僅顯示前六後四)
user_id string 消費者帳號
cellphone_code string 用以取消綁定之手機國碼
cellphone string 用以取消綁定之手機號碼
virtual_pan string 虛擬卡號
enable string 是否啟用 0.關閉 1.啟用

其他關聯欄位說明

關聯欄位

『商品項目』欄位

參數名稱 型態 說明 必須
id string 商品編號 必填
name string 商品名稱 必填
cost integer 商品單價 必填
amount integer 商品數量 必填
total integer 商品小計 必填

『MYPAY電子錢包資料』欄位

參數名稱 型態 說明 必須
virtualPan string 虛擬卡號 必填
userId string 電子錢包綁定帳號 必填
bizId string 電子錢包綁定商務代號 必填

『商品細項』欄位

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

值的定義

『付款方式』值內容

型態 說明 備註
CREDITCARD string 信用卡
ABROAD string 海外信用卡

『證號類型』值內容

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

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

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

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

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

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

型態 說明 備註
0 integer 未使用電子發票開立
1 integer 雲端發票
2 integer 發票捐贈
3 integer 實體發票 重要提示,若選擇此模式,商戶需要自行列印實體發票交付給消費者,系統不會寄送mail通知與中獎後也不會通知給消費者。電子發票列印格式,請參考國稅局頒布標準。

『雲端發票類型』值內容

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

『含不含簡訊費』值內容

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

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

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

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

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

『信用卡自動請款類型』值內容

型態 說明 備註
0 string 自行請款
1 string 自動請款(預設)

『信用卡別類型』值內容

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

『交易服務類型』值內容

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

『回傳付款方式』值內容

型態 說明 備註
CREDITCARD string 信用卡
ABROAD string 海外信用卡

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

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

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

型態 說明 備註
CREDITCARD string 信用卡
ABROAD string 海外信用卡

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

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

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

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

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

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

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

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

『電子錢包執行狀態碼』值內容

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

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

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

『交易查詢』欄位

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

附錄一:設定調整

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

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

附錄三:API模擬串接服務

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

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

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

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

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