NAV
php csharp java javascript python

特約商店 定期定額獨立頁面

修改歷程

版本 異動日期 修訂內容 位置
1.0 2024.03.05 新版文件

開發前請先閱讀

金鑰的注意事項

Q:金鑰的有效期限

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

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

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

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

A:會

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

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

請求結果的告知

Q:何時會將建立、修改的結果告知

A:當操作者成功建立、修改或者當網址超過15分鐘沒有觸發延長,會由附錄三 這邊的設定,背景主動發動通知商家

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

A:請直接回應8888,如沒有回應,MyPay會通知5次

定期定額獨立頁面設計概要

安全性設計

每次請求新增或修改的網址僅存在15分鐘,並且開始頁面時必須輸入請求店家的統編,以確認資料的安全性

定期定額 目前提供之服務與格式

定期定額 提供應用方式,應用情境如下:

請求新增網址:透過MyPay提供的定期定額頁面,新增一筆定期定額扣款資料

請求修改網址:透過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相容編碼

請求建立定期定額頁面

<?php

final class StoreBatchDebitCreator
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "5p8LnrEiuwUn8Zn5yH31s0mg3Jjq5elB";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";

    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }

    /**
     * 資料 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;
    }

    /**
     * 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;
    }

    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/batchdebitcreator'
        );
    }

    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['project_name'] = "自訂扣款名目" . date("Ymd");
        $rawData['regular'] = "M";
        $rawData['order_id'] = "T" . time();
        $rawData['group_id'] = "A" . time();

        return $rawData;
    }
}

$StoreBatchDebitCreator = new StoreBatchDebitCreator();
$StoreBatchDebitCreator->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 StoreBatchDebitCreator {
        /// <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() {
            StoreBatchDebitCreator simulator = new StoreBatchDebitCreator();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            datePart = DateTime.Now.ToString("yyyyMMdd");

            DateTime now = DateTime.Now;
            long unixTimestamp = ((DateTimeOffset)now).ToUnixTimeSeconds();
            string result = string.Concat("A", unixTimestamp);

            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.project_name =  string.Concat("自訂扣款名目", datePart);
            rawData.regular =  'M';
            rawData.order_id =  string.Concat("A", unixTimestamp);
            rawData.group_id =  string.Concat("T", unixTimestamp);

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/batchdebitcreator";
            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 StoreBatchDebitCreator {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreBatchDebitCreator simulator = new StoreBatchDebitCreator();
        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>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String currentDate = LocalDateTime.now().format(formatter);
        rawData.put("store_uid", this.storeUid);
        rawData.put("project_name", "自訂扣款名目" + currentDate);
        rawData.put("regular", "M");
        rawData.put("order_id", "T" + System.currentTimeMillis() / 1000);
        rawData.put("group_id", "A" + System.currentTimeMillis() / 1000);

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

/**
 * 特約商店串接-定期定額請求建立網址
 */
function StoreBatchDebitCreator() {
  // 特約商店商務代號
  this.storeUid = "289151880002";
  // 特約商店金鑰或認證碼
  this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
  // 串接交易位置
  this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreBatchDebitCreator.prototype.getRawData = function () {
  const currentDate = new Date().toISOString().slice(0, 10).replace(/-/g, '');

  return {
    store_uid: this.storeUid,
    project_name: "自訂扣款名目" + currentDate,
    regular: "M",
    order_id: "T" + Math.floor(Date.now() / 1000),
    group_id: "A" + Math.floor(Date.now() / 1000)
  };
};
/**
 * 取得服務位置
 */
StoreBatchDebitCreator.prototype.getService = function () {
  return {
    service_name: "api",
    cmd: "api/batchdebitcreator"
  };
};
/**
 * AES 256 加密
 */
StoreBatchDebitCreator.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 到主機
 */
StoreBatchDebitCreator.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();
  });
};
/**
 * 取得送出欄位資料
 */
StoreBatchDebitCreator.prototype.getPostData = function () {
  return {
    "store_uid": this.storeUid,
    "service": this.encrypt(this.getService(), this.storeKey),
    "encry_data": this.encrypt(this.getRawData(), this.storeKey)
  };
};
/**
 * 執行
 */
