@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.
Files changed (106) hide show
  1. package/.env.example +92 -0
  2. package/MCP-SETUP.md +190 -0
  3. package/README.md +483 -0
  4. package/check-keys.js +52 -0
  5. package/keys/README.md +112 -0
  6. package/mcp-config.json +9 -0
  7. package/package.json +66 -0
  8. package/payware-mcp-config.json +12 -0
  9. package/src/auth/rsa-keys.js +82 -0
  10. package/src/auth/sandbox-setup.js +187 -0
  11. package/src/config/env.js +229 -0
  12. package/src/config/partner-types.js +143 -0
  13. package/src/core/auth/jwt-factory.js +182 -0
  14. package/src/core/auth/jwt-token.js +735 -0
  15. package/src/core/utils/json-serializer.js +100 -0
  16. package/src/core/utils/key-utils.js +133 -0
  17. package/src/index.js +237 -0
  18. package/src/isv/data/index.js +291 -0
  19. package/src/isv/deep-links/delete-product-link.js +154 -0
  20. package/src/isv/deep-links/delete-transaction-link.js +154 -0
  21. package/src/isv/deep-links/get-product-link.js +167 -0
  22. package/src/isv/deep-links/get-transaction-link.js +167 -0
  23. package/src/isv/deep-links/index.js +23 -0
  24. package/src/isv/index.js +103 -0
  25. package/src/isv/oauth2/create-token-simple.js +46 -0
  26. package/src/isv/oauth2/get-token-info.js +157 -0
  27. package/src/isv/oauth2/obtain-token.js +189 -0
  28. package/src/isv/oauth2/token-helper.js +151 -0
  29. package/src/isv/products/audios.js +470 -0
  30. package/src/isv/products/create-product.js +314 -0
  31. package/src/isv/products/delete-product.js +119 -0
  32. package/src/isv/products/get-product-image.js +247 -0
  33. package/src/isv/products/get-product.js +168 -0
  34. package/src/isv/products/index.js +65 -0
  35. package/src/isv/products/list-products.js +136 -0
  36. package/src/isv/products/schedules.js +522 -0
  37. package/src/isv/products/update-product.js +265 -0
  38. package/src/isv/transactions/cancel-transaction.js +129 -0
  39. package/src/isv/transactions/create-transaction.js +361 -0
  40. package/src/isv/transactions/get-status.js +217 -0
  41. package/src/isv/transactions/process-transaction.js +145 -0
  42. package/src/isv/transactions/simulate-callback.js +146 -0
  43. package/src/isv/transactions/transaction-history.js +186 -0
  44. package/src/isv/utils/auth.js +159 -0
  45. package/src/mcp-proxy.js +150 -0
  46. package/src/merchant/data/export-report.js +108 -0
  47. package/src/merchant/data/generate-report.js +151 -0
  48. package/src/merchant/data/get-report-status.js +120 -0
  49. package/src/merchant/data/index.js +351 -0
  50. package/src/merchant/deep-links/delete-product-link.js +121 -0
  51. package/src/merchant/deep-links/delete-transaction-link.js +121 -0
  52. package/src/merchant/deep-links/get-product-link.js +134 -0
  53. package/src/merchant/deep-links/get-transaction-link.js +134 -0
  54. package/src/merchant/deep-links/index.js +23 -0
  55. package/src/merchant/index.js +92 -0
  56. package/src/merchant/products/audios.js +606 -0
  57. package/src/merchant/products/create-product.js +288 -0
  58. package/src/merchant/products/delete-product.js +111 -0
  59. package/src/merchant/products/get-product-image.js +252 -0
  60. package/src/merchant/products/get-product.js +144 -0
  61. package/src/merchant/products/index.js +65 -0
  62. package/src/merchant/products/list-products.js +112 -0
  63. package/src/merchant/products/schedules.js +646 -0
  64. package/src/merchant/products/update-product.js +282 -0
  65. package/src/merchant/transactions/cancel-transaction.js +241 -0
  66. package/src/merchant/transactions/create-transaction.js +482 -0
  67. package/src/merchant/transactions/get-status.js +196 -0
  68. package/src/merchant/transactions/process-transaction.js +349 -0
  69. package/src/merchant/transactions/simulate-callback.js +246 -0
  70. package/src/merchant/transactions/transaction-history.js +258 -0
  71. package/src/payment-institution/data/index.js +280 -0
  72. package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
  73. package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
  74. package/src/payment-institution/deep-links/index.js +17 -0
  75. package/src/payment-institution/index.js +92 -0
  76. package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
  77. package/src/payment-institution/transactions/finalize-transaction.js +340 -0
  78. package/src/payment-institution/transactions/get-transaction-history.js +269 -0
  79. package/src/payment-institution/transactions/get-transaction-status.js +234 -0
  80. package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
  81. package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
  82. package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
  83. package/src/proxy-server.js +205 -0
  84. package/src/shared/data/data-api.js +372 -0
  85. package/src/shared/deep-links/api.js +214 -0
  86. package/src/shared/index.js +44 -0
  87. package/src/shared/products/products-api.js +872 -0
  88. package/src/tools/advanced-code-generator.js +2247 -0
  89. package/src/utils/code-examples/common/auth-examples.js +1482 -0
  90. package/src/utils/code-examples/common/helpers.js +416 -0
  91. package/src/utils/code-examples/common/utils-examples.js +591 -0
  92. package/src/utils/code-examples/frameworks/examples.js +859 -0
  93. package/src/utils/code-examples/index.js +441 -0
  94. package/src/utils/code-examples/isv/oauth2.js +600 -0
  95. package/src/utils/code-examples/isv/products.js +666 -0
  96. package/src/utils/code-examples/isv/transactions.js +813 -0
  97. package/src/utils/code-examples/merchant/products.js +497 -0
  98. package/src/utils/code-examples/merchant/transactions.js +623 -0
  99. package/src/utils/code-examples/payment-institution/transactions.js +388 -0
  100. package/src/utils/code-examples/shared/data.js +607 -0
  101. package/src/utils/code-examples/shared/deep-links.js +662 -0
  102. package/src/utils/code-examples/shared/soundbites.js +808 -0
  103. package/src/utils/code-examples.js +646 -0
  104. package/src/utils/format-request.js +363 -0
  105. package/src/utils/json-formatter.js +249 -0
  106. package/src/utils/server-info.js +132 -0
