[C#] 實現 TabPay 金流平台的快速信用卡支付整合(保留卡片) - Pay By Card Token
2024-09-04
接續上一篇文章,這也是為何主要最後選 TabPay 的原因,因為他可以保存住客戶的信用卡授權
然後再次進行刷卡,但是得先取得授權並且保存著,這時候要使用的就是 Pay by Card Token
1. 你得先參考 之前這篇文章 實現 TabPay 金流平台的快速信用卡支付整合 - Get Prime 中間的步驟,拿到
Partner Key 跟 APP Key ,還有裡面取的 Prime 的方式,那一段是一樣的
sandbox 測試卡號 4242424242424242 時間 04/29 , CSV: 123
HTML + Javascript Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://js.tappaysdk.com/tpdirect/v5.1.0"></script> | |
<script>TPDirect.setupSDK('153376', 'appkey_blog_step2', 'sandbox')</script> | |
<form method="post" id="formMain" enctype="multipart/form-data" onsubmit="Splash1()"> | |
<div> | |
<label>請輸入卡號</label> | |
<p> | |
<div id="cardview-container"></div> | |
</p> | |
<p> | |
<button type="button" onclick="onClick()">Get Prime By Javascript</button> | |
</p> | |
<p> | |
<textarea asp-for="Prime" name="Prime" id="Prime" style="width:100%"> | |
</textarea> | |
</p> | |
<p> | |
<button id="btnSubmit" asp-page-handler="Save" style="width: 200px;" class="btn btn-success pull-right"><i class="fa fa-save" aria-hidden="true"></i> Pay by Prime</button> | |
</p> | |
</div> | |
<div style="color:red" id="divResult"> | |
@Model.Result | |
</div> | |
</form> | |
<script> | |
function onClick() { | |
toastr.success($('#cc-number').val()); | |
TPDirect.card.getPrime(function (result) { | |
console.log(result); | |
//取得結果顯示出來 | |
$('#Prime').val(JSON.stringify(result)); | |
$('#divResult').html(JSON.stringify(result)); | |
}) | |
} | |
var defaultCardViewStyle = { | |
color: 'rgb(0,0,0)', | |
fontSize: '24px', | |
lineHeight: '50px', | |
fontWeight: '300', | |
errorColor: 'red', | |
placeholderColor: '' | |
}; | |
TPDirect.card.setup('#cardview-container', defaultCardViewStyle, { | |
isUsedCcv: true | |
}) | |
TPDirect.card.onUpdate(function (update) { | |
if (update.canGetPrime) { | |
console.log('success log'); | |
} else { | |
} | |
if (update.hasError) { | |
cardViewContainer.classList.add('error') | |
} else { | |
cardViewContainer.classList.remove('error') | |
} | |
if (update.status.number) { | |
showErrorMessage('Please check your credit card number') | |
} else { | |
hideErrorMessage() | |
} | |
}) | |
/* Prime Result | |
{ | |
"status": 0, | |
"msg": "Success", | |
"card": { | |
"prime": "407475a665e5a772f7ea2b27c592292ba6f3137d6cc4b1cde49f6b8017acd66d", | |
"issuer": "", | |
"lastfour": "4242", | |
"bincode": "424242", | |
"funding": 0, | |
"type": 1, | |
"level": "", | |
"country": "UNITED KINGDOM", | |
"countrycode": "GB" | |
}, | |
"clientip": "211.23.139.189", | |
"card_identifier": "3bbfcb157e5f44ee8856074baf712ae4" | |
} | |
*/ | |
</script> | |
2. 將 Prime 送回去做首次交易的時候,必須要把一個參數 remember 設成 true ,進行第一次交易
這時候它們回應的 JSON 就會有詳細的 card_secret
C# Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public IActionResult OnPostSave() | |
{ | |
using (var client = new HttpClient()) | |
{ | |
var primeInfo = JsonConvert.DeserializeObject<CardInfo>(Prime); | |
var url = "https://sandbox.tappaysdk.com/tpc/payment/pay-by-prime"; | |
client.DefaultRequestHeaders.Add("x-api-key", "partner_key"); | |
client.DefaultRequestHeaders.Accept | |
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header | |
var requestBody = new | |
{ | |
partner_key = "partner_key", | |
prime = primeInfo.card.prime, | |
amount = "99", | |
merchant_id = "userid_CTBC", | |
details = "Some item", | |
//這參數要射成 true 才會拿到 card_secret | |
remember=true, | |
cardholder = new | |
{ | |
phone_number = "+886923456789", | |
name = "王小明", | |
email = "LittleMing@Wang.com", | |
zip_code = "100", | |
address = "台北市天龍區芝麻街1號1樓", | |
national_id = "A123456789" | |
} | |
}; | |
var json = Newtonsoft.Json.JsonConvert.SerializeObject(requestBody); | |
var content = new StringContent(json, Encoding.UTF8, "application/json"); | |
var response = client.PostAsync(url, content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
Result = responseString; | |
Console.WriteLine(responseString); | |
} | |
return Page(); | |
} | |
/* Result with card_secret | |
{ | |
"status": 0, | |
"msg": "Success", | |
"amount": 99, | |
"acquirer": "TW_CTBC", | |
"currency": "TWD", | |
"card_secret": { | |
"card_token": "6140ed9f274bbff606655a4bdb4e7d87c8c2a27d59fbb8ef4fbb8d0d7d647de0", | |
"card_key": "db9d633cf5a7d602b695cbcca509244b1d833b4752d9960580c191a6d76454a2" | |
}, | |
"rec_trade_id": "D20240904GcZQ1f", | |
"bank_transaction_id": "TP20240904GcZQ1f", | |
"order_number": "", | |
"auth_code": "829428", | |
"card_info": { | |
"issuer": "", | |
"funding": 0, | |
"type": 1, | |
"level": "", | |
"country": "UNITED KINGDOM", | |
"last_four": "4242", | |
"bin_code": "424242", | |
"issuer_zh_tw": "", | |
"bank_id": "", | |
"country_code": "GB", | |
"expiry_date": "202902" | |
}, | |
"transaction_time_millis": 1725421174282, | |
"bank_transaction_time": { | |
"start_time_millis": "1725421174325", | |
"end_time_millis": "1725421174325" | |
}, | |
"bank_result_code": "", | |
"bank_result_msg": "", | |
"card_identifier": "3bbfcb157e5f44ee8856074baf712ae4", | |
"merchant_id": "no2somdej_CTBC", | |
"is_rba_verified": false, | |
"transaction_method_details": { | |
"transaction_method_reference": "REQUEST", | |
"transaction_method": "FRICTIONLESS" | |
} | |
} | |
*/ | |
3. 之後就可以透過 card_secret 做之後的消費扣款,不需要客戶再輸入一次卡號
C# Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using (var client = new HttpClient()) | |
{ | |
var url = "https://sandbox.tappaysdk.com/tpc/payment/pay-by-token"; | |
client.DefaultRequestHeaders.Add("x-api-key", "partner_key"); | |
client.DefaultRequestHeaders | |
.Accept | |
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header | |
var requestBody = new | |
{ | |
//from card_secret | |
card_key= "64575fa115981d67d4eec89df8407e9b024d097a703f9f159aad271387bc8e13", | |
card_token= "1bd3eefb8d0def18f946623787a19d2ec9c54d527469c64f9f24f05d29ec4ba4", | |
partner_key = "partner_besc5SvEihVTIGv8UzLRxa53yfmfJ73YnLgQyPUIHOFbrMXMASglg4d6", | |
amount = "96", | |
currency="TWD", | |
merchant_id = "_CTBC", | |
details = "測試商品_"+DateTime.Now.ToString("yyyy-MM-dd HHMMss"), | |
remember = true, | |
cardholder = new | |
{ | |
phone_number = "+886923456789", | |
name = "許當麻", | |
email = "no2somdej@gmail.com", | |
zip_code = "231", | |
address = "台北市天龍區芝麻街1號1樓", | |
national_id = "A123456789" | |
} | |
}; | |
var json = Newtonsoft.Json.JsonConvert.SerializeObject(requestBody); | |
var content = new StringContent(json, Encoding.UTF8, "application/json"); | |
var response = client.PostAsync(url, content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
Result = responseString; | |
Console.WriteLine(responseString); | |
} | |
/* Result | |
{ | |
"status": 0, | |
"msg": "Success", | |
"amount": 96, | |
"acquirer": "TW_CTBC", | |
"currency": "TWD", | |
"rec_trade_id": "D20240904ojlXMT", | |
"bank_transaction_id": "TP20240904ojlXMT", | |
"order_number": "", | |
"auth_code": "732341", | |
"card_info": { | |
"issuer": "", | |
"funding": 0, | |
"type": 1, | |
"level": "", | |
"country": "UNITED KINGDOM", | |
"last_four": "4242", | |
"bin_code": "424242", | |
"issuer_zh_tw": "", | |
"bank_id": "", | |
"country_code": "GB", | |
"expiry_date": "202704" | |
}, | |
"transaction_time_millis": 1725426202354, | |
"bank_transaction_time": { | |
"start_time_millis": "1725426202410", | |
"end_time_millis": "1725426202410" | |
}, | |
"bank_result_code": "", | |
"bank_result_msg": "", | |
"card_identifier": "3bbfcb157e5f44ee8856074baf712ae4", | |
"merchant_id": "no2somdej_CTBC", | |
"is_rba_verified": false, | |
"transaction_method_details": { | |
"transaction_method_reference": "REQUEST", | |
"transaction_method": "FRICTIONLESS" | |
} | |
} | |
*/ | |
Result:
reference:
https://docs.tappaysdk.com/tutorial/zh/back.html#pay-by-card-token-api
https://blog.no2don.com/2024/09/c-sharp-tabpay-get-prime-ctbc.html