StoreBatchDebitCreator.prototype.run = async function () {
  json = await this.post(this.getPostData())
  console.log(json);
};

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

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

        Returns:
            {dict}: 欄位資料
        """
        current_date = datetime.now().strftime('%Y%m%d')
        rawData = {
            'store_uid': self.storeUid,
            'project_name': "自訂扣款名目" + current_date,
            'regular': "M",
            'order_id': "T" + str(int(time.time())),
            'group_id': "A" + str(int(time.time())),
        }
        return rawData

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

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

    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)

StoreBatchDebitCreator = StoreBatchDebitCreator()
StoreBatchDebitCreator.run()

回傳 JSON 結構如下:

{
  "code": "200",
  "msg": "資料正確",
  "page_code": "6d5924df99",
  "url": "http:\/\/pay.k20-mypay.tw\/regularinstallment\/link\/6d5924df99.html"
}

在請求返回後,網址只能存在15分鐘,並且只能於同一個裝置同一瀏覽器開啟,一旦更換瀏覽器或裝置開啟,將會顯示頁面不存在,一旦新增完畢後,系統將會背景通知設定結果

特約商店『請求建立定期定額頁面』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name":"api","cmd":"api\/batchdebitcreator"}
JSON格式,AES256加密資料
encry_data text 『請求建立定期定額頁面』欄位參考
JSON格式,AES256加密資料

『請求建立定期定額頁面』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
project_name string 專案名稱 必填
regular string 扣款單位 必填
『分期類型定義』值參考
notify_before string 扣款前通知 專案名稱若已存在,則此蘭位於新增時無效,非必填
『扣款通知』值參考
notify_before_message string 通知內容 專案名稱若已存在,則此蘭位於新增時無效
notify_after string 扣款後通知 專案名稱若已存在,則此蘭位於新增時無效,非必填
『扣款通知』值參考
notify_after_message string 通知內容
retry_enable int 扣款失敗後,是否啟用重扣機制 專案名稱若已存在,則此蘭位於新增時無效,非必填
『扣款失敗後,重扣是否啟用』值參考
fail_notify_delay string 扣款失敗,延遲幾日後重扣,單位:日 專案名稱若已存在,則此蘭位於新增時無效,非必填
僅能輸入3~5
retry_time string 扣款失敗後,要重試幾次重扣 專案名稱若已存在,則此蘭位於新增時無效,非必填
僅能輸入1~2
order_id string 請求編號(請求編號最長為50bytes),不可重複 必填
group_id string 扣款單號(不可重複,每當交易回報時,會帶入此單號,使之識別扣款為同一筆申請的定期定額) 必填
pay_mode_uid integer 付款方式 非必填
『卡片類型定義』值參考
name string 扣款人姓名 非必填
debtor_type integer 扣款人身份類型 非必填
『證號類型』值參考
debtor_id string 扣款人證號 非必填
phone_code string 扣款人手機國碼 非必填
phone string 扣款人手機
mail string 扣款人電子信箱
store_member_id string 網站會員ID
currency string 幣別(目前強制為TWD)
cost string 每期應扣金額 非必填
regular_first_charge_date string 起扣日期 非必填
regular_total string 扣款次數 非必填
invoice_type integer 發票類型(預設0) 非必填
『單據類型』值參考
cloud_type int 雲端載具類型(預設0) 非必填
『雲端發票類型』值參考
invoice_mobile_code string 當cloud_type為2時紀錄的手機條碼
invoice_natural_person string 當cloud_type為3時紀錄的自然人憑證條碼
invoice_love_code string 當input_type為2時紀錄的愛心碼
tong_bian string 發票統編 非必填
donation_statistics_type int 捐款收據統計模式(預設0),當invoice_type為5時必填,且不能為0 依狀況必填
『捐款收據統計模式』值參考
donation_identity_type int 捐款收據收件對象當invoice_type為5時必填,且不能為0 依狀況必填
『捐款單位』值參考
donation_type_no string 捐款收據對象身分證或統編,當donation_identity_type為1時填身分證2填統編,當donation_identity_type為1時必填
donation_type_name string 捐款收據對象姓名或公司名稱,當donation_identity_type為1時填姓名2填公司名稱,當donation_identity_type為1時必填
invoice_receipt_zip_code string 捐款收據地址郵政區碼
invoice_receipt_city string 捐款收據地址縣市
invoice_receipt_district string 捐款收據地址鄉區
invoice_receipt_address string 捐款收據地址
echo_0 string 自訂回傳1 非必填
echo_1 string 自訂回傳2 非必填
echo_2 string 自訂回傳3 非必填
echo_3 string 自訂回傳4 非必填
echo_4 string 自訂回傳5 非必填

『請求建立定期定額頁面』回傳欄位

參數名稱 型態 說明 必須
code string 回應代碼 『執行結果代碼』值參考
msg string 回應說明
page_code string 頁面代碼
url string 頁面網址

請求修改定期定額網址

<?php

final class StoreBatchDebitUpdater
{
    /**
     * 特約商店商務代號
     * @var string
     */
    public $storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     * @var string
     */
    public $storeKey = "5p8LnrEiuwUn8Zn5yH31s0mg3Jjq5elB";
    /**
     * 串接交易位置
     * @var string
     */
    public $url = "https://pay.usecase.cc/api/init";

    /**
     * 執行
     */
    public function run()
    {
        $json = $this->post($this->getPostData());
        echo $json;
    }

    /**
     * 資料 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;
    }

    /**
     * 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;
    }

    /**
     * 取得服務位置
     * @return array
     */
    public function getService()
    {
        return array(
            'service_name' => 'api',
            'cmd' => 'api/batchdebitupdater'
        );
    }

    /**
     * 取得串接欄位資料
     * @return array
     */
    public function getRawData()
    {
        $rawData = array();
        $rawData['store_uid'] = $this->storeUid;
        $rawData['original_order_id'] = "T1709533895";
        $rawData['order_id'] = "T" . time();

        return $rawData;
    }
}

$StoreBatchDebitUpdater = new StoreBatchDebitUpdater();
$StoreBatchDebitUpdater->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 StoreBatchDebitUpdater {
        /// <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() {
            StoreBatchDebitUpdater simulator = new StoreBatchDebitUpdater();
            //僅限走https的Tls 1.2以上版本
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            //發送至遠端
            var result = simulator.Post(simulator.GetPostData());

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

            datePart = DateTime.Now.ToString("yyyyMMdd");

            DateTime now = DateTime.Now;
            long unixTimestamp = ((DateTimeOffset)now).ToUnixTimeSeconds();

            dynamic rawData = new ExpandoObject();
            rawData.store_uid = this.storeUid;
            rawData.original_order_id = "T1709533895";
            rawData.order_id =  string.Concat("A", unixTimestamp);

            return rawData;
        }
        /// <summary>
        /// 取得服務位置
        /// </summary>
        private ServiceRequest GetService() {
            ServiceRequest rawData = new ServiceRequest();
            rawData.service_name = "api";
            rawData.cmd = "api/batchdebitupdater";
            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 StoreBatchDebitCreator {
    /**
     * 特約商店商務代號
     */
    String storeUid = "289151880002";
    /**
     * 特約商店金鑰或認證碼
     */
    String storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
    /**
     * 串接交易位置
     */
    String url = "https://pay.usecase.cc/api/init";
    /**
     * 執行
     * @param  args
     */
    public static void main(String[] args) {
        StoreBatchDebitCreator simulator = new StoreBatchDebitCreator();
        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>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String currentDate = LocalDateTime.now().format(formatter);
        rawData.put("store_uid", this.storeUid);
        rawData.put("original_order_id", "T1709533895");
        rawData.put("order_id", "T" + System.currentTimeMillis() / 1000);

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

/**
 * 特約商店串接-定期定額請求修改網址
 */
function StoreBatchDebitUpdater() {
  // 特約商店商務代號
  this.storeUid = "289151880002";
  // 特約商店金鑰或認證碼
  this.storeKey = "KYTjd9ACcjGaTK6V3zWmMkyrQS08Ndcx";
  // 串接交易位置
  this.url = "https://pay.usecase.cc/api/init";
};
/**
 * 取得串接欄位資料
 */
StoreBatchDebitUpdater.prototype.getRawData = function () {
  return {
    store_uid: this.storeUid,
    original_order_id: "T1709533895",
    order_id: "T" + Math.floor(Date.now() / 1000),
  };
};
/**
 * 取得服務位置
 */
StoreBatchDebitUpdater.prototype.getService = function () {
  return {
    service_name: "api",
    cmd: "api/batchdebitupdater"
  };
};
/**
 * AES 256 加密
 */
StoreBatchDebitUpdater.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 到主機
 */
StoreBatchDebitUpdater.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();
  });
};
/**
 * 取得送出欄位資料
 */
StoreBatchDebitUpdater.prototype.getPostData = function () {
  return {
    "store_uid": this.storeUid,
    "service": this.encrypt(this.getService(), this.storeKey),
    "encry_data": this.encrypt(this.getRawData(), this.storeKey)
  };
};
/**
 * 執行
 */
StoreBatchDebitUpdater.prototype.run = async function () {
  json = await this.post(this.getPostData())
  console.log(json);
};

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

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

        Returns:
            {dict}: 欄位資料
        """
        rawData = {
            'store_uid': self.storeUid,
            'original_order_id': "T1709533895",
            'order_id': "T" + str(int(time.time()))
        }
        return rawData

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

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

    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)

