payuni-checkout
8
总安装量
8
周安装量
#33888
全站排名
安装命令
npx skills add https://github.com/paid-tw/skills --skill payuni-checkout
Agent 安装分布
codex
8
gemini-cli
8
cursor
8
opencode
8
amp
7
antigravity
7
Skill 文档
çµ±ä¸éæµ UPP æ¯ä»ä¸²æ¥ä»»å
ä½ ç任忝å¨ç¨æ¶çå°æ¡ä¸å¯¦ä½çµ±ä¸éæµ UPP å¹åæ¯ä»åè½ã
ä¸²æ¥ Checklist
宿以䏿¥é©å³å¯å®æä¸²æ¥ï¼
- ç°å¢ç¢ºèª – ç¢ºèªæ¡æ¶é¡åèæ¯ä»æ¹å¼éæ±
- ç°å¢è®æ¸ – è¨å® PAYUNI_MERCHANT_IDãHASH_KEYãHASH_IV
- æ¯ä»æ¨¡çµ – 建ç«å å¯è§£å¯èè¨å®å»ºç«åè½
- æ¯ä»è¡¨å® – 建ç«éåºè³çµ±ä¸éæµç HTML 表å®
- å調èç – å»ºç« NotifyURL è ReturnURL 端é»
- 測試é©è – ä½¿ç¨æ¸¬è©¦ç°å¢é©è
Step 1: 確èªå°æ¡ç°å¢
è©¢åç¨æ¶ï¼
-
æ¡æ¶é¡åï¼ä½ 使ç¨ä»éº¼æ¡æ¶ï¼
- PHP (Laravel / CodeIgniter / åç)
- Node.js (Express / Next.js / NestJS)
- Python (Django / Flask / FastAPI)
- å ¶ä»
-
æ¯ä»æ¹å¼ï¼éè¦æ¯æ´åªäºæ¯ä»æ¹å¼ï¼ï¼å¯è¤é¸ï¼
- ä¿¡ç¨å¡
- LINE Pay
- Apple Pay / Google Pay
- ATM è½å¸³
- è¶ å代碼/æ¢ç¢¼
ç¨æ¶è¼¸å
¥: $ARGUMENTS
Step 2: 檢æ¥ç°å¢è®æ¸
æå°å°æ¡ä¸ç .env æè¨å®æªï¼ç¢ºèªæ¯å¦å·²è¨å®ï¼
PAYUNI_MERCHANT_IDPAYUNI_HASH_KEYPAYUNI_HASH_IV
è¥æªè¨å®ï¼å¼å°ç¨æ¶è¨å®ç°å¢è®æ¸ã
Step 3: å»ºç«æ¯ä»æ¨¡çµ
æ ¹æç¨æ¶æ¡æ¶å»ºç«æ¯ä»æ¨¡çµæªæ¡ã
建ç«ä½ç½®å»ºè°:
- Laravel:
app/Services/PayuniService.php - Express:
services/payuni.jsæservices/payuni.ts - Next.js:
lib/payuni.ts - Django:
payments/services.py
æ ¸å¿åè½:
encrypt(data)– AES-256-CBC å å¯decrypt(data)– AES-256-CBC è§£å¯generateHashInfo(encryptInfo)– SHA256 éæ¹createOrder(orderData)– 建ç«è¨å®ä¸¦åå³è¡¨å®è³æverifyCallback(payload)– é©èå調éç¥
Node.js/TypeScript ç¯ä¾
import crypto from 'crypto';
const config = {
merchantId: process.env.PAYUNI_MERCHANT_ID!,
hashKey: process.env.PAYUNI_HASH_KEY!,
hashIV: process.env.PAYUNI_HASH_IV!,
isTest: process.env.PAYUNI_TEST_MODE === 'true',
};
// AES-256-CBC å å¯
function encrypt(data: string): string {
const key = Buffer.from(config.hashKey.padEnd(32, '\0').slice(0, 32), 'utf8');
const iv = Buffer.from(config.hashIV.padEnd(16, '\0').slice(0, 16), 'utf8');
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// SHA256 éæ¹
function generateHashInfo(encryptInfo: string): string {
return crypto
.createHash('sha256')
.update(encryptInfo)
.digest('hex')
.toUpperCase();
}
// 建ç«è¨å®
function createOrder(params: {
orderId: string;
amount: number;
productName: string;
returnUrl: string;
notifyUrl: string;
}) {
const tradeInfo = {
MerID: config.merchantId,
MerTradeNo: params.orderId,
TradeAmt: params.amount,
ProdDesc: params.productName,
ReturnURL: params.returnUrl,
NotifyURL: params.notifyUrl,
};
const queryString = new URLSearchParams(tradeInfo as any).toString();
const encryptInfo = encrypt(queryString);
const hashInfo = generateHashInfo(encryptInfo);
return {
MerID: config.merchantId,
EncryptInfo: encryptInfo,
HashInfo: hashInfo,
};
}
Step 4: å»ºç«æ¯ä»è¡¨å®é é¢
æ ¹ææ¡æ¶å»ºç«æ¯ä»è¡¨å®ï¼éå å«ï¼
<form method="post" action="https://sandbox-api.payuni.com.tw/api/upp">
<input type="hidden" name="MerID" value="{ååºä»£è}">
<input type="hidden" name="EncryptInfo" value="{å å¯è³æ}">
<input type="hidden" name="HashInfo" value="{SHA256éæ¹}">
<button type="submit">åå¾ä»æ¬¾</button>
</form>
注æï¼ æ£å¼ç°å¢è«æ¹çº https://api.payuni.com.tw/api/upp
Step 5: 建ç«å調èç
建ç«å ©å端é»ï¼
-
NotifyURL (èæ¯éç¥):
POST /api/webhooks/payuni- æ¥æ¶çµ±ä¸éæµèæ¯éç¥
- é©èç°½å (CheckCode)
- æ´æ°è¨å®çæ
- åæ
{ success: true }
-
ReturnURL (åå°è¿å):
GET /checkout/result- ç¨æ¶æ¯ä»å®æå¾å°å
- 顯示交æçµæ
ç°½åé©èé輯
function verifyCheckCode(params: Record<string, string>): boolean {
const { CheckCode, ...otherParams } = params;
const sortedKeys = Object.keys(otherParams).sort();
const paramStr = sortedKeys.map(k => `${k}=${otherParams[k]}`).join('&');
const signStr = `HashKey=${config.hashKey}&${paramStr}&HashIV=${config.hashIV}`;
const calculated = crypto
.createHash('sha256')
.update(signStr)
.digest('hex')
.toUpperCase();
return calculated === CheckCode;
}
Step 6: 測試é©è
å¼å°ç¨æ¶é²è¡æ¸¬è©¦ï¼
- ä½¿ç¨æ¸¬è©¦ç°å¢
https://sandbox-api.payuni.com.tw - é©èå å¯è§£å¯æ£ç¢ºæ§
- 確èªåèª¿å¯æ£å¸¸æ¥æ¶
- 測試ä¸åæ¯ä»æ¹å¼
API åè
端é»
| ç°å¢ | URL |
|---|---|
| 測試 | https://sandbox-api.payuni.com.tw/api/upp |
| æ£å¼ | https://api.payuni.com.tw/api/upp |
TradeInfo å¿ è¦åæ¸
| 忏 | é¡å | 說æ |
|---|---|---|
| MerID | String | ååºä»£è |
| MerTradeNo | String(30) | è¨å®ç·¨èï¼ä¸å¯éè¤ï¼ |
| TradeAmt | Number | éé¡ |
| ProdDesc | String | ååæè¿° |
| ReturnURL | String | åå°è¿åç¶²å |
| NotifyURL | String | èæ¯éç¥ç¶²å |
æ¯ä»æ¹å¼åæ¸
| 忏 | å¼ | 說æ |
|---|---|---|
| CREDIT | 1 | ä¿¡ç¨å¡ |
| LINEPAY | 1 | LINE Pay |
| APPLEPAY | 1 | Apple Pay |
| GOOGLEPAY | 1 | Google Pay |
| VACC | 1 | ATM è½å¸³ |
| CVS | 1 | è¶ å代碼 |
| BARCODE | 1 | è¶ åæ¢ç¢¼ |