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 扣款失敗,延遲幾日後重扣,單位:日 專案名稱若已存在,則此蘭位於新增時無效,非必填
retry_time string 扣款失敗後,要重試幾次重扣 專案名稱若已存在,則此蘭位於新增時無效,非必填
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 扣款失敗,延遲幾日後重扣,單位:日
retry_time string 扣款失敗後,要重試幾次重扣
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 延扣原因

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

系統設定->連線通知設定

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

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

附錄五:API模擬串接服務

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