StoreBatchDebitUpdater = StoreBatchDebitUpdater()
StoreBatchDebitUpdater.run()

回傳 JSON 結構如下:

{
  "code": "200",
  "msg": "資料正確",
  "page_code": "16796e61b1",
  "url": "http:\/\/pay.k20-mypay.tw\/regularinstallment\/link\/16796e61b1.html"
}

特約商店『請求修改定期定額網址』參數說明

欄位 型態 說明
store_uid string(16) 特約商店商務代號
service text {"service_name":"api","cmd":"api\/batchdebitupdater"}
JSON格式,AES256加密資料
encry_data text 『請求修改定期定額網址』欄位參考
JSON格式,AES256加密資料

『請求修改定期定額網址』欄位

參數名稱 型態 說明 必須
store_uid string 特約商店代碼 必填
order_id string 請求編號(請求編號最長為50bytes),不可重複 必填
original_order_id string 原始單號,必須是當初發動建立定期定額的order_id 必填
notify_before string 扣款前通知 『扣款通知』值參考
notify_before_message string 通知內容
notify_after string 扣款後通知 『扣款通知』值參考
notify_after_message string 通知內容
retry_enable int 扣款失敗後,是否啟用重扣機制(預設1) 非必填
『扣款失敗後,重扣是否啟用』值參考
fail_notify_delay string 扣款失敗,延遲幾日後重扣,單位:日 專案名稱若已存在,則此蘭位於新增時無效,非必填
僅能輸入3~5
retry_time string 扣款失敗後,要重試幾次重扣 專案名稱若已存在,則此蘭位於新增時無效,非必填
僅能輸入1~2
pay_mode_uid integer 付款方式 非必填
『卡片類型定義』值參考
card_lock integer 信用卡資料是否解鎖(預設0) 非必填
『更新頁面設定鎖』值參考
member_lock integer 會員資料鎖(預設0) 非必填
『更新頁面設定鎖』值參考
name string 扣款人姓名 非必填
debtor_type integer 扣款人身份類型(預設) 非必填
『證號類型』值參考
debtor_id string 扣款人證號 非必填
phone_code string 扣款人手機國碼 非必填
phone string 扣款人手機
mail string 扣款人電子信箱
store_member_id string 網站會員ID
currency string 幣別(目前強制為TWD)
cost string 每期應扣金額 非必填
invoice_lock int 發票/收據 鎖(預設0) 非必填
『更新頁面設定鎖』值參考
invoice_type integer 發票類型(預設0) 非必填
『單據類型』值參考
cloud_type int 雲端載具類型(預設0) 非必填
『雲端發票類型』值參考
invoice_mobile_code string 當cloud_type為2時紀錄的手機條碼
invoice_natural_person string 當cloud_type為3時紀錄的自然人憑證條碼
invoice_love_code string 當input_type為2時紀錄的愛心碼
tong_bian string 發票統編 非必填
donation_statistics_type int 捐款收據統計模式(預設0),當invoice_type為5時必填,且不能為0 依狀況必填
『捐款收據統計模式』值參考
donation_identity_type int 捐款收據收件對象當invoice_type為5時必填,且不能為0 依狀況必填
『捐款單位』值參考
donation_type_no string 捐款收據對象身分證或統編,當donation_identity_type為1時填身分證2填統編,當donation_identity_type為1時必填
donation_type_name string 捐款收據對象姓名或公司名稱,當donation_identity_type為1時填姓名2填公司名稱,當donation_identity_type為1時必填
invoice_receipt_zip_code string 捐款收據地址郵政區碼
invoice_receipt_city string 捐款收據地址縣市
invoice_receipt_district string 捐款收據地址鄉區
invoice_receipt_address string 捐款收據地址
edit_debit_lock int 扣款設定是否解鎖(預設0) 非必填
『更新頁面設定鎖』值參考
debit_setting_type int 扣款設定異動(預設0) 非必填
『』值參考
stop_date string 停扣日,格式:YYYY-MM-DD 非必填
delay_start_date string 延扣起始日
delay_end_date string 延扣結束日
stop_reason string 停扣、延扣原因
uniform_invoice_tax_name string 免用統一發票買受人
uniform_invoice_tax_id string 免用統一發票買受人統編
echo_lock int 自訂資料鎖(預設0) 非必填
『更新頁面設定鎖』值參考
echo_0 string 自訂回傳1 非必填
echo_1 string 自訂回傳2 非必填
echo_2 string 自訂回傳3 非必填
echo_3 string 自訂回傳4 非必填
echo_4 string 自訂回傳5 非必填

