@payware/mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +92 -0
- package/MCP-SETUP.md +190 -0
- package/README.md +483 -0
- package/check-keys.js +52 -0
- package/keys/README.md +112 -0
- package/mcp-config.json +9 -0
- package/package.json +66 -0
- package/payware-mcp-config.json +12 -0
- package/src/auth/rsa-keys.js +82 -0
- package/src/auth/sandbox-setup.js +187 -0
- package/src/config/env.js +229 -0
- package/src/config/partner-types.js +143 -0
- package/src/core/auth/jwt-factory.js +182 -0
- package/src/core/auth/jwt-token.js +735 -0
- package/src/core/utils/json-serializer.js +100 -0
- package/src/core/utils/key-utils.js +133 -0
- package/src/index.js +237 -0
- package/src/isv/data/index.js +291 -0
- package/src/isv/deep-links/delete-product-link.js +154 -0
- package/src/isv/deep-links/delete-transaction-link.js +154 -0
- package/src/isv/deep-links/get-product-link.js +167 -0
- package/src/isv/deep-links/get-transaction-link.js +167 -0
- package/src/isv/deep-links/index.js +23 -0
- package/src/isv/index.js +103 -0
- package/src/isv/oauth2/create-token-simple.js +46 -0
- package/src/isv/oauth2/get-token-info.js +157 -0
- package/src/isv/oauth2/obtain-token.js +189 -0
- package/src/isv/oauth2/token-helper.js +151 -0
- package/src/isv/products/audios.js +470 -0
- package/src/isv/products/create-product.js +314 -0
- package/src/isv/products/delete-product.js +119 -0
- package/src/isv/products/get-product-image.js +247 -0
- package/src/isv/products/get-product.js +168 -0
- package/src/isv/products/index.js +65 -0
- package/src/isv/products/list-products.js +136 -0
- package/src/isv/products/schedules.js +522 -0
- package/src/isv/products/update-product.js +265 -0
- package/src/isv/transactions/cancel-transaction.js +129 -0
- package/src/isv/transactions/create-transaction.js +361 -0
- package/src/isv/transactions/get-status.js +217 -0
- package/src/isv/transactions/process-transaction.js +145 -0
- package/src/isv/transactions/simulate-callback.js +146 -0
- package/src/isv/transactions/transaction-history.js +186 -0
- package/src/isv/utils/auth.js +159 -0
- package/src/mcp-proxy.js +150 -0
- package/src/merchant/data/export-report.js +108 -0
- package/src/merchant/data/generate-report.js +151 -0
- package/src/merchant/data/get-report-status.js +120 -0
- package/src/merchant/data/index.js +351 -0
- package/src/merchant/deep-links/delete-product-link.js +121 -0
- package/src/merchant/deep-links/delete-transaction-link.js +121 -0
- package/src/merchant/deep-links/get-product-link.js +134 -0
- package/src/merchant/deep-links/get-transaction-link.js +134 -0
- package/src/merchant/deep-links/index.js +23 -0
- package/src/merchant/index.js +92 -0
- package/src/merchant/products/audios.js +606 -0
- package/src/merchant/products/create-product.js +288 -0
- package/src/merchant/products/delete-product.js +111 -0
- package/src/merchant/products/get-product-image.js +252 -0
- package/src/merchant/products/get-product.js +144 -0
- package/src/merchant/products/index.js +65 -0
- package/src/merchant/products/list-products.js +112 -0
- package/src/merchant/products/schedules.js +646 -0
- package/src/merchant/products/update-product.js +282 -0
- package/src/merchant/transactions/cancel-transaction.js +241 -0
- package/src/merchant/transactions/create-transaction.js +482 -0
- package/src/merchant/transactions/get-status.js +196 -0
- package/src/merchant/transactions/process-transaction.js +349 -0
- package/src/merchant/transactions/simulate-callback.js +246 -0
- package/src/merchant/transactions/transaction-history.js +258 -0
- package/src/payment-institution/data/index.js +280 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
- package/src/payment-institution/deep-links/index.js +17 -0
- package/src/payment-institution/index.js +92 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
- package/src/payment-institution/transactions/finalize-transaction.js +340 -0
- package/src/payment-institution/transactions/get-transaction-history.js +269 -0
- package/src/payment-institution/transactions/get-transaction-status.js +234 -0
- package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
- package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
- package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
- package/src/proxy-server.js +205 -0
- package/src/shared/data/data-api.js +372 -0
- package/src/shared/deep-links/api.js +214 -0
- package/src/shared/index.js +44 -0
- package/src/shared/products/products-api.js +872 -0
- package/src/tools/advanced-code-generator.js +2247 -0
- package/src/utils/code-examples/common/auth-examples.js +1482 -0
- package/src/utils/code-examples/common/helpers.js +416 -0
- package/src/utils/code-examples/common/utils-examples.js +591 -0
- package/src/utils/code-examples/frameworks/examples.js +859 -0
- package/src/utils/code-examples/index.js +441 -0
- package/src/utils/code-examples/isv/oauth2.js +600 -0
- package/src/utils/code-examples/isv/products.js +666 -0
- package/src/utils/code-examples/isv/transactions.js +813 -0
- package/src/utils/code-examples/merchant/products.js +497 -0
- package/src/utils/code-examples/merchant/transactions.js +623 -0
- package/src/utils/code-examples/payment-institution/transactions.js +388 -0
- package/src/utils/code-examples/shared/data.js +607 -0
- package/src/utils/code-examples/shared/deep-links.js +662 -0
- package/src/utils/code-examples/shared/soundbites.js +808 -0
- package/src/utils/code-examples.js +646 -0
- package/src/utils/format-request.js +363 -0
- package/src/utils/json-formatter.js +249 -0
- package/src/utils/server-info.js +132 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { createJWTToken } from '../../core/auth/jwt-token.js';
|
|
3
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get transaction status via payware API (active transactions)
|
|
7
|
+
* @param {Object} params - Transaction status parameters
|
|
8
|
+
* @returns {Object} Transaction status response
|
|
9
|
+
*/
|
|
10
|
+
export async function getPITransactionStatus({
|
|
11
|
+
transactionId,
|
|
12
|
+
partnerId,
|
|
13
|
+
privateKey,
|
|
14
|
+
useSandbox = true
|
|
15
|
+
}) {
|
|
16
|
+
if (!transactionId) {
|
|
17
|
+
throw new Error('Transaction ID is required');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!partnerId || !privateKey) {
|
|
21
|
+
throw new Error('Partner ID and private key are required for proper JWT creation');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Create JWT token for GET request (no contentMd5 needed for GET)
|
|
25
|
+
const tokenData = createJWTToken(partnerId, privateKey, null);
|
|
26
|
+
|
|
27
|
+
// Required headers as per payware API documentation
|
|
28
|
+
const headers = {
|
|
29
|
+
'Authorization': `Bearer ${tokenData.token}`,
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
'Api-Version': '1' // Required: current API version
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
36
|
+
const response = await axios.get(`${baseUrl}/transactions/${transactionId}`, {
|
|
37
|
+
headers
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
transaction: response.data,
|
|
43
|
+
requestId: response.headers['x-request-id'],
|
|
44
|
+
timestamp: new Date().toISOString()
|
|
45
|
+
};
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: {
|
|
50
|
+
message: error.response?.data?.message || error.message,
|
|
51
|
+
status: error.response?.status,
|
|
52
|
+
code: error.response?.data?.code,
|
|
53
|
+
details: error.response?.data
|
|
54
|
+
},
|
|
55
|
+
timestamp: new Date().toISOString()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get payment institution transaction status tool implementation
|
|
62
|
+
*/
|
|
63
|
+
export const getPITransactionStatusTool = {
|
|
64
|
+
name: "payware_operations_get_transaction_status",
|
|
65
|
+
description: `Get the current status of an active payware transaction as a payment institution.
|
|
66
|
+
|
|
67
|
+
**Use Cases:**
|
|
68
|
+
- Check transaction status and details
|
|
69
|
+
- Monitor transaction progress
|
|
70
|
+
- Get participant information (payee/payer accounts, BICs)
|
|
71
|
+
- Check remaining time to live
|
|
72
|
+
|
|
73
|
+
**Response includes:**
|
|
74
|
+
- Transaction ID and type
|
|
75
|
+
- Payee/payer account details and BICs
|
|
76
|
+
- Transaction amount and currency
|
|
77
|
+
- Reason lines and creation timestamp
|
|
78
|
+
- Remaining time to live
|
|
79
|
+
- Current transaction state
|
|
80
|
+
|
|
81
|
+
**Note:** This endpoint only returns active transactions. Use \`payware_pi_get_transaction_history\` for completed/expired transactions.`,
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
transactionId: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Transaction ID to check status. Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
|
|
88
|
+
pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
|
|
89
|
+
},
|
|
90
|
+
partnerId: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
93
|
+
default: getPartnerIdSafe()
|
|
94
|
+
},
|
|
95
|
+
privateKey: {
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "RSA private key for JWT token creation. Uses environment-specific private key as default.",
|
|
98
|
+
default: getPrivateKeySafe()
|
|
99
|
+
},
|
|
100
|
+
useSandbox: {
|
|
101
|
+
type: "boolean",
|
|
102
|
+
description: "Use sandbox environment for testing",
|
|
103
|
+
default: true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
required: ["transactionId"]
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async handler(args) {
|
|
110
|
+
const {
|
|
111
|
+
transactionId,
|
|
112
|
+
partnerId = getPartnerIdSafe(),
|
|
113
|
+
privateKey = getPrivateKeySafe(args.useSandbox ?? true),
|
|
114
|
+
useSandbox = true
|
|
115
|
+
} = args;
|
|
116
|
+
|
|
117
|
+
if (!transactionId) {
|
|
118
|
+
throw new Error("Transaction ID is required");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!partnerId) {
|
|
122
|
+
throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!privateKey) {
|
|
126
|
+
throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const result = await getPITransactionStatus({
|
|
130
|
+
transactionId,
|
|
131
|
+
partnerId,
|
|
132
|
+
privateKey,
|
|
133
|
+
useSandbox
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (result.success) {
|
|
137
|
+
const tx = result.transaction;
|
|
138
|
+
const createdDate = tx.created ? new Date(tx.created * 1000).toISOString() : 'N/A';
|
|
139
|
+
|
|
140
|
+
// Transaction type display
|
|
141
|
+
const typeDisplay = tx.transactionType || 'DEFAULT';
|
|
142
|
+
const initiatorDisplay = tx.initiatedBy || 'UNKNOWN';
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
content: [{
|
|
146
|
+
type: "text",
|
|
147
|
+
text: `📊 **Payment Institution Transaction Status**
|
|
148
|
+
|
|
149
|
+
**Transaction Information:**
|
|
150
|
+
- ID: ${tx.transactionId || transactionId}
|
|
151
|
+
- Type: ${typeDisplay}
|
|
152
|
+
- Initiated By: ${initiatorDisplay}
|
|
153
|
+
- Status: ⏳ ACTIVE
|
|
154
|
+
- Created: ${createdDate}
|
|
155
|
+
- Remaining TTL: ${tx.timeToLive || 'N/A'} seconds
|
|
156
|
+
|
|
157
|
+
**Transaction Details:**
|
|
158
|
+
- Amount: ${tx.amount || 'N/A'} ${tx.currency || 'N/A'}
|
|
159
|
+
- Reason L1: ${tx.reasonL1 || 'N/A'}
|
|
160
|
+
${tx.reasonL2 ? `- Reason L2: ${tx.reasonL2}` : ''}
|
|
161
|
+
|
|
162
|
+
**Payee Information:**
|
|
163
|
+
- Account: ${tx.payeeAccount || 'N/A'}
|
|
164
|
+
- Friendly Name: ${tx.payeeFriendlyName || 'N/A'}
|
|
165
|
+
- BIC: ${tx.payeeBIC || 'N/A'}
|
|
166
|
+
|
|
167
|
+
**Payer Information:**
|
|
168
|
+
- Account: ${tx.payerAccount || 'N/A'}
|
|
169
|
+
- Friendly Name: ${tx.payerFriendlyName || 'N/A'}
|
|
170
|
+
- BIC: ${tx.payerBIC || 'N/A'}
|
|
171
|
+
|
|
172
|
+
**Full API Response:**
|
|
173
|
+
\`\`\`json
|
|
174
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
175
|
+
\`\`\`
|
|
176
|
+
|
|
177
|
+
**API Call Details:**
|
|
178
|
+
- Endpoint: GET ${baseUrl}/transactions/${transactionId}
|
|
179
|
+
- Request ID: ${result.requestId || 'N/A'}
|
|
180
|
+
- Timestamp: ${result.timestamp}
|
|
181
|
+
|
|
182
|
+
**Next Steps:**
|
|
183
|
+
1. ${!tx.payerAccount ? 'Transaction waiting for payer to process' : 'Transaction processed, waiting for finalization'}
|
|
184
|
+
2. ${tx.timeToLive && parseInt(tx.timeToLive) < 60 ? '⚠️ Transaction expires soon!' : 'Monitor remaining TTL'}
|
|
185
|
+
3. Use \`payware_pi_process_transaction\` if you need to process this transaction
|
|
186
|
+
4. Use \`payware_pi_finalize_transaction\` to confirm/decline after processing
|
|
187
|
+
|
|
188
|
+
**⚠️ Transaction State:**
|
|
189
|
+
- This is an **active** transaction
|
|
190
|
+
- Participants can still interact with it
|
|
191
|
+
- Will expire in ${tx.timeToLive || 'unknown'} seconds if not completed`
|
|
192
|
+
}]
|
|
193
|
+
};
|
|
194
|
+
} else {
|
|
195
|
+
return {
|
|
196
|
+
content: [{
|
|
197
|
+
type: "text",
|
|
198
|
+
text: `❌ **Transaction Status Check Failed**
|
|
199
|
+
|
|
200
|
+
**Transaction ID:** ${transactionId}
|
|
201
|
+
|
|
202
|
+
**Error Details:**
|
|
203
|
+
- Message: ${result.error.message}
|
|
204
|
+
- Status: ${result.error.status || 'N/A'}
|
|
205
|
+
- Code: ${result.error.code || 'N/A'}
|
|
206
|
+
|
|
207
|
+
**Full Error Response:**
|
|
208
|
+
\`\`\`json
|
|
209
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
210
|
+
\`\`\`
|
|
211
|
+
|
|
212
|
+
**Timestamp:** ${result.timestamp}
|
|
213
|
+
|
|
214
|
+
**Common Issues:**
|
|
215
|
+
1. **ERR_MISSING_TRANSACTION (404)**: Transaction not found, expired, or already completed
|
|
216
|
+
2. **Invalid Transaction ID**: Check transaction ID format (10 chars: 'pw'/'pr'/'ps' + 8 chars)
|
|
217
|
+
3. **Authentication Issues**: Verify JWT token and partner credentials
|
|
218
|
+
|
|
219
|
+
**Troubleshooting:**
|
|
220
|
+
1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
|
|
221
|
+
2. Check if transaction has expired or been completed
|
|
222
|
+
3. Use \`payware_pi_get_transaction_history\` for completed/expired transactions
|
|
223
|
+
4. Verify your partner credentials and API access
|
|
224
|
+
5. Ensure transaction was created or you have access to it
|
|
225
|
+
|
|
226
|
+
**Alternative Actions:**
|
|
227
|
+
- If transaction is completed: Use \`payware_pi_get_transaction_history\`
|
|
228
|
+
- If transaction ID is wrong: Verify the correct transaction ID
|
|
229
|
+
- If access issues: Check your payment institution credentials`
|
|
230
|
+
}]
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { createJWTToken } from '../../core/auth/jwt-token.js';
|
|
3
|
+
import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
|
|
4
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Process a transaction as a payment institution via payware API
|
|
8
|
+
* Payment institutions can process transactions they didn't create
|
|
9
|
+
* @param {Object} params - Transaction processing parameters
|
|
10
|
+
* @returns {Object} Transaction processing response
|
|
11
|
+
*/
|
|
12
|
+
export async function processPITransaction({
|
|
13
|
+
transactionId,
|
|
14
|
+
account,
|
|
15
|
+
friendlyName,
|
|
16
|
+
amount,
|
|
17
|
+
currency,
|
|
18
|
+
reasonL1,
|
|
19
|
+
reasonL2,
|
|
20
|
+
callbackUrl,
|
|
21
|
+
passbackParams,
|
|
22
|
+
timeToLive,
|
|
23
|
+
partnerId,
|
|
24
|
+
privateKey,
|
|
25
|
+
// Delivery address for SHIPPABLE transactions
|
|
26
|
+
deliveryAddress,
|
|
27
|
+
useSandbox = true
|
|
28
|
+
}) {
|
|
29
|
+
if (!transactionId) {
|
|
30
|
+
throw new Error('Transaction ID is required');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!account) {
|
|
34
|
+
throw new Error('account is required for payment institutions');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!friendlyName) {
|
|
38
|
+
throw new Error('friendlyName is required for payment institutions');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!currency) {
|
|
42
|
+
throw new Error('currency is required for payment institutions');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!reasonL1) {
|
|
46
|
+
throw new Error('reasonL1 is required for payment institutions');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!partnerId || !privateKey) {
|
|
50
|
+
throw new Error('Partner ID and private key are required for proper JWT creation');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Build request body according to payment institution API documentation
|
|
54
|
+
const requestBody = {
|
|
55
|
+
account,
|
|
56
|
+
friendlyName,
|
|
57
|
+
...(callbackUrl && { callbackUrl }),
|
|
58
|
+
...(passbackParams && { passbackParams }),
|
|
59
|
+
trData: {
|
|
60
|
+
...(amount !== undefined && { amount: amount.toString() }),
|
|
61
|
+
currency,
|
|
62
|
+
reasonL1,
|
|
63
|
+
...(reasonL2 && { reasonL2 })
|
|
64
|
+
},
|
|
65
|
+
...(timeToLive && {
|
|
66
|
+
trOptions: {
|
|
67
|
+
timeToLive
|
|
68
|
+
}
|
|
69
|
+
}),
|
|
70
|
+
...(deliveryAddress && { deliveryAddress })
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Convert to deterministic minimized JSON for MD5 calculation
|
|
74
|
+
const minimizedBodyString = createMinimizedJSON(requestBody);
|
|
75
|
+
|
|
76
|
+
// Create JWT token with contentMd5 for the request body (POST requires contentMd5)
|
|
77
|
+
const tokenData = createJWTToken(partnerId, privateKey, minimizedBodyString);
|
|
78
|
+
|
|
79
|
+
// Required headers as per payware API documentation
|
|
80
|
+
const headers = {
|
|
81
|
+
'Authorization': `Bearer ${tokenData.token}`,
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
'Api-Version': '1' // Required: current API version
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
88
|
+
// Send the exact minimized JSON string that was used for MD5 calculation
|
|
89
|
+
const response = await axios.post(`${baseUrl}/transactions/${transactionId}`, minimizedBodyString, {
|
|
90
|
+
headers,
|
|
91
|
+
// Tell axios to send the string as-is, don't serialize it again
|
|
92
|
+
transformRequest: [(data) => data]
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
transaction: response.data,
|
|
98
|
+
requestId: response.headers['x-request-id'],
|
|
99
|
+
timestamp: new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: {
|
|
105
|
+
message: error.response?.data?.message || error.message,
|
|
106
|
+
status: error.response?.status,
|
|
107
|
+
code: error.response?.data?.code,
|
|
108
|
+
details: error.response?.data
|
|
109
|
+
},
|
|
110
|
+
timestamp: new Date().toISOString()
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Process payment institution transaction tool implementation
|
|
117
|
+
*/
|
|
118
|
+
export const processPITransactionTool = {
|
|
119
|
+
name: "payware_operations_process_transaction",
|
|
120
|
+
description: `Process a transaction as a payment institution. Payment institutions can process transactions created by others and must provide account/friendlyName details.
|
|
121
|
+
|
|
122
|
+
**Use Cases:**
|
|
123
|
+
- **As Payer (SRC)**: Process a transaction initiated by payee (pay a request)
|
|
124
|
+
- **As Payee (DST)**: Process a transaction initiated by payer (accept payment)
|
|
125
|
+
- **Cross-PI**: Process transactions from other payment institutions
|
|
126
|
+
|
|
127
|
+
**Required for Payment Institutions:**
|
|
128
|
+
- account: Your account identifier
|
|
129
|
+
- friendlyName: Your account holder name
|
|
130
|
+
- currency: Transaction currency (required)
|
|
131
|
+
- reasonL1: Transaction grounds description (required)
|
|
132
|
+
|
|
133
|
+
**API Request Structure:**
|
|
134
|
+
\`\`\`json
|
|
135
|
+
{
|
|
136
|
+
"account": "GB29NWBK60161331926818",
|
|
137
|
+
"friendlyName": "Jane Doe Bank",
|
|
138
|
+
"callbackUrl": "https://callback.url",
|
|
139
|
+
"passbackParams": "internal-ref-123",
|
|
140
|
+
"trData": {
|
|
141
|
+
"amount": "57.60",
|
|
142
|
+
"currency": "EUR",
|
|
143
|
+
"reasonL1": "Bill payment",
|
|
144
|
+
"reasonL2": "Invoice #12345"
|
|
145
|
+
},
|
|
146
|
+
"trOptions": {
|
|
147
|
+
"timeToLive": 300
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
\`\`\``,
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: {
|
|
154
|
+
transactionId: {
|
|
155
|
+
type: "string",
|
|
156
|
+
description: "Transaction ID to process. Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
|
|
157
|
+
pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
|
|
158
|
+
},
|
|
159
|
+
account: {
|
|
160
|
+
type: "string",
|
|
161
|
+
description: "Your account identifier (required for payment institutions)",
|
|
162
|
+
maxLength: 36
|
|
163
|
+
},
|
|
164
|
+
friendlyName: {
|
|
165
|
+
type: "string",
|
|
166
|
+
description: "Your account holder recognizable name (required for payment institutions)",
|
|
167
|
+
maxLength: 100
|
|
168
|
+
},
|
|
169
|
+
amount: {
|
|
170
|
+
type: ["number", "string"],
|
|
171
|
+
description: "Amount as currency value to process. For payee: must be <= original amount. For payer: can be >= original amount (tipping)",
|
|
172
|
+
minimum: 0.01,
|
|
173
|
+
maximum: 9999999999999.99
|
|
174
|
+
},
|
|
175
|
+
currency: {
|
|
176
|
+
type: "string",
|
|
177
|
+
pattern: "^[A-Z]{3}$",
|
|
178
|
+
description: "Transaction currency (ISO 3-character code, required for payment institutions)"
|
|
179
|
+
},
|
|
180
|
+
reasonL1: {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "Transaction grounds description (required for payment institutions - omit for SHIPPABLE to get merchant name)",
|
|
183
|
+
maxLength: 100
|
|
184
|
+
},
|
|
185
|
+
reasonL2: {
|
|
186
|
+
type: "string",
|
|
187
|
+
description: "Transaction grounds description continuation (optional - omit for SHIPPABLE to get product name)",
|
|
188
|
+
maxLength: 100
|
|
189
|
+
},
|
|
190
|
+
callbackUrl: {
|
|
191
|
+
type: "string",
|
|
192
|
+
description: "HTTPS URL to receive transaction status callbacks (mandatory when processing as payee)",
|
|
193
|
+
format: "uri"
|
|
194
|
+
},
|
|
195
|
+
passbackParams: {
|
|
196
|
+
type: "string",
|
|
197
|
+
description: "Parameters passed back through callback",
|
|
198
|
+
maxLength: 200
|
|
199
|
+
},
|
|
200
|
+
timeToLive: {
|
|
201
|
+
type: "number",
|
|
202
|
+
description: "Time allowed for transaction finalization in seconds (PI can extend: 60-2592000, Merchant: original+120 max)",
|
|
203
|
+
minimum: 60,
|
|
204
|
+
maximum: 2592000
|
|
205
|
+
},
|
|
206
|
+
partnerId: {
|
|
207
|
+
type: "string",
|
|
208
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
209
|
+
default: getPartnerIdSafe()
|
|
210
|
+
},
|
|
211
|
+
privateKey: {
|
|
212
|
+
type: "string",
|
|
213
|
+
description: "RSA private key for JWT token creation. Uses environment-specific private key as default.",
|
|
214
|
+
default: getPrivateKeySafe()
|
|
215
|
+
},
|
|
216
|
+
// Delivery address for SHIPPABLE transactions
|
|
217
|
+
deliveryAddress: {
|
|
218
|
+
type: "object",
|
|
219
|
+
description: "Delivery address (required when processing SHIPPABLE transactions)",
|
|
220
|
+
properties: {
|
|
221
|
+
fullName: {
|
|
222
|
+
type: "string",
|
|
223
|
+
description: "Recipient full name (required)",
|
|
224
|
+
maxLength: 300
|
|
225
|
+
},
|
|
226
|
+
streetAddressLine1: {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "Street address line 1 (required)",
|
|
229
|
+
maxLength: 300
|
|
230
|
+
},
|
|
231
|
+
streetAddressLine2: {
|
|
232
|
+
type: "string",
|
|
233
|
+
description: "Street address line 2 (optional)",
|
|
234
|
+
maxLength: 300
|
|
235
|
+
},
|
|
236
|
+
zipCode: {
|
|
237
|
+
type: "string",
|
|
238
|
+
description: "ZIP code (required)",
|
|
239
|
+
maxLength: 20
|
|
240
|
+
},
|
|
241
|
+
city: {
|
|
242
|
+
type: "string",
|
|
243
|
+
description: "City name (required)",
|
|
244
|
+
maxLength: 100
|
|
245
|
+
},
|
|
246
|
+
region: {
|
|
247
|
+
type: "string",
|
|
248
|
+
description: "Region (required)",
|
|
249
|
+
maxLength: 200
|
|
250
|
+
},
|
|
251
|
+
country: {
|
|
252
|
+
type: "string",
|
|
253
|
+
description: "Country (required)",
|
|
254
|
+
maxLength: 32
|
|
255
|
+
},
|
|
256
|
+
phoneNumber: {
|
|
257
|
+
type: "string",
|
|
258
|
+
description: "Recipient phone number (required if email not provided)",
|
|
259
|
+
maxLength: 255
|
|
260
|
+
},
|
|
261
|
+
email: {
|
|
262
|
+
type: "string",
|
|
263
|
+
description: "Recipient email address (required if phoneNumber not provided)",
|
|
264
|
+
format: "email",
|
|
265
|
+
maxLength: 255
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
required: ["fullName", "streetAddressLine1", "zipCode", "city", "region", "country"]
|
|
269
|
+
},
|
|
270
|
+
useSandbox: {
|
|
271
|
+
type: "boolean",
|
|
272
|
+
description: "Use sandbox environment for testing",
|
|
273
|
+
default: true
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
required: ["transactionId", "account", "friendlyName", "currency", "reasonL1"]
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
async handler(args) {
|
|
280
|
+
const {
|
|
281
|
+
transactionId,
|
|
282
|
+
account,
|
|
283
|
+
friendlyName,
|
|
284
|
+
amount,
|
|
285
|
+
currency,
|
|
286
|
+
reasonL1,
|
|
287
|
+
reasonL2,
|
|
288
|
+
callbackUrl,
|
|
289
|
+
passbackParams,
|
|
290
|
+
timeToLive,
|
|
291
|
+
partnerId = getPartnerIdSafe(),
|
|
292
|
+
privateKey = getPrivateKeySafe(args.useSandbox ?? true),
|
|
293
|
+
deliveryAddress,
|
|
294
|
+
useSandbox = true
|
|
295
|
+
} = args;
|
|
296
|
+
|
|
297
|
+
if (!transactionId) {
|
|
298
|
+
throw new Error("Transaction ID is required");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!account) {
|
|
302
|
+
throw new Error("account is required for payment institutions");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!friendlyName) {
|
|
306
|
+
throw new Error("friendlyName is required for payment institutions");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (!currency) {
|
|
310
|
+
throw new Error("currency is required for payment institutions");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!reasonL1) {
|
|
314
|
+
throw new Error("reasonL1 is required for payment institutions");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!partnerId) {
|
|
318
|
+
throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!privateKey) {
|
|
322
|
+
throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const result = await processPITransaction({
|
|
326
|
+
transactionId,
|
|
327
|
+
account,
|
|
328
|
+
friendlyName,
|
|
329
|
+
amount,
|
|
330
|
+
currency,
|
|
331
|
+
reasonL1,
|
|
332
|
+
reasonL2,
|
|
333
|
+
callbackUrl,
|
|
334
|
+
passbackParams,
|
|
335
|
+
timeToLive,
|
|
336
|
+
partnerId,
|
|
337
|
+
privateKey,
|
|
338
|
+
deliveryAddress,
|
|
339
|
+
useSandbox
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
if (result.success) {
|
|
343
|
+
return {
|
|
344
|
+
content: [{
|
|
345
|
+
type: "text",
|
|
346
|
+
text: `🔄 **Payment Institution Transaction Processing Initiated**
|
|
347
|
+
|
|
348
|
+
**Transaction ID:** ${transactionId}
|
|
349
|
+
**Processing Status:** ✅ Successful
|
|
350
|
+
|
|
351
|
+
**Your Details:**
|
|
352
|
+
- Account: ${account}
|
|
353
|
+
- Friendly Name: ${friendlyName}
|
|
354
|
+
${amount ? `- Amount: ${amount} ${currency}` : ''}
|
|
355
|
+
${reasonL1 ? `- Reason: ${reasonL1}${reasonL2 ? ` (${reasonL2})` : ''}` : ''}
|
|
356
|
+
${timeToLive ? `- Time to Live: ${timeToLive} seconds` : ''}
|
|
357
|
+
${callbackUrl ? `- Callback URL: ${callbackUrl}` : ''}
|
|
358
|
+
${passbackParams ? `- Passback Params: ${passbackParams}` : ''}
|
|
359
|
+
|
|
360
|
+
**Transaction Details:**
|
|
361
|
+
\`\`\`json
|
|
362
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
363
|
+
\`\`\`
|
|
364
|
+
|
|
365
|
+
**Request ID:** ${result.requestId || 'N/A'}
|
|
366
|
+
**Timestamp:** ${result.timestamp}
|
|
367
|
+
|
|
368
|
+
**Next Steps:**
|
|
369
|
+
1. **TRANSACTION_PROCESSED** callback will be sent to counterparty
|
|
370
|
+
2. Wait for callback notification to your URL (if provided)
|
|
371
|
+
3. Monitor transaction status for completion
|
|
372
|
+
4. Use \`payware_pi_finalize_transaction\` to confirm/decline the transaction
|
|
373
|
+
5. Handle final TRANSACTION_FINALIZED callbacks
|
|
374
|
+
|
|
375
|
+
**⚠️ Important:**
|
|
376
|
+
- As a payment institution, you must finalize this transaction
|
|
377
|
+
- Transaction will expire if not finalized within TTL
|
|
378
|
+
- Callback URL is mandatory when processing as payee`
|
|
379
|
+
}]
|
|
380
|
+
};
|
|
381
|
+
} else {
|
|
382
|
+
return {
|
|
383
|
+
content: [{
|
|
384
|
+
type: "text",
|
|
385
|
+
text: `❌ **Payment Institution Transaction Processing Failed**
|
|
386
|
+
|
|
387
|
+
**Transaction ID:** ${transactionId}
|
|
388
|
+
|
|
389
|
+
**Error Details:**
|
|
390
|
+
- Message: ${result.error.message}
|
|
391
|
+
- Status: ${result.error.status || 'N/A'}
|
|
392
|
+
- Code: ${result.error.code || 'N/A'}
|
|
393
|
+
|
|
394
|
+
**Full Error Response:**
|
|
395
|
+
\`\`\`json
|
|
396
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
**Timestamp:** ${result.timestamp}
|
|
400
|
+
|
|
401
|
+
**Common Payment Institution Issues:**
|
|
402
|
+
1. **ERR_MISSING_TRANSACTION**: Transaction ID not found or expired
|
|
403
|
+
2. **ERR_ALREADY_PROCESSED**: Transaction already processed
|
|
404
|
+
3. **ERR_MISSING_PARTNER_ACCOUNT**: Account parameter missing or empty
|
|
405
|
+
4. **ERR_MISSING_FRIENDLY_NAME**: Friendly name parameter missing
|
|
406
|
+
5. **ERR_MISSING_CALLBACK_URL**: Callback URL required when processing as payee
|
|
407
|
+
6. **ERR_INVALID_AMOUNT**: Amount validation failed
|
|
408
|
+
7. **ERR_SPECIFYING_CURRENCY_NOT_ALLOWED**: Cannot change currency on merchant transactions
|
|
409
|
+
|
|
410
|
+
**Troubleshooting:**
|
|
411
|
+
1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
|
|
412
|
+
2. Ensure account and friendlyName are provided
|
|
413
|
+
3. Check currency matches original transaction currency
|
|
414
|
+
4. Verify callback URL is provided (especially for payee role)
|
|
415
|
+
5. Validate amount constraints based on your role in the transaction
|
|
416
|
+
6. Check if transaction requires delivery address (SHIPPABLE type)`
|
|
417
|
+
}]
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
};
|