@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,340 @@
|
|
|
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
|
+
* Finalize a transaction as a payment institution via payware API
|
|
8
|
+
* Payment institutions can update transaction status after execution in their network
|
|
9
|
+
* @param {Object} params - Transaction finalization parameters
|
|
10
|
+
* @returns {Object} Transaction finalization response
|
|
11
|
+
*/
|
|
12
|
+
export async function finalizeTransaction({
|
|
13
|
+
transactionId,
|
|
14
|
+
status,
|
|
15
|
+
statusMessage,
|
|
16
|
+
amount,
|
|
17
|
+
fee,
|
|
18
|
+
currency,
|
|
19
|
+
partnerId,
|
|
20
|
+
privateKey,
|
|
21
|
+
useSandbox = true
|
|
22
|
+
}) {
|
|
23
|
+
if (!transactionId) {
|
|
24
|
+
throw new Error('Transaction ID is required');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!status || !['CONFIRMED', 'CANCELLED', 'DECLINED', 'FAILED'].includes(status)) {
|
|
28
|
+
throw new Error('status is required and must be one of: CONFIRMED, CANCELLED, DECLINED, FAILED');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (['CANCELLED', 'DECLINED', 'FAILED'].includes(status) && !statusMessage) {
|
|
32
|
+
throw new Error(`statusMessage is required for status: ${status}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (status === 'CONFIRMED') {
|
|
36
|
+
if (!amount) {
|
|
37
|
+
throw new Error('amount is required for CONFIRMED transactions');
|
|
38
|
+
}
|
|
39
|
+
if (!currency) {
|
|
40
|
+
throw new Error('currency is required for CONFIRMED transactions');
|
|
41
|
+
}
|
|
42
|
+
if (fee === undefined) {
|
|
43
|
+
throw new Error('fee is required for CONFIRMED transactions (use 0 for no fee)');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!partnerId || !privateKey) {
|
|
48
|
+
throw new Error('Partner ID and private key are required for proper JWT creation');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Build request body according to payment institution API documentation
|
|
52
|
+
const requestBody = {
|
|
53
|
+
status,
|
|
54
|
+
...(statusMessage && { statusMessage }),
|
|
55
|
+
...(status === 'CONFIRMED' && {
|
|
56
|
+
amount: amount.toString(),
|
|
57
|
+
fee: fee.toString(),
|
|
58
|
+
currency
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Convert to deterministic minimized JSON for MD5 calculation
|
|
63
|
+
const minimizedBodyString = createMinimizedJSON(requestBody);
|
|
64
|
+
|
|
65
|
+
// Create JWT token with contentMd5 for the request body (PATCH requires contentMd5)
|
|
66
|
+
const tokenData = createJWTToken(partnerId, privateKey, minimizedBodyString);
|
|
67
|
+
|
|
68
|
+
// Required headers as per payware API documentation
|
|
69
|
+
const headers = {
|
|
70
|
+
'Authorization': `Bearer ${tokenData.token}`,
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'Api-Version': '1' // Required: current API version
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
77
|
+
// Send the exact minimized JSON string that was used for MD5 calculation
|
|
78
|
+
const response = await axios.patch(`${baseUrl}/transactions/${transactionId}`, minimizedBodyString, {
|
|
79
|
+
headers,
|
|
80
|
+
// Tell axios to send the string as-is, don't serialize it again
|
|
81
|
+
transformRequest: [(data) => data]
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
transaction: response.data,
|
|
87
|
+
requestId: response.headers['x-request-id'],
|
|
88
|
+
timestamp: new Date().toISOString()
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: {
|
|
94
|
+
message: error.response?.data?.message || error.message,
|
|
95
|
+
status: error.response?.status,
|
|
96
|
+
code: error.response?.data?.code,
|
|
97
|
+
details: error.response?.data
|
|
98
|
+
},
|
|
99
|
+
timestamp: new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Finalize transaction tool implementation
|
|
106
|
+
*/
|
|
107
|
+
export const finalizeTransactionTool = {
|
|
108
|
+
name: "payware_operations_finalize_transaction",
|
|
109
|
+
description: `Finalize a transaction as a payment institution. This updates the transaction status after execution in your payment network.
|
|
110
|
+
|
|
111
|
+
**Payment Institution Finalization:**
|
|
112
|
+
- **CONFIRMED**: Transaction executed successfully (requires amount, fee, currency)
|
|
113
|
+
- **CANCELLED**: Transaction cancelled by creator
|
|
114
|
+
- **DECLINED**: Transaction declined by payment institution (requires statusMessage)
|
|
115
|
+
- **FAILED**: Transaction failed during execution (requires statusMessage)
|
|
116
|
+
|
|
117
|
+
**Requirements:**
|
|
118
|
+
- Only payment institutions can finalize transactions
|
|
119
|
+
- Currency must match the processing currency of the transaction
|
|
120
|
+
- Amount/fee required for CONFIRMED status
|
|
121
|
+
- StatusMessage required for CANCELLED/DECLINED/FAILED status
|
|
122
|
+
|
|
123
|
+
**API Request Structure:**
|
|
124
|
+
\`\`\`json
|
|
125
|
+
{
|
|
126
|
+
"status": "CONFIRMED",
|
|
127
|
+
"amount": "57.60",
|
|
128
|
+
"fee": "0.29",
|
|
129
|
+
"currency": "EUR"
|
|
130
|
+
}
|
|
131
|
+
\`\`\``,
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
transactionId: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Transaction ID to finalize. Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
|
|
138
|
+
pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
|
|
139
|
+
},
|
|
140
|
+
status: {
|
|
141
|
+
type: "string",
|
|
142
|
+
enum: ["CONFIRMED", "CANCELLED", "DECLINED", "FAILED"],
|
|
143
|
+
description: "Final transaction status"
|
|
144
|
+
},
|
|
145
|
+
statusMessage: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Transaction failure/cancellation reason (required for CANCELLED, DECLINED, FAILED)",
|
|
148
|
+
maxLength: 100
|
|
149
|
+
},
|
|
150
|
+
amount: {
|
|
151
|
+
type: ["number", "string"],
|
|
152
|
+
description: "Final transaction amount (required for CONFIRMED status)",
|
|
153
|
+
minimum: 0.01,
|
|
154
|
+
maximum: 9999999999999.99
|
|
155
|
+
},
|
|
156
|
+
fee: {
|
|
157
|
+
type: ["number", "string"],
|
|
158
|
+
description: "Fee amount collected by payment institution (required for CONFIRMED status, use 0 for no fee)",
|
|
159
|
+
minimum: 0,
|
|
160
|
+
maximum: 9999999999999.99
|
|
161
|
+
},
|
|
162
|
+
currency: {
|
|
163
|
+
type: "string",
|
|
164
|
+
pattern: "^[A-Z]{3}$",
|
|
165
|
+
description: "Transaction currency (required for CONFIRMED status, must match processing currency)"
|
|
166
|
+
},
|
|
167
|
+
partnerId: {
|
|
168
|
+
type: "string",
|
|
169
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
170
|
+
default: getPartnerIdSafe()
|
|
171
|
+
},
|
|
172
|
+
privateKey: {
|
|
173
|
+
type: "string",
|
|
174
|
+
description: "RSA private key for JWT token creation. Uses environment-specific private key as default.",
|
|
175
|
+
default: getPrivateKeySafe()
|
|
176
|
+
},
|
|
177
|
+
useSandbox: {
|
|
178
|
+
type: "boolean",
|
|
179
|
+
description: "Use sandbox environment for testing",
|
|
180
|
+
default: true
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
required: ["transactionId", "status"]
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
async handler(args) {
|
|
187
|
+
const {
|
|
188
|
+
transactionId,
|
|
189
|
+
status,
|
|
190
|
+
statusMessage,
|
|
191
|
+
amount,
|
|
192
|
+
fee,
|
|
193
|
+
currency,
|
|
194
|
+
partnerId = getPartnerIdSafe(),
|
|
195
|
+
privateKey = getPrivateKeySafe(args.useSandbox ?? true),
|
|
196
|
+
useSandbox = true
|
|
197
|
+
} = args;
|
|
198
|
+
|
|
199
|
+
if (!transactionId) {
|
|
200
|
+
throw new Error("Transaction ID is required");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!status) {
|
|
204
|
+
throw new Error("status is required and must be one of: CONFIRMED, CANCELLED, DECLINED, FAILED");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Validate status-specific requirements
|
|
208
|
+
if (['CANCELLED', 'DECLINED', 'FAILED'].includes(status) && !statusMessage) {
|
|
209
|
+
throw new Error(`statusMessage is required for status: ${status}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (status === 'CONFIRMED') {
|
|
213
|
+
if (!amount) {
|
|
214
|
+
throw new Error("amount is required for CONFIRMED transactions");
|
|
215
|
+
}
|
|
216
|
+
if (!currency) {
|
|
217
|
+
throw new Error("currency is required for CONFIRMED transactions");
|
|
218
|
+
}
|
|
219
|
+
if (fee === undefined) {
|
|
220
|
+
throw new Error("fee is required for CONFIRMED transactions (use 0 for no fee)");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!partnerId) {
|
|
225
|
+
throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!privateKey) {
|
|
229
|
+
throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const result = await finalizeTransaction({
|
|
233
|
+
transactionId,
|
|
234
|
+
status,
|
|
235
|
+
statusMessage,
|
|
236
|
+
amount,
|
|
237
|
+
fee,
|
|
238
|
+
currency,
|
|
239
|
+
partnerId,
|
|
240
|
+
privateKey,
|
|
241
|
+
useSandbox
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (result.success) {
|
|
245
|
+
const statusEmojis = {
|
|
246
|
+
CONFIRMED: '✅',
|
|
247
|
+
CANCELLED: '🚫',
|
|
248
|
+
DECLINED: '❌',
|
|
249
|
+
FAILED: '💥'
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const statusEmoji = statusEmojis[status] || '📄';
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
content: [{
|
|
256
|
+
type: "text",
|
|
257
|
+
text: `${statusEmoji} **Transaction Finalized Successfully**
|
|
258
|
+
|
|
259
|
+
**Transaction ID:** ${transactionId}
|
|
260
|
+
**Final Status:** ${status}
|
|
261
|
+
|
|
262
|
+
**Finalization Details:**
|
|
263
|
+
${statusMessage ? `- Status Message: ${statusMessage}` : ''}
|
|
264
|
+
${amount ? `- Final Amount: ${amount} ${currency}` : ''}
|
|
265
|
+
${fee !== undefined ? `- Fee Collected: ${fee} ${currency}` : ''}
|
|
266
|
+
|
|
267
|
+
**Transaction Response:**
|
|
268
|
+
\`\`\`json
|
|
269
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
270
|
+
\`\`\`
|
|
271
|
+
|
|
272
|
+
**API Call Details:**
|
|
273
|
+
- Endpoint: PATCH ${baseUrl}/transactions/${transactionId}
|
|
274
|
+
- Request ID: ${result.requestId || 'N/A'}
|
|
275
|
+
- Timestamp: ${result.timestamp}
|
|
276
|
+
|
|
277
|
+
**Callbacks Triggered:**
|
|
278
|
+
- **TRANSACTION_FINALIZED** callback sent to all parties
|
|
279
|
+
- Transaction moved to historical records
|
|
280
|
+
- Final status permanently recorded
|
|
281
|
+
|
|
282
|
+
**Next Steps:**
|
|
283
|
+
${status === 'CONFIRMED' ?
|
|
284
|
+
`1. ✅ Payment completed successfully
|
|
285
|
+
2. Transaction funds should be processed in your network
|
|
286
|
+
3. Use \`payware_pi_get_transaction_history\` to retrieve details later` :
|
|
287
|
+
`1. ⚠️ Payment not completed due to: ${statusMessage || status}
|
|
288
|
+
2. Transaction marked as ${status} in payware system
|
|
289
|
+
3. All parties notified via callbacks`
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
**⚠️ Important:**
|
|
293
|
+
- Transaction finalization is **permanent** and cannot be reversed
|
|
294
|
+
- This transaction is now complete in the payware system`
|
|
295
|
+
}]
|
|
296
|
+
};
|
|
297
|
+
} else {
|
|
298
|
+
return {
|
|
299
|
+
content: [{
|
|
300
|
+
type: "text",
|
|
301
|
+
text: `❌ **Transaction Finalization Failed**
|
|
302
|
+
|
|
303
|
+
**Transaction ID:** ${transactionId}
|
|
304
|
+
**Attempted Status:** ${status}
|
|
305
|
+
|
|
306
|
+
**Error Details:**
|
|
307
|
+
- Message: ${result.error.message}
|
|
308
|
+
- Status: ${result.error.status || 'N/A'}
|
|
309
|
+
- Code: ${result.error.code || 'N/A'}
|
|
310
|
+
|
|
311
|
+
**Full Error Response:**
|
|
312
|
+
\`\`\`json
|
|
313
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
314
|
+
\`\`\`
|
|
315
|
+
|
|
316
|
+
**Timestamp:** ${result.timestamp}
|
|
317
|
+
|
|
318
|
+
**Common Finalization Issues:**
|
|
319
|
+
1. **ERR_MISSING_TRANSACTION**: Transaction ID not found or expired
|
|
320
|
+
2. **ERR_TRANSACTION_NOT_PROCESSED**: Transaction hasn't been processed yet
|
|
321
|
+
3. **ERR_ALREADY_PROCESSED**: Transaction already finalized
|
|
322
|
+
4. **ERR_INVALID_STATUS**: Invalid status value provided
|
|
323
|
+
5. **ERR_MISSING_STATUS_MESSAGE**: Status message required for failed/declined/cancelled
|
|
324
|
+
6. **ERR_SPECIFYING_CURRENCY_NOT_ALLOWED**: Currency doesn't match transaction currency
|
|
325
|
+
7. **ERR_INVALID_AMOUNT**: Amount validation failed
|
|
326
|
+
8. **ERR_UNAUTHORIZED_OPERATION**: Not authorized to finalize this transaction
|
|
327
|
+
|
|
328
|
+
**Troubleshooting:**
|
|
329
|
+
1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
|
|
330
|
+
2. Ensure transaction has been processed first
|
|
331
|
+
3. Check status is one of: CONFIRMED, CANCELLED, DECLINED, FAILED
|
|
332
|
+
4. Provide statusMessage for non-CONFIRMED statuses
|
|
333
|
+
5. Include amount, fee, currency for CONFIRMED status
|
|
334
|
+
6. Verify you are authorized to finalize this transaction
|
|
335
|
+
7. Ensure currency matches the original transaction currency`
|
|
336
|
+
}]
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
@@ -0,0 +1,269 @@
|
|
|
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 history via payware API (completed/expired transactions)
|
|
7
|
+
* @param {Object} params - Transaction history parameters
|
|
8
|
+
* @returns {Object} Transaction history response
|
|
9
|
+
*/
|
|
10
|
+
export async function getPITransactionHistory({
|
|
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-history/${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 history tool implementation
|
|
62
|
+
*/
|
|
63
|
+
export const getPITransactionHistoryTool = {
|
|
64
|
+
name: "payware_operations_get_transaction_history",
|
|
65
|
+
description: `Get the complete history of a completed or expired payware transaction as a payment institution.
|
|
66
|
+
|
|
67
|
+
**Use Cases:**
|
|
68
|
+
- Retrieve details of completed transactions
|
|
69
|
+
- Get information about expired transactions
|
|
70
|
+
- Access finalized transaction data including final status
|
|
71
|
+
- Audit and reconciliation purposes
|
|
72
|
+
|
|
73
|
+
**Response includes:**
|
|
74
|
+
- Complete transaction details
|
|
75
|
+
- Final status (CONFIRMED, DECLINED, FAILED, EXPIRED)
|
|
76
|
+
- Status message (for failed/declined transactions)
|
|
77
|
+
- Payee/payer account details and BICs
|
|
78
|
+
- Transaction amounts, currency, and timestamps
|
|
79
|
+
- Creation and processing timeline
|
|
80
|
+
|
|
81
|
+
**Note:** This endpoint is throttled and may return HTTP 429 (Too Many Requests). Implement appropriate retry logic.`,
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
transactionId: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Transaction ID to retrieve history. 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 getPITransactionHistory({
|
|
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
|
+
// Status emoji mapping
|
|
141
|
+
const statusEmojis = {
|
|
142
|
+
CONFIRMED: '✅',
|
|
143
|
+
DECLINED: '❌',
|
|
144
|
+
FAILED: '💥',
|
|
145
|
+
EXPIRED: '⏰',
|
|
146
|
+
CANCELLED: '🚫'
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const statusEmoji = statusEmojis[tx.status] || '📄';
|
|
150
|
+
const typeDisplay = tx.transactionType || 'DEFAULT';
|
|
151
|
+
const initiatorDisplay = tx.initiatedBy || 'UNKNOWN';
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
content: [{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: `📜 **Payment Institution Transaction History**
|
|
157
|
+
|
|
158
|
+
**Transaction Information:**
|
|
159
|
+
- ID: ${tx.transactionId || transactionId}
|
|
160
|
+
- Type: ${typeDisplay}
|
|
161
|
+
- Initiated By: ${initiatorDisplay}
|
|
162
|
+
- Final Status: ${statusEmoji} ${tx.status || 'UNKNOWN'}
|
|
163
|
+
${tx.statusMessage ? `- Status Message: ${tx.statusMessage}` : ''}
|
|
164
|
+
- Created: ${createdDate}
|
|
165
|
+
- TTL: ${tx.timeToLive || 'N/A'} seconds
|
|
166
|
+
|
|
167
|
+
**Transaction Details:**
|
|
168
|
+
- Amount: ${tx.amount || 'N/A'} ${tx.currency || 'N/A'}
|
|
169
|
+
- Reason L1: ${tx.reasonL1 || 'N/A'}
|
|
170
|
+
${tx.reasonL2 ? `- Reason L2: ${tx.reasonL2}` : ''}
|
|
171
|
+
|
|
172
|
+
**Payee Information:**
|
|
173
|
+
- Account: ${tx.payeeAccount || 'N/A'}
|
|
174
|
+
- Friendly Name: ${tx.payeeFriendlyName || 'N/A'}
|
|
175
|
+
- BIC: ${tx.payeeBIC || 'N/A'}
|
|
176
|
+
|
|
177
|
+
**Payer Information:**
|
|
178
|
+
- Account: ${tx.payerAccount || 'N/A'}
|
|
179
|
+
- Friendly Name: ${tx.payerFriendlyName || 'N/A'}
|
|
180
|
+
- BIC: ${tx.payerBIC || 'N/A'}
|
|
181
|
+
|
|
182
|
+
**Full Transaction History:**
|
|
183
|
+
\`\`\`json
|
|
184
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
**API Call Details:**
|
|
188
|
+
- Endpoint: GET ${baseUrl}/transactions-history/${transactionId}
|
|
189
|
+
- Request ID: ${result.requestId || 'N/A'}
|
|
190
|
+
- Timestamp: ${result.timestamp}
|
|
191
|
+
|
|
192
|
+
**Transaction Outcome:**
|
|
193
|
+
${tx.status === 'CONFIRMED'
|
|
194
|
+
? `✅ **Transaction Completed Successfully**
|
|
195
|
+
- Payment was processed and confirmed
|
|
196
|
+
- Funds should have been transferred between accounts`
|
|
197
|
+
: tx.status === 'DECLINED'
|
|
198
|
+
? `❌ **Transaction Declined**
|
|
199
|
+
- Payment was declined by the payment institution
|
|
200
|
+
- Reason: ${tx.statusMessage || 'No specific reason provided'}`
|
|
201
|
+
: tx.status === 'FAILED'
|
|
202
|
+
? `💥 **Transaction Failed**
|
|
203
|
+
- Payment failed during processing
|
|
204
|
+
- Reason: ${tx.statusMessage || 'No specific reason provided'}`
|
|
205
|
+
: tx.status === 'EXPIRED'
|
|
206
|
+
? `⏰ **Transaction Expired**
|
|
207
|
+
- Transaction was not completed within the time limit
|
|
208
|
+
- No payment was processed`
|
|
209
|
+
: tx.status === 'CANCELLED'
|
|
210
|
+
? `🚫 **Transaction Cancelled**
|
|
211
|
+
- Transaction was cancelled by the creator
|
|
212
|
+
- Reason: ${tx.statusMessage || 'No specific reason provided'}`
|
|
213
|
+
: `📄 **Transaction Status: ${tx.status}**`
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
**⚠️ Historical Record:**
|
|
217
|
+
- This transaction is completed and cannot be modified
|
|
218
|
+
- Data is archived for audit and reconciliation purposes
|
|
219
|
+
- Use this information for financial reporting and analysis`
|
|
220
|
+
}]
|
|
221
|
+
};
|
|
222
|
+
} else {
|
|
223
|
+
return {
|
|
224
|
+
content: [{
|
|
225
|
+
type: "text",
|
|
226
|
+
text: `❌ **Transaction History Retrieval Failed**
|
|
227
|
+
|
|
228
|
+
**Transaction ID:** ${transactionId}
|
|
229
|
+
|
|
230
|
+
**Error Details:**
|
|
231
|
+
- Message: ${result.error.message}
|
|
232
|
+
- Status: ${result.error.status || 'N/A'}
|
|
233
|
+
- Code: ${result.error.code || 'N/A'}
|
|
234
|
+
|
|
235
|
+
**Full Error Response:**
|
|
236
|
+
\`\`\`json
|
|
237
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
238
|
+
\`\`\`
|
|
239
|
+
|
|
240
|
+
**Timestamp:** ${result.timestamp}
|
|
241
|
+
|
|
242
|
+
**Common Issues:**
|
|
243
|
+
1. **ERR_MISSING_TRANSACTION (404)**: Transaction not found in history
|
|
244
|
+
2. **HTTP 429 (Too Many Requests)**: API is throttled, implement retry logic
|
|
245
|
+
3. **Authentication Issues**: Verify JWT token and partner credentials
|
|
246
|
+
4. **Transaction Still Active**: Use \`payware_pi_get_transaction_status\` for active transactions
|
|
247
|
+
|
|
248
|
+
**Troubleshooting:**
|
|
249
|
+
1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
|
|
250
|
+
2. Check if transaction is still active (not yet completed/expired)
|
|
251
|
+
3. Implement retry logic for rate limiting (HTTP 429)
|
|
252
|
+
4. Verify your payment institution credentials and API access
|
|
253
|
+
5. Ensure transaction was created or you have access to it
|
|
254
|
+
|
|
255
|
+
**Rate Limiting Notes:**
|
|
256
|
+
- This endpoint is throttled by payware
|
|
257
|
+
- If you receive HTTP 429, wait and retry
|
|
258
|
+
- Consider implementing exponential backoff for retries
|
|
259
|
+
- Avoid excessive polling of this endpoint
|
|
260
|
+
|
|
261
|
+
**Alternative Actions:**
|
|
262
|
+
- If transaction is still active: Use \`payware_pi_get_transaction_status\`
|
|
263
|
+
- If rate limited: Wait and retry after a delay
|
|
264
|
+
- If transaction not found: Verify the transaction ID exists`
|
|
265
|
+
}]
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|