『請求修改定期定額網址』回傳欄位

參數名稱 型態 說明 必須
code string 回應代碼 『執行結果代碼』值參考
msg string 回應說明
page_code string 頁面代碼
url string 頁面網址

其他關聯欄位說明

關聯欄位

『分期類型定義』值內容

型態 說明 備註
W string 每週定期扣款
F string 雙週定期扣款
M string 每月定期扣款
S string 每季定期扣款
H string 每半年定期扣款
A string 每一年定期扣款
O string 一次性扣款

『扣款通知』值內容

型態 說明 備註
0 不通知
1 mail
2 簡訊

『扣款失敗後,重扣是否啟用』值內容

型態 說明 備註
0
1

『卡片類型定義』值內容

型態 說明 備註
1 信用卡
9 海外信用卡
29 美國運通

『證號類型』值內容

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

『單據類型』值內容

型態 說明 備註
0 不開
1 雲端發票
2 捐贈
4 免用統一發票收據
5 捐贈收據

『雲端發票類型』值內容

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

『捐款收據統計模式』值內容

型態 說明 備註
0 無作用
1 單筆
2 年度

『捐款單位』值內容

型態 說明 備註
0 無作用,預設
1 個人
2 公司

『更新頁面設定鎖』值內容

型態 說明 備註
0 不解除
1 解除

