Help us improve
Share bugs, ideas, or general feedback.
From payuni
Implements PAYUNi Query API for single/batch transaction queries, order status checks, and payment verification in Node.js/TypeScript apps.
npx claudepluginhub paid-tw/skills --plugin payuniHow this skill is triggered — by the user, by Claude, or both
Slash command
/payuni:payuni-queryThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
你的任務是在用戶的專案中實作統一金流交易查詢功能。
Implements 統一金流 (PAYUNi) webhook endpoints with CheckCode signature verification, replay attack prevention, and order status updates for Next.js, Express, or other backends.
Implements NewebPay QueryTradeInfo API for transaction status queries by order and amount. Generates SHA256 CheckValue; handles single queries, batch reconciliation, status confirmation.
Implements KryptoGO payment queries to check single payment intent status and list intents with filters. Use for order status checking, transaction verification, or payment confirmation in KryptoGO integrations.
Share bugs, ideas, or general feedback.
你的任務是在用戶的專案中實作統一金流交易查詢功能。
用戶輸入: $ARGUMENTS
詢問用戶:
查詢情境:需要什麼查詢功能?
專案框架:你使用什麼框架?
在現有的支付模組中加入查詢方法,或建立新模組。
核心功能:
generateQueryParams(orderNo) - 產生查詢參數queryTrade(orderNo) - 查詢單筆交易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',
};
function getQueryEndpoint(): string {
return config.isTest
? 'https://sandbox-api.payuni.com.tw/api/query'
: 'https://api.payuni.com.tw/api/query';
}
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;
}
function generateHashInfo(encryptInfo: string): string {
return crypto
.createHash('sha256')
.update(encryptInfo)
.digest('hex')
.toUpperCase();
}
async function queryTrade(orderNo: string): Promise<{
success: boolean;
data?: any;
error?: string;
}> {
try {
const queryData = {
MerID: config.merchantId,
MerTradeNo: orderNo,
};
const queryString = new URLSearchParams(queryData).toString();
const encryptInfo = encrypt(queryString);
const hashInfo = generateHashInfo(encryptInfo);
const response = await fetch(getQueryEndpoint(), {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
MerID: config.merchantId,
EncryptInfo: encryptInfo,
HashInfo: hashInfo,
}),
});
const result = await response.json();
return {
success: result.Status === 'SUCCESS',
data: result,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Query failed',
};
}
}
// 使用範例
const result = await queryTrade('ORDER-123');
if (result.success) {
console.log('交易狀態:', result.data.TradeStatus);
}
建議整合方式:
GET /api/orders/:orderNo/status| 環境 | URL |
|---|---|
| 測試 | https://sandbox-api.payuni.com.tw/api/query |
| 正式 | https://api.payuni.com.tw/api/query |
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| MerID | String | ✓ | 商店代號 |
| EncryptInfo | String | ✓ | 加密後的查詢參數 |
| HashInfo | String | ✓ | SHA256 雜湊值 |
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
| MerID | String | ✓ | 商店代號 |
| MerTradeNo | String | ✓ | 商店訂單編號 |
| 值 | 說明 |
|---|---|
| 0 | 未付款 |
| 1 | 已付款 |
| 2 | 付款失敗 |
| 3 | 已取消 |
| 6 | 已退款 |
| 代碼 | 說明 | 解決方式 |
|---|---|---|
| TRA10001 | 查無此筆交易 | 確認訂單編號正確 |
| TRA10002 | 驗證錯誤 | 確認加密參數正確 |
| TRA10003 | 商店代號錯誤 | 確認 MerchantID 正確 |