概述
環境 Domain
以下為串接時可使用的環境 Domain:
- 正式環境:https://api.payments.91app.com
- 開發者環境:https://api.developer.payments.91app.com
串接時必要資訊
API 串接資訊 | 說明 | 取得/提供方式 |
|---|---|---|
| N1-API-KEY | 呼叫方的驗證授權,請置於 API 呼叫時的 header 中 | 與 91APP Payments 完成申請後提供。(於申請完成結果回覆檔的 Api Key) |
| sharedSecret | 計算 N1-DATA-SIGNATURE 需要的 secret | 與 91APP Payments 完成申請後提供。(於申請完成結果回覆檔的 IV Key) |
| N1-DATA-SIGNATURE | API Payload 資料完整性驗證,請置於 API 呼叫時的 header 中 | 透過 API Path 與 Payload 計算 HMAC-SHA256,可參考下面範例 |
| 91APP Payments IP | 91APP Payments 有提供交易結果通知,若商店有針對 IP 進行管控,請將 91APP Payments 的對應 IP 加入白名單 | 與 91APP Payments 完成申請後提供給商店 |
| 商店 IP | 91APP Payments 除 API Key 的存取控管外,亦會針對 IP 作管控,請於申請時提供貴商店發送 API 的固定 IP 以利加入白名單 | 申請時提供給 91APP Payments |
N1-DATA-SIGNATURE 計算範例
- C#
- PHP
void Main()
{
var sharedSecret = "sampleSecret";
// 1. HTTP POST Method 的簽章範例
var requestBody = new { Sample = "sample" };
var jsonString = JsonConvert.SerializeObject(requestBody);
Console.WriteLine(jsonString);
// {"Sample":"sample"}
var hmacContentForPost = SignHMAC(jsonString, sharedSecret).ToLower();
var signatureForPost = Convert.ToBase64String(Encoding.UTF8.GetBytes(hmacContentForPost));
Console.WriteLine(signatureForPost);
// ZjY0ZDViYTljMTQ1NWY0ODU5MDAwZjIwZDliNDBjYTAxNjNjNWFiMmQwNzBkM2NjODgyYjY3N2MzNjM4YWY3Yg==
// 2. HTTP GET Method 的簽章範例
var scheme = "https";
var host = "api.developer.payments.91app.com";
var path = "/v2/trades/sample";
var uriBuilder = new UriBuilder(scheme, host);
uriBuilder.Path = path;
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("q", "test");
uriBuilder.Query = query.ToString();
// 注意:需要移除 path 與 query string 間的問號
var inputData = uriBuilder.Uri.PathAndQuery.Replace("?", string.Empty);
Console.WriteLine(inputData);
// /v2/trades/sampleq=test
var hmacContentForGet = SignHMAC(inputData, sharedSecret).ToLower();
var signatureForGet = Convert.ToBase64String(Encoding.UTF8.GetBytes(hmacContentForGet));
Console.WriteLine(signatureForGet);
// OTcxOWIyZTZmZGZlYjkyZjA4M2U1ZTc4MmQxMDg4NjQzMTk3Zjg0NmYwOWJjMDkzYzZlMWM1MTBkNTU2ZDQ2OA==
}
public string SignHMAC(string inputData, string sharedSecret)
{
var encoding = new UTF8Encoding();
var keyByte = encoding.GetBytes(sharedSecret);
var messageBytes = encoding.GetBytes(inputData);
using (var hmacSHA256 = new HMACSHA256(keyByte))
{
var hashMessage = hmacSHA256.ComputeHash(messageBytes);
return BitConverter.ToString(hashMessage).Replace("-", string.Empty);
}
}
<?php
// 串接端請確保在組合 API request payload 並提供給 API client(e.g. curl) 時,有與簽章的 json_encode 是一致的處理方式
$sharedSecret = "sampleSecret";
// 1. HTTP POST Method 的簽章範例
$requestBody = ["Sample" => "sample"];
$jsonString = json_encode($requestBody);
$signature = signHMAC($jsonString, $sharedSecret);
echo $signature . "\n";
// ZjY0ZDViYTljMTQ1NWY0ODU5MDAwZjIwZDliNDBjYTAxNjNjNWFiMmQwNzBkM2NjODgyYjY3N2MzNjM4YWY3Yg==
// 2. HTTP GET Method 的簽章範例
$scheme = "https";
$host = "api.developer.payments.91app.com";
$path = "/v2/trades/sample";
$uri = $scheme . "://" . $host . $path;
$query = http_build_query(['q' => 'test']);
$uri .= '?' . $query;
// 如果��� query string,要移除 path 與 query string 間的問號
$inputData = str_replace('?', '', parse_url($uri, PHP_URL_PATH) . '?' . parse_url($uri, PHP_URL_QUERY));
echo $inputData . "\n";
// /v2/trades/sampleq=test
$signatureForGet = signHMAC($inputData, $sharedSecret);
echo $signatureForGet . "\n";
// OTcxOWIyZTZmZGZlYjkyZjA4M2U1ZTc4MmQxMDg4NjQzMTk3Zjg0NmYwOWJjMDkzYzZlMWM1MTBkNTU2ZDQ2OA==
// 計算 HMAC 簽名
function signHMAC(string $data, string $sharedSecret): string
{
$hmacString = hash_hmac('sha256', $data, $sharedSecret, false);
$convertToUtf8Context = mb_convert_encoding(strtolower($hmacString), 'UTF-8', 'ISO-8859-1');
return base64_encode($convertToUtf8Context);
}
?>
各 API 摘要說明
| 類型 | API 名稱 | API Path | 說明 | 狀態 |
|---|---|---|---|---|
| 交易請求 | 透過txnToken進行交易 | /v2/payments/request-by-txnToken | 消費者於 SDK 中輸入信用卡資訊後,SDK 會回覆 txnToken,可使用該組 txnToken 搭配此 API 送出交易請求 | 可供串接 |
| 交易請求 | 透過cardToken進行交易 | /v2/payments/request-by-cardToken | 若前次交易選擇記住卡號,則 91APP Payments 會回傳 cardToken,付款成功後,後續商店可用該 cardToken 請求交易 | 可供串接 |
| 交易請求 | 付款頁連結建立 | /v2/pay-pages/url | 建立一個 91APP Payments 的付款頁讓消費者進行付款 | 可供串接 |
| 交易請求 | 付款頁連結取消 | /v2/pay-pages/cancel | 將已產生的付款頁連結作廢 | 可供串接 |
| 查詢 | 交易查詢 | /v2/trades/{tradeId} | 用以查詢指定交易當前狀態 | 可供串接 |
| 查詢 | 交易歷程查詢 | /v2/trades/{tradeId}/record | 用以查詢指定交易的狀態歷程 | 可供串接 |
| 請退款 | 請款申請 | /v2/trades/{tradeId}/capture | 針對指定交易執行請款請求 | 可供串接 |
| 請退款 | 請款取消 | /v2/trades/{tradeId}/capcancel | 針對指定交易執行請款取消 | 可供串接 |
| 請退款 | 授權取消/退款申請 | /v2/trades/{tradeId}/refund | 針對指定交易執行退款申請 | 可供串接 |
| 交易取消 | 交易取消 | /v2/trades/{tradeId}/cancel | 針對指定交易執行交易取消,目前僅支援超商代碼交易可以操作 | 可供串接 |
| 活動 | 信用卡活動 BIN 碼驗證 | /v2/promotion-bin-code/verify-bin-code | 驗證是否有符合特定支付方式的對應活動 | Preview 版本, 尚未提供串接 |
| 帳務 | 平台出帳 | /v2/ledgers/transfers | 推廣商向合作商店發動出帳作業 | 可供串接 |
| 帳務 | 平台扣帳 | /v2/ledgers/charges | 推廣商向合作商店發動扣款作業 | 可供串接 |
| 帳務 | 帳務交易查詢 | /v2/ledgers/requests/{transferCode} | 推廣商可查詢帳務請求交易當前狀態 | 可供串接 |
| 帳務 | 帳務交易取消 | /v2/ledgers/transfers/{transferCode}/cancel | 推廣商可取消已請求的帳務交易 | 可供串接 |
| 帳務 | 虛擬帳戶餘額查詢 | /v2/ledgers/{storeCode}/virtual-account | 推廣商可查詢指定商店的虛擬帳戶餘額資訊 | 可供串接 |
使用情境/流程
輸入信用卡號交易
記住卡號交易
儲值金串接
支付後儲值
交易請求需帶入商品類型(ProductType)為儲值商品(StoredValue),
支付成功後會回傳 儲值驗證Token (StoredValueToken),商店端可使用該 儲值驗證Token 進行儲值金的儲值操作。
正常情況下,儲值金的儲值操作不會失敗,但若儲值失敗,商店端可透過客服退款的方式處理。
目前僅支援以下付款方式:
- CreditCard (信用卡)
- ApplePay (Apple Pay)
- ATM (ATM轉帳)
不需轉導至外部交易頁
情境:
- 信用卡一般授權
- ApplePay
需轉導至外部(3D)交易頁或等待消費者操作
情境:
- 信用卡 3D 交易驗證
- ATM 轉帳
儲值金付款
在一些情況下,消費者剩餘的儲值金不足以支付當前交易金額,或是消費者希望使用儲值金支付部分金額,剩餘金額則使用其他支付方式支付。 在這種情況下,當其中一種支付方式失敗時,商店端應該要能夠處理這種情況。
- 使用順序建議為:儲值金 > 其他支付方式。
- 當其它支付方式失敗時,商店端應該要能夠取消儲值金的交易請求 ,以避免消費者的儲值金被扣除。
- 正常交易退款請使用 退款 API 。
下圖示範了如何同時使用儲值金付款與其它支付方式付款(以信用卡為例),並處理支付失敗的情況。
大哥付你分期
大哥付你分期部分交易可能進入審核流程(詳見 大哥付你分期官網),此時交易狀態將為付款處理中(recordStatus=8)。
商店須等待最終審核通知,收到付款處理中時不可完成交易,待 91APP Payments 發送最終結果通知後方可處理。
注意事項:
- 最終交易結果通知與第一次交易結果通知格式相同,以
recordStatus判斷最終結果。
交易測試資訊
開發者平台環境測試串接使用的工具,可供整合流程使用。
信用卡
- 信用卡: 以下測試卡號對應的有效年月請輸入 2034 年 12 月(即 12/34);CVV 驗證碼規則為:AMEX 使用任意四碼,其他信用卡使用任意三碼。
- 國外卡不可分期
卡號 | 發卡組織 | 發卡行 | 交易結果 | 說明 |
|---|---|---|---|---|
| 4503 0749 6961 8452 | VISA | 滙豐(台灣)商業銀行 | 交易成功 | |
| 4929 2535 4090 4963 | VISA | 國外卡 | 交易成功 | |
| 4485 4762 2372 8773 | VISA | 國外卡 | 交易成功 | |
| 3575 7745 7043 0792 | JCB | 國外卡 | 交易成功 | |
| 3541 5447 6092 6458 | JCB | 國外卡 | 交易成功 | |
| 5370 4983 9636 5683 | MasterCard | 國外卡 | 交易成功 | |
| 5407 6548 2107 5373 | MasterCard | 國外卡 | 交易成功 | |
| 5222 2512 5671 0161 | MasterCard | 玉山商業銀行 | 交易成功 | |
| 4058 6514 2155 8456 | VISA | 永豐商業銀行 | 交易成功 | |
| 3782 821430 84307 | AMEX | 美國運通 | 交易成功 | |
| 5408 2950 9969 1159 | MasterCard | 中國信託商業銀行 | 交易失敗 | 分期交易會失敗,用以提供測試分期交易失敗場景 |
| 5452 7908 7359 8567 | MasterCard | 星展(台灣)商業銀行 | 交易失敗 | 銀行端回覆未知錯誤,statusCode = NeedContactBank |
| 5122 1143 3831 2656 | MasterCard | 玉山商業銀行 | 交易失敗 | 銀行端回覆未知錯誤,statusCode = NeedContactBank |
| 4720 8940 9183 3605 | VISA | 王道商業銀行 | 交易失敗 | 銀行端拒絕交易,statusCode = RefuseTrade |
| 4800 8957 3345 1295 | VISA | 玉山商業銀行 | 3D 交易失敗 | 一般交易會成功,3D 交易會失敗,statusCode = Failured3DS |
| 5442 2801 8461 3035 | MasterCard | 台新國際商業銀行 | 交易失敗 | 卡片過期,statusCode = cardExpired |
| 5415 1006 6650 5678 | MasterCard | 國泰世華商業銀行 | 交易失敗 | 銀行沒收卡片,statusCode = CardConfiscated |
| 3782 829014 30858 | AMEX | 美國運通 | 交易失敗 | 銀行端拒絕交易,statusCode = RefuseTrade |
| 3782 824890 46878 | AMEX | 美國運通 | 交易失敗 | 3D 驗證失敗,statusCode = Failured3DS |
| 不在名單的卡號 | - | - | 交易失敗 | 卡號錯誤,statusCode = CardNumberWrong |
Apple Pay
在開發環境中測試 Apple Pay 串接時,可以以你的真實 Apple Pay 中的信用卡來做測試,並取得 txnToken,使用真實信用卡測試的交易將會回應固定的信用卡資訊及 txnToken,開發者環境的 Apple Pay 不會扣款,請安心使用。如需測試各種交易場景,可使用以下 txnToken 來模擬不同的交易結果,確保 Apple Pay 功能在不同情況下都能正確運作。
TxnToken | FirstSix | LastFour | 發卡組織 | 發卡行名稱 | 交易結果 | 說明 |
|---|---|---|---|---|---|---|
| b75c365fce2f4288acad5 5f16f964f6b246b23d4 | 450307 | 8452 | VISA | 滙豐(台灣)商業銀行 | Success | |
| cc836fb4004a437098fc0 9c5261459c6a05e5b91 | 522225 | 0161 | MasterCard | 玉山商業銀行 | Success | |
| 5ed4576dbead42e59407c 636c7db66e20085e106 | 357577 | 0792 | JCB | 國外卡 | Success | |
| d6104d554f8f418ba9b3e 8e05ce76366a8550d2b | 545279 | 8567 | MasterCard | 星展(台灣)商業銀行 | NeedContactBank | 銀行錯誤,請持卡人請與發卡銀行聯絡 (Call Bank) |
| 9f9503007d4246b3b823c c646d63b715a620e846 | 472089 | 3605 | VISA | 王道商業銀行 | RefuseTrade | 銀行拒絕交易 (Decline) |
| 9768d625b5924d15b5b38 68d14069225f44098fa | 544228 | 3035 | MasterCard | 台新國際商業銀行 | CardExpired | 卡片過期 (Expire card) |
| e6e5bfe9b973481da22cd c5c97a5aabc2f52258a | 541510 | 5678 | MasterCard | 國泰世華商業銀行 | CardConfiscated | 銀行沒收卡片 (Pickup) |
Google Pay
在開發環境中測試 Google Pay 串接時,可以以你的真實 Google Pay 中的信用卡來做測試,並取得 txnToken,使用真實信用卡測試的交易將會回應固定的信用卡資訊及 txnToken,開發者環境的 Google Pay 不會扣款,請安心使用。如需測試各種交易場景,可使用以下 txnToken 來模擬不同的交易結果,確保 Google Pay 功能在不同情況下都能正確運作。
TxnToken | FirstSix | LastFour | 發卡組織 | 發卡行名稱 | 交易結果 | 說明 |
|---|---|---|---|---|---|---|
| g6ft6et28n940tp945vbb 41p41qb1s8x18pj3jdv | 450307 | 8452 | VISA | 滙豐(台灣)商業銀行 | Success | |
| 5x50q2w3fqw4g7r3whstj 143i62secc7phy9ny14 | 522225 | 0161 | MasterCard | 玉山商業銀行 | Success | |
| 558r810833w33dgavbcis r2m1cc765aizgfv2ako | 357577 | 0792 | JCB | 國外卡 | Success | |
| yg731804yvwgs3ucy8avq v8s6xdxb0dh6x3oxnk7 | 545279 | 8567 | MasterCard | 星展(台灣)商業銀行 | NeedContactBank | 銀行錯誤,請持卡人請與發卡銀行聯絡 (Call Bank) |
| au2on8ti4b3y52tw35a86 m7t2p41wd97o527qt21 | 472089 | 3605 | VISA | 王道商業銀行 | RefuseTrade | 銀行拒絕交易 (Decline) |
| j08jjfd6dh3ezyo4yibfz m148409dyc170829xg0 | 544228 | 3035 | MasterCard | 台新國際商業銀行 | CardExpired | 卡片過期 (Expire card) |
| k1q59b50n9f12zf20yj7e 0mt5512s0ppa596d978 | 541510 | 5678 | MasterCard | 國泰世華商業銀行 | CardConfiscated | 銀行沒收卡片 (Pickup) |
大哥付你分期
在開發環境中測試大哥付你分期串接時,請使用以下測試帳號模擬消費者登入大哥付付款頁面進行分期付款。
手機號碼 | 驗證簡訊碼 | 測試情境 |
|---|---|---|
| 0935154782 | 0000 | 交易成功 |
| 0935290666 | 0000 | 結帳金額 > 50,000 元時進入專審,轉專後維持付款處理中 |
| 0935005687 | 0000 | 進入專人審核中,3~5分鐘後(專審拒絕)轉付款失敗 |
| 0935005778 | 0000 | 進入專人審核中,3~5分鐘後(專審通過)轉付款成功 |
推廣商帳務測試資訊
帳務執行日
於 平台出帳 及 平台扣款 API 中欄位設定,可預約帳務交易在 N 天後執行,設定 0 的話則是當日執行
- 當日執行:系統於每小時批次執行
- 預約執行:因測試與正式環境有所差異,請參考下方各環境說明
- 正式環境:將在預約當日上午執行
- 若在 4 / 21 發動
平台出帳或平台扣款請求且帳務執行日為 3 天,系統將在 4 / 24 上午執行 - 帳務交易執行結果在上午 11 點後可供查詢
- 若在 4 / 21 發動
- 測試環境:於預約當日零時執行
- 正式環境:將在預約當日上午執行
帳務交易測試情境
測試環境中的帳務交易結果均會成功處理,不會有失敗的帳務交易
成功/失敗情境
- 成功情境: 交易金額必須設定為 ≦ 5,000
- 失敗情境: 交易金額設定為 > 5,000 時,可以取得請求失敗的案例
儲值金測試資訊
儲值金提領
商店端可使用儲值金提領申請 API 進行儲值金的提領操作。
在開發者平台環境測試中,儲值金提領的狀態會停留在 提領申請 的狀態。商店可以透過儲值金提領更新API 將該提領申請取消,除此之外,開發環境中不會有其他狀態的變化。
名詞說明
| 名詞 | 說明 |
|---|---|
| txnToken | 消費者於前端 SDK 中輸入信用卡卡號與相關資料後,SDK 會提供對應的 txnToken,用以作為短時間內(90 秒)當次交易使用,並且可讓商店端不須碰觸到消費者信用卡號等機敏性資料 |
| cardToken | "交易請求:透過txnToken進行交易" API 提供記住卡號功能,該 API 會回傳 cardToken 參數,當該次交易為授權成功的狀況下,商店端即可記住該對應的 cardToken 供該消費者後續交易使用,使消費者於下次交易請求時不用再次輸入完整卡號(RememberCard 支援 AMEX;BindingCard 不支援 AMEX) |
| txnLastToken | 當想使用記住卡號的交易請求時,消費者只需要輸入 CVV 信用卡驗證碼,前端 SDK 會換得 txnLastToken,商店端即可使用該 txnLastToken 與 cardToken 共同完成 /v2/payments/request-by-cardToken 的交易請求;使用 AMEX 卡別時為必填 |
列舉定義
交易狀態/recordStatus
| 值 | 說明 |
|---|---|
| 1 | 待付款 |
| 2 | 付款失敗 |
| 3 | 付款取消 |
| 4 | 付款成功 |
| 5 | 請款成功 |
| 6 | 部分退款成功 |
| 7 | 全部退款成功 |
| 8 | 付款處理中 |
請款狀態/captureStatus
| 值 | 說明 |
|---|---|
| 0 | 尚未請款 |
| 1 | 請款已請求 |
| 2 | 請款處理中 |
| 3 | 請款成功 |
商品類型/productType
| 值 | 說明 |
|---|---|
| Normal | 一般商品 |
| Subscription | 定期購交易 |
| Advance | 遞延性交易 |
| StoredValue | 儲值商品 |
支付方式/payType
| 值 | 說明 |
|---|---|
| CreditCard | 信用卡 |
| ATM | ATM轉帳 |
| CVS | 超商代碼 |
| ApplePay | Apple Pay |
| GooglePay | Google Pay |
| StoredValue | 儲值金 |
| LinePay | LINE Pay |
| OPPayLater | 大哥付你分期 |
| OnlineBanking | 網路銀行 |
| TouchnGo | Touch'n Go |
| GrabPay | Grab Pay |
| CIMB | CIMB |
| LinkAja | LinkAja |
| ShopeePay | Shopee Pay |
| Dragonpay | Dragonpay |
| PayMaya | PayMaya |
| PayNow | PayNow |
| PromtPay | Promt Pay |
幣別/currency
馬來西亞令吉 (MYR)、新加坡元 (SGD)、泰銖 (THB)、越南盾 (VND)、菲律賓披索 (PHP)、印尼盾 (IDR)交易時,僅支援 RMS 的交易。
| 幣別 | 交易金額限制 | 舉例 |
|---|---|---|
| 新台幣 (TWD) | >NT$1 | 如需發起 NT$1 的交易時,請帶入1 |
| 馬來西亞令吉 (MYR) | >RM0.01 | 如需發起 RM0.01 的交易時,請帶入1 |
| 新加坡元 (SGD) | >S$1.00 | 如需發起 S$1.00 的交易時,請帶入100 |
| 泰銖 (THB) | >฿1.00 | 如需發起 ฿1.00 的交易時,請帶入100 |
| 菲律賓披索 (PHP) | >₱50.00 | 如需發起 ₱1.00 的交易時,請帶入100 |
| 印尼盾 (IDR) | >Rp100.00 | 如需發起 Rp100.00 的交易時,請帶入10000 |
N1-IDEMPOTENCY-KEY說明
非必填,若未填表示不使用 Idempotency 機制
Idempotency 機制
目的:避免 API 傳輸過程因網路延遲或其他因素,造成應用程式例外或資料不一致...等意料之外的錯誤
相同的 Idempotent Key及 Request 資訊,一小時內執行第二次以上會得到同樣的結果
Idempotency 錯誤處理
當使用相同的 Idempotent Key,但是 Request 資訊與上次不一致,會拋出錯誤
HTTP 400 BadRequest:{ "errorCode" : "IdempotentError" , "message" : "請求不一致" }
當同時間有相同的 Idempotent Key 及 Request 資訊,但第一個 Request 尚未完成,第二個 Request 會拋出錯誤
HTTP 409 Conflict:{ "errorCode" : "IdempotentConflict" , "message" : "請求衝突,請稍後再試" }
這時候可以進行 Retry,直到第一個 Request 完成,第二個 Request 就會取得同樣的結果