附錄一:定期定額請求建立、修改網址狀態碼

狀態代碼 狀態說明 詳細說明
100 系統收到資料不正確。
200 系統收到正確資料。
400 系統錯誤

附錄二:定期定額,新增或修改背景通知結果回報欄位

當新增或修改結束後,若有在後台設定回傳通知,系統將會將此次修改結果回傳於設定的url

背景通知 JSON 結構如下:

{
  "code": "A0000",
  "msg": "成功",
  "page_code": "4f10a91077",
  "order_id": "T1709533895",
  "indice_data": {
    "name": "gogoro24期零利率",
    "regular": "M",
    "notify_before": "2",
    "notify_before_message": "(s:-特店名稱-:)將於(s:-扣款月日-:)為(s:-產品名稱-:)扣款,信用卡帳單顯示:(s:-金流受款名稱-:),謝謝",
    "notify_after": "0",
    "notify_after_message": "(s:-特店名稱-:)將於(s:-扣款月日-:)為(s:-產品名稱-:)扣款,信用卡帳單顯示:(s:-金流受款名稱-:),謝謝",
    "retry_enable": "1",
    "fail_notify_delay": "3",
    "retry_time": "1"
  },
  "member_data": {
    "group_id": "A1709533895",
    "pay_mode_uid": "1",
    "name": "王安石",
    "debtor_type": "1",
    "debtor_id": "A123456789",
    "phone_code": "886",
    "phone": "900000000",
    "mail": "[email protected]",
    "store_member_id": "0900000000",
    "currency": "TWD",
    "cost": "100.0000",
    "regular_first_charge_date": "2024-03-04",
    "regular_stop_charge_date": "",
    "invoice_type": "1",
    "cloud_type": "4",
    "invoice_mobile_code": "\/MHX377Q",
    "invoice_natural_person": "",
    "invoice_love_code": "",
    "tong_bian": "",
    "donation_statistics_type": "0",
    "donation_identity_type": "0",
    "donation_type_no": "",
    "donation_type_name": "",
    "invoice_receipt_zip_code": "",
    "invoice_receipt_city": "",
    "invoice_receipt_district": "",
    "invoice_receipt_address": "",
    "uniform_invoice_tax_name": "",
    "uniform_invoice_tax_id": "",
    "echo_0": "1",
    "echo_1": "2",
    "echo_2": "3",
    "echo_3": "4",
    "echo_4": "5"
  }
}