@@ -0,0 +1,482 @@
1
+ import axios from 'axios';
2
+ import { createJWTToken, generateContentMd5 } 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
+ * Create a transaction via payware API
8
+ * @param {Object} params - Transaction parameters
9
+ * @returns {Object} Transaction response
10
+ */
11
+ export async function createTransaction({
12
+ type = 'PLAIN',
13
+ amount,
14
+ currency = 'EUR',
15
+ reasonL1,
16
+ reasonL2,
17
+ callbackUrl,
18
+ account,
19
+ friendlyName,
20
+ shop,
21
+ timeToLive = 120,
22
+ partnerId,
23
+ privateKey,
24
+ passbackParams,
25
+ // QR Options
26
+ qrFormat,
27
+ qrBorder,
28
+ qrErrorCorrection,
29
+ qrScale,
30
+ qrVersion,
31
+ // Barcode Options
32
+ barFormat,
33
+ barModuleWidth,
34
+ barBarHeight,
35
+ barFontSize,
36
+ barHumanReadableLocation,
37
+ useSandbox = true
38
+ }) {
39
+ if (!reasonL1) {
40
+ throw new Error('reasonL1 is required (transaction grounds description)');
41
+ }
42
+
43
+ if (amount !== undefined && (typeof amount !== 'string' && typeof amount !== 'number')) {
44
+ throw new Error('Amount must be a string or number representing currency value (e.g., "25.50" or 25.50)');
45
+ }
46
+
47
+ if (amount !== undefined && parseFloat(amount) < 0) {
48
+ throw new Error('Amount must be non-negative');
49
+ }
50
+
51
+ if (!['PLAIN', 'QR', 'BARCODE'].includes(type)) {
52
+ throw new Error('Transaction type must be PLAIN, QR, or BARCODE');
53
+ }
54
+
55
+ if (!partnerId || !privateKey) {
56
+ throw new Error('Partner ID and private key are required for proper JWT creation');
57
+ }
58
+
59
+ // Build QR options if applicable
60
+ const qrOptions = {};
61
+ if (type === 'QR') {
62
+ if (qrFormat) qrOptions.qrFormat = qrFormat;
63
+ if (qrBorder !== undefined) qrOptions.qrBorder = qrBorder;
64
+ if (qrErrorCorrection) qrOptions.qrErrorCorrection = qrErrorCorrection;
65
+ if (qrScale) qrOptions.qrScale = qrScale;
66
+ if (qrVersion) qrOptions.qrVersion = qrVersion;
67
+ }
68
+
69
+ // Build barcode options if applicable
70
+ const barOptions = {};
71
+ if (type === 'BARCODE') {
72
+ if (barFormat) barOptions.barFormat = barFormat;
73
+ if (barModuleWidth) barOptions.barModuleWidth = barModuleWidth;
74
+ if (barBarHeight) barOptions.barBarHeight = barBarHeight;
75
+ if (barFontSize) barOptions.barFontSize = barFontSize;
76
+ if (barHumanReadableLocation) barOptions.barHumanReadableLocation = barHumanReadableLocation;
77
+ }
78
+
79
+ // Build request body according to documentation structure
80
+ const requestBody = {
81
+ ...(account && { account }),
82
+ ...(friendlyName && { friendlyName }),
83
+ ...(shop && { shop }),
84
+ ...(callbackUrl && { callbackUrl }),
85
+ ...(passbackParams && {
86
+ passbackParams: typeof passbackParams === 'string' ? passbackParams : JSON.stringify(passbackParams)
87
+ }),
88
+ trData: {
89
+ amount: amount !== undefined ? amount.toString() : '0.00',
90
+ currency,
91
+ reasonL1,
92
+ ...(reasonL2 && { reasonL2 })
93
+ },
94
+ trOptions: {
95
+ type,
96
+ timeToLive
97
+ },
98
+ ...(type === 'QR' && Object.keys(qrOptions).length > 0 && { qrOptions }),
99
+ ...(type === 'BARCODE' && Object.keys(barOptions).length > 0 && { barOptions })
100
+ };
101
+
102
+ // Convert to deterministic minimized JSON as required by payware API for MD5 calculation
103
+ const minimizedBodyString = createMinimizedJSON(requestBody);
104
+
105
+ // Create JWT token with contentMd5 for the request body (POST requires contentMd5)
106
+ const tokenData = createJWTToken(partnerId, privateKey, minimizedBodyString);
107
+
108
+ // Required headers as per payware API documentation
109
+ const headers = {
110
+ 'Authorization': `Bearer ${tokenData.token}`,
111
+ 'Content-Type': 'application/json',
112
+ 'Api-Version': '1' // Required: current API version
113
+ };
114
+
115
+ try {
116
+
117
+ // Send the exact minimized JSON string that was used for MD5 calculation
118
+ // This ensures the server calculates the same MD5 hash
119
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
120
+ const response = await axios.post(`${baseUrl}/transactions`, minimizedBodyString, {
121
+ headers,
122
+ // Tell axios to send the string as-is, don't serialize it again
123
+ transformRequest: [(data) => data]
124
+ });
125
+
126
+ return {
127
+ success: true,
128
+ transaction: response.data,
129
+ requestId: response.headers['x-request-id'],
130
+ timestamp: new Date().toISOString()
131
+ };
132
+ } catch (error) {
133
+ // Provide helpful error message for MD5 mismatches
134
+ let enhancedMessage = error.response?.data?.message || error.message;
135
+
136
+ if (error.response?.data?.code === 'ERR_INVALID_MD5' ||
137
+ enhancedMessage?.includes('MD5') ||
138
+ enhancedMessage?.includes('contentMd5')) {
139
+ enhancedMessage = `MD5 Mismatch Error: The contentMd5 in JWT header doesn't match the request body.
140
+
141
+ Cause: Different JSON strings were used for JWT contentMd5 calculation and HTTP body.
142
+ Solution: Ensure the EXACT same compact JSON string is used for both purposes.
143
+
144
+ Original error: ${enhancedMessage}`;
145
+ }
146
+
147
+ return {
148
+ success: false,
149
+ error: {
150
+ message: enhancedMessage,
151
+ status: error.response?.status,
152
+ code: error.response?.data?.code,
153
+ details: error.response?.data,
154
+ helpUrl: error.response?.data?.code === 'ERR_INVALID_MD5' ?
155
+ 'https://github.com/payware/mcp-server#md5-consistency' : undefined
156
+ },
157
+ timestamp: new Date().toISOString()
158
+ };
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Create transaction tool implementation
164
+ */
165
+ export const createTransactionTool = {
166
+ name: "payware_operations_create_transaction",
167
+ description: `Create a new payware transaction. Parameters map to the following API structure:
168
+
169
+ 📋 **ROOT LEVEL** (Transaction metadata):
170
+ - shop, account, friendlyName, callbackUrl, passbackParams
171
+
172
+ 💰 **TRANSACTION DATA** (trData object):
173
+ - amount, currency, reasonL1, reasonL2
174
+
175
+ ⚙️ **TRANSACTION OPTIONS** (trOptions object):
176
+ - type, timeToLive
177
+
178
+ 📱 **QR OPTIONS** (qrOptions object - only when type=QR):
179
+ - qrFormat, qrBorder, qrErrorCorrection, qrScale, qrVersion
180
+
181
+ 🔗 **BARCODE OPTIONS** (barOptions object - only when type=BARCODE):
182
+ - barFormat, barModuleWidth, barBarHeight, barFontSize, barHumanReadableLocation
183
+
184
+ 🔐 **AUTHENTICATION** (not sent to API, used for JWT signing):
185
+ - partnerId, privateKey
186
+
187
+ **Actual API Request Structure:**
188
+ \`\`\`json
189
+ {
190
+ "shop": "...",
191
+ "account": "...",
192
+ "friendlyName": "...",
193
+ "callbackUrl": "...",
194
+ "passbackParams": "...",
195
+ "trData": {
196
+ "amount": "25.50",
197
+ "currency": "EUR",
198
+ "reasonL1": "...",
199
+ "reasonL2": "..."
200
+ },
201
+ "trOptions": {
202
+ "type": "QR",
203
+ "timeToLive": 300
204
+ },
205
+ "qrOptions": { ... }
206
+ }
207
+ \`\`\``,
208
+ inputSchema: {
209
+ type: "object",
210
+ properties: {
211
+ type: {
212
+ type: "string",
213
+ enum: ["PLAIN", "QR", "BARCODE"],
214
+ description: "Transaction type"
215
+ },
216
+ amount: {
217
+ type: "number",
218
+ description: "Amount as currency value (e.g., 25.50 for €25.50 or '15.75' for $15.75). Can be 0 for amount-flexible transactions. Max 36 chars including decimals",
219
+ minimum: 0,
220
+ maximum: 9999999999999.99
221
+ },
222
+ currency: {
223
+ type: "string",
224
+ pattern: "^[A-Z]{3}$",
225
+ description: "Transaction currency (ISO 3-character code)"
226
+ },
227
+ reasonL1: {
228
+ type: "string",
229
+ description: "Transaction grounds description (required)",
230
+ maxLength: 100
231
+ },
232
+ reasonL2: {
233
+ type: "string",
234
+ description: "Transaction grounds description continuation (optional)",
235
+ maxLength: 100
236
+ },
237
+ account: {
238
+ type: "string",
239
+ description: "📋 ROOT LEVEL: Account identifier (if not supplied, determined from payware portal)",
240
+ maxLength: 36
241
+ },
242
+ friendlyName: {
243
+ type: "string",
244
+ description: "📋 ROOT LEVEL: Account holder recognizable name (if not supplied, merchant alias is used)",
245
+ maxLength: 100
246
+ },
247
+ shop: {
248
+ type: "string",
249
+ description: "📋 ROOT LEVEL: Shop code (if not supplied, default shop is used)",
250
+ maxLength: 10
251
+ },
252
+ timeToLive: {
253
+ type: "number",
254
+ description: "⚙️ TRANSACTION OPTIONS: Time allowed for payment initiation in seconds",
255
+ minimum: 60,
256
+ maximum: 600
257
+ },
258
+ callbackUrl: {
259
+ type: "string",
260
+ description: "📋 ROOT LEVEL: HTTPS URL to receive transaction status callbacks (must be https://)",
261
+ format: "uri"
262
+ },
263
+ partnerId: {
264
+ type: "string",
265
+ description: "🔐 AUTHENTICATION: Partner ID from payware dashboard (not sent in API request). Uses PAYWARE_PARTNER_ID env var as default."
266
+ },
267
+ privateKey: {
268
+ type: "string",
269
+ description: "🔐 AUTHENTICATION: RSA private key for JWT token creation (not sent in API request). Accepts PEM format with/without headers or raw base64 content. Uses environment-specific private key as default."
270
+ },
271
+ passbackParams: {
272
+ type: "string",
273
+ description: "📋 ROOT LEVEL: Additional parameters passed back in callbacks (max 200 chars)",
274
+ maxLength: 200
275
+ },
276
+ // QR Code Options
277
+ qrFormat: {
278
+ type: "string",
279
+ enum: ["PNG", "JPEG", "GIF", "BMP", "SVG"],
280
+ description: "📱 QR OPTIONS: Image format for QR code (only when type=QR, default: SVG)"
281
+ },
282
+ qrBorder: {
283
+ type: "number",
284
+ minimum: 1,
285
+ maximum: 10,
286
+ description: "📱 QR OPTIONS: Border size in modules around QR code (only when type=QR, default: 4)"
287
+ },
288
+ qrErrorCorrection: {
289
+ type: "string",
290
+ enum: ["LOW", "MEDIUM", "QUARTILE", "HIGH"],
291
+ description: "📱 QR OPTIONS: Error correction level - LOW (7%), MEDIUM (15%), QUARTILE (25%), HIGH (30%) (only when type=QR, default: QUARTILE)"
292
+ },
293
+ qrScale: {
294
+ type: "number",
295
+ minimum: 1,
296
+ maximum: 100,
297
+ description: "📱 QR OPTIONS: Size of each module in pixels, irrelevant for SVG (only when type=QR, default: 16)"
298
+ },
299
+ qrVersion: {
300
+ type: "number",
301
+ minimum: 1,
302
+ maximum: 40,
303
+ description: "📱 QR OPTIONS: QR code version, higher versions can store more data (only when type=QR, default: 10)"
304
+ },
305
+ // Barcode Options
306
+ barFormat: {
307
+ type: "string",
308
+ enum: ["PNG", "SVG", "JPG"],
309
+ description: "🔗 BARCODE OPTIONS: Image format for barcode (only when type=BARCODE, default: SVG)"
310
+ },
311
+ barModuleWidth: {
312
+ type: "number",
313
+ minimum: 1,
314
+ maximum: 5,
315
+ description: "Barcode module width in pixels (applies when type=BARCODE)"
316
+ },
317
+ barBarHeight: {
318
+ type: "number",
319
+ minimum: 10,
320
+ maximum: 200,
321
+ description: "Barcode height in pixels (applies when type=BARCODE)"
322
+ },
323
+ barFontSize: {
324
+ type: "number",
325
+ minimum: 8,
326
+ maximum: 24,
327
+ description: "Barcode text font size (applies when type=BARCODE)"
328
+ },
329
+ barHumanReadableLocation: {
330
+ type: "string",
331
+ enum: ["TOP", "BOTTOM", "NONE"],
332
+ description: "Location of human readable text (applies when type=BARCODE)"
333
+ },
334
+ useSandbox: {
335
+ type: "boolean",
336
+ description: "Use sandbox environment for testing"
337
+ }
338
+ },
339
+ required: ["currency", "reasonL1"],
340
+ additionalProperties: false
341
+ },
342
+
343
+ async handler(args) {
344
+ const {
345
+ type = 'PLAIN',
346
+ amount,
347
+ currency = 'EUR',
348
+ reasonL1,
349
+ reasonL2,
350
+ callbackUrl,
351
+ account,
352
+ friendlyName,
353
+ shop,
354
+ timeToLive = 120,
355
+ partnerId = getPartnerIdSafe(),
356
+ privateKey = getPrivateKeySafe(args.useSandbox ?? true),
357
+ passbackParams,
358
+ // QR Options
359
+ qrFormat,
360
+ qrBorder,
361
+ qrErrorCorrection,
362
+ qrScale,
363
+ qrVersion,
364
+ // Barcode Options
365
+ barFormat,
366
+ barModuleWidth,
367
+ barBarHeight,
368
+ barFontSize,
369
+ barHumanReadableLocation,
370
+ useSandbox = true
371
+ } = args;
372
+
373
+ if (!reasonL1) {
374
+ throw new Error("reasonL1 is required (transaction grounds description)");
375
+ }
376
+
377
+ if (!partnerId) {
378
+ throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
379
+ }
380
+
381
+ if (!privateKey) {
382
+ throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
383
+ }
384
+
385
+ const result = await createTransaction({
386
+ type,
387
+ amount,
388
+ currency,
389
+ reasonL1,
390
+ reasonL2,
391
+ callbackUrl,
392
+ account,
393
+ friendlyName,
394
+ shop,
395
+ timeToLive,
396
+ partnerId,
397
+ privateKey,
398
+ passbackParams,
399
+ // QR Options
400
+ qrFormat,
401
+ qrBorder,
402
+ qrErrorCorrection,
403
+ qrScale,
404
+ qrVersion,
405
+ // Barcode Options
406
+ barFormat,
407
+ barModuleWidth,
408
+ barBarHeight,
409
+ barFontSize,
410
+ barHumanReadableLocation,
411
+ useSandbox
412
+ });
413
+
414
+ if (result.success) {
415
+ // New transactions are always ACTIVE when created
416
+ const status = result.transaction.status || 'ACTIVE';
417
+ const statusEmoji = '⏳';
418
+
419
+ return {
420
+ content: [{
421
+ type: "text",
422
+ text: `💳 **Transaction Created Successfully**
423
+
424
+ **Transaction Details:**
425
+ - ID: ${result.transaction.transactionId || 'N/A'}
426
+ - Type: ${type}
427
+ - Status: ${statusEmoji} ${status}
428
+ - Amount: ${amount} ${currency}
429
+ - Description: ${reasonL1}${reasonL2 ? ` (${reasonL2})` : ''}
430
+ ${callbackUrl ? `- Callback URL: ${callbackUrl}` : ''}
431
+
432
+ **API Response:**
433
+ \`\`\`json
434
+ ${JSON.stringify(result.transaction, null, 2)}
435
+ \`\`\`
436
+
437
+ **API Call Details:**
438
+ - Endpoint: POST ${baseUrl}/transactions
439
+ - Response Status: ${result.transaction ? 'Success' : 'Failed'}
440
+ - Request ID: ${result.requestId || 'N/A'}
441
+ - Timestamp: ${result.timestamp}
442
+
443
+ **Next Steps:**
444
+ 1. Save the transaction ID: \`${result.transaction.transactionId || 'N/A'}\`
445
+ 2. Use \`payware_transactions_get_transaction_status\` to check status
446
+ 3. Wait for callback notification (if callback URL provided)
447
+ 4. Process payment through payware interface`
448
+ }]
449
+ };
450
+ } else {
451
+ return {
452
+ content: [{
453
+ type: "text",
454
+ text: `❌ **Transaction Creation Failed**
455
+
456
+ **Error Details:**
457
+ - Message: ${result.error.message}
458
+ - Status: ${result.error.status || 'N/A'}
459
+ - Code: ${result.error.code || 'N/A'}
460
+
461
+ **API Call Details:**
462
+ - Endpoint: POST ${baseUrl}/transactions
463
+ - Headers: Api-Version=1, Content-Type=application/json
464
+
465
+ **Full Error Response:**
466
+ \`\`\`json
467
+ ${JSON.stringify(result.error.details || result.error, null, 2)}
468
+ \`\`\`
469
+
470
+ **Timestamp:** ${result.timestamp}
471
+
472
+ **Troubleshooting:**
473
+ 1. Verify JWT token is valid and not expired
474
+ 2. Check transaction parameters (amount, type, currency)
475
+ 3. Ensure private key matches public key registered with payware
476
+ 4. Verify partner ID and API access
477
+ 5. Check sandbox API status`
478
+ }]
479
+ };
480
+ }
481
+ }
482
+ };
@@ -0,0 +1,196 @@
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 from payware API
7
+ * @param {Object} params - Parameters for status request
8
+ * @returns {Object} Transaction status response
9
+ */
10
+ export async function getTransactionStatus({ transactionId, partnerId, privateKey, useSandbox = true }) {
11
+ if (!transactionId) {
12
+ throw new Error('Transaction ID is required');
13
+ }
14
+
15
+ if (!partnerId || !privateKey) {
16
+ throw new Error('Partner ID and private key are required for proper JWT creation');
17
+ }
18
+
19
+ // Create JWT token without body (GET request - no contentMd5 required)
20
+ const tokenData = createJWTToken(partnerId, privateKey, null);
21
+
22
+ // Required headers as per payware API documentation
23
+ const headers = {
24
+ 'Authorization': `Bearer ${tokenData.token}`,
25
+ 'Content-Type': 'application/json',
26
+ 'Api-Version': '1' // Required: current API version
27
+ };
28
+
29
+ try {
30
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
31
+ const response = await axios.get(`${baseUrl}/transactions/${transactionId}`, { headers });
32
+
33
+ return {
34
+ success: true,
35
+ transaction: response.data,
36
+ requestId: response.headers['x-request-id'],
37
+ timestamp: new Date().toISOString()
38
+ };
39
+ } catch (error) {
40
+ return {
41
+ success: false,
42
+ error: {
43
+ message: error.response?.data?.message || error.message,
44
+ status: error.response?.status,
45
+ code: error.response?.data?.code,
46
+ details: error.response?.data
47
+ },
48
+ timestamp: new Date().toISOString()
49
+ };
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Format transaction status for display
55
+ */
56
+ function formatTransactionStatus(transaction) {
57
+ const statusEmojis = {
58
+ 'ACTIVE': '⏳'
59
+ };
60
+
61
+ // If a transaction is returned from GET /transactions/{id}, it's always ACTIVE
62
+ // (transactions with final statuses are only available via /transactions-history)
63
+ const status = transaction.status || 'ACTIVE';
64
+ const emoji = statusEmojis[status] || '⏳';
65
+
66
+ return {
67
+ emoji,
68
+ status,
69
+ formatted: `${emoji} ${status}`
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Get transaction status tool implementation
75
+ */
76
+ export const getTransactionStatusTool = {
77
+ name: "payware_operations_get_transaction_status",
78
+ description: `Get status of an ACTIVE transaction by ID (for completed/expired transactions use transaction history tool).
79
+
80
+ **Endpoint:** GET /transactions/{transactionId}
81
+ **Use Case:** Check status of ACTIVE transactions only. This endpoint only returns transactions with ACTIVE status.
82
+ **Note:** For transactions with final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED), use 'payware_transactions_get_history' instead.`,
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: {
86
+ transactionId: {
87
+ type: "string",
88
+ description: "Transaction ID to check status for"
89
+ },
90
+ partnerId: {
91
+ type: "string",
92
+ description: "Partner ID from payware dashboard. Can use 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. Can use PAYWARE_PRIVATE_KEY_PATH env var 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
+ additionalProperties: false
108
+ },
109
+
110
+ async handler(args) {
111
+ const { transactionId, partnerId = getPartnerIdSafe(), privateKey = getPrivateKeySafe(args.useSandbox ?? true), useSandbox = true } = args;
112
+
113
+ if (!transactionId) {
114
+ throw new Error("Transaction ID is required");
115
+ }
116
+
117
+ if (!partnerId) {
118
+ throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
119
+ }
120
+
121
+ if (!privateKey) {
122
+ throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
123
+ }
124
+
125
+ const result = await getTransactionStatus({ transactionId, partnerId, privateKey, useSandbox });
126
+
127
+ if (result.success) {
128
+ const statusInfo = formatTransactionStatus(result.transaction);
129
+
130
+ return {
131
+ content: [{
132
+ type: "text",
133
+ text: `📊 **Transaction Status Retrieved**
134
+
135
+ **Transaction:** ${transactionId}
136
+ **Status:** ${statusInfo.formatted}
137
+
138
+ **Transaction Details:**
139
+ - ID: ${result.transaction.id || 'N/A'}
140
+ - Type: ${result.transaction.type || 'N/A'}
141
+ - Amount: ${result.transaction.trData ? `${result.transaction.trData.amount} ${result.transaction.trData.currency}` : 'N/A'}
142
+ - Description: ${result.transaction.description || 'N/A'}
143
+ - Created: ${result.transaction.createdAt || 'N/A'}
144
+ - Updated: ${result.transaction.updatedAt || 'N/A'}
145
+
146
+ **Full Response:**
147
+ \`\`\`json
148
+ ${JSON.stringify(result.transaction, null, 2)}
149
+ \`\`\`
150
+
151
+ **Request ID:** ${result.requestId || 'N/A'}
152
+ **Timestamp:** ${result.timestamp}
153
+
154
+ **Status Meanings:**
155
+ - ⏳ ACTIVE: Active transaction pending processing or finalizing
156
+
157
+ **Note:** Only ACTIVE transactions are returned by this endpoint. For final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED), use the transaction history tool.`
158
+ }]
159
+ };
160
+ } else {
161
+ return {
162
+ content: [{
163
+ type: "text",
164
+ text: `❌ **Failed to Get Transaction Status**
165
+
166
+ **Transaction ID:** ${transactionId}
167
+
168
+ **Error Details:**
169
+ - Message: ${result.error.message}
170
+ - Status: ${result.error.status || 'N/A'}
171
+ - Code: ${result.error.code || 'N/A'}
172
+
173
+ **Full Error Response:**
174
+ \`\`\`json
175
+ ${JSON.stringify(result.error.details || result.error, null, 2)}
176
+ \`\`\`
177
+
178
+ **Timestamp:** ${result.timestamp}
179
+
180
+ **Possible Causes:**
181
+ 1. Transaction ID not found or invalid
182
+ 2. JWT token expired or invalid
183
+ 3. No access permission to this transaction
184
+ 4. API connectivity issues
185
+ 5. Transaction belongs to different partner
186
+
187
+ **Troubleshooting:**
188
+ 1. Verify the transaction ID is correct
189
+ 2. Check if JWT token is valid and not expired
190
+ 3. Ensure you have access to this transaction
191
+ 4. Try creating a new transaction if this one is very old`
192
+ }]
193
+ };
194
+ }
195
+ }
196
+ };