『回傳值』

參數名稱 型態 說明 必須
code string 回應代碼 『代碼表』值參考
msg string 代碼訊息
page_code string 頁面代碼
order_id string 商家請求單號
indice_data object 扣款名目資料 『扣款名目資料』欄位參考
member_data object 消費者扣款資料 『消費者扣款資料』欄位參考
delay_date array 延期設定 每筆『延扣紀錄』欄位參考

『代碼表』

型態 說明 備註
A0000 新增/修改成功
A0001 請求網址過期

『扣款名目資料』

參數名稱 型態 說明 必須
name string 專案名稱
regular string 扣款單位 『分期類型定義』值參考
notify_before string 扣款前通知方式 『扣款通知』值參考
notify_before_message string 扣款前通知內容
notify_after string 扣款後通知方式 『扣款通知』值參考
notify_after_message string 扣款後通知內容
retry_enable int 扣款失敗後,是否啟用重扣機制 『扣款失敗後,重扣是否啟用』值參考
fail_notify_delay string 扣款失敗,延遲幾日後重扣,單位:日
retry_time string 扣款失敗後,要重試幾次重扣

『消費者扣款資料』

參數名稱 型態 說明 必須
group_id string 扣款單號(不可重複,每當交易回報時,會帶入此單號,使之識別扣款為同一筆申請的定期定額) 必填
pay_mode_uid integer 付款方式 非必填
『卡片類型定義』值參考
name string 扣款人姓名 非必填
debtor_type integer 扣款人身份類型 非必填
『證號類型』值參考
debtor_id string 扣款人證號 非必填
phone_code string 扣款人手機國碼 非必填
phone string 扣款人手機
mail string 扣款人電子信箱
store_member_id string 網站會員ID
currency string 幣別(目前強制為TWD)
cost string 每期應扣金額 非必填
regular_first_charge_date string 起扣日期 非必填
regular_stop_charge_date string 扣款到期日 非必填
invoice_type integer 發票類型(預設0) 非必填
『單據類型』值參考
cloud_type int 雲端載具類型(預設0) 非必填
『雲端發票類型』值參考
invoice_mobile_code string 當cloud_type為2時紀錄的手機條碼
invoice_natural_person string 當cloud_type為3時紀錄的自然人憑證條碼
invoice_love_code string 當input_type為2時紀錄的愛心碼
tong_bian string 發票統編 非必填
donation_statistics_type int 捐款收據統計模式(預設0),當invoice_type為5時必填,且不能為0 依狀況必填
『捐款收據統計模式』值參考
donation_identity_type int 捐款收據收件對象當invoice_type為5時必填,且不能為0 依狀況必填
『捐款單位』值參考
donation_type_no string 捐款收據對象身分證或統編,當donation_identity_type為1時填身分證2填統編,當donation_identity_type為1時必填
donation_type_name string 捐款收據對象姓名或公司名稱,當donation_identity_type為1時填姓名2填公司名稱,當donation_identity_type為1時必填
invoice_receipt_zip_code string 捐款收據地址郵政區碼
invoice_receipt_city string 捐款收據地址縣市
invoice_receipt_district string 捐款收據地址鄉區
invoice_receipt_address string 捐款收據地址
uniform_invoice_tax_name string 免用統一發票買受人
uniform_invoice_tax_id string 免用統一發票買受人統編
echo_0 string 自訂回傳1 非必填
echo_1 string 自訂回傳2 非必填
echo_2 string 自訂回傳3 非必填
echo_3 string 自訂回傳4 非必填
echo_4 string 自訂回傳5 非必填

『延扣紀錄』

參數名稱 型態 說明 必須
delay_start_date string 延扣起始日
delay_end_date string 延扣結束日
delay_reason string 延扣原因

附錄三:回傳通知設定網址位置

系統設定->連線通知設定,通知網址的部分,僅限80跟443 port

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

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

附錄五:API模擬串接服務

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

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

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

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

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

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

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

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

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

高鉅模擬信用卡(3D)

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