@payware/mcp-server 1.1.1 → 1.3.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 (127) hide show
  1. package/.env.example +0 -0
  2. package/README.md +22 -16
  3. package/check-keys.js +0 -0
  4. package/keys/README.md +0 -0
  5. package/mcp-config.json +0 -0
  6. package/package.json +69 -66
  7. package/payware-mcp-config.json +0 -0
  8. package/src/auth/rsa-keys.js +0 -0
  9. package/src/auth/sandbox-setup.js +186 -186
  10. package/src/config/env.js +0 -0
  11. package/src/config/partner-types.js +0 -0
  12. package/src/core/auth/jwt-factory.js +4 -4
  13. package/src/core/auth/jwt-token.js +107 -66
  14. package/src/core/utils/json-serializer.js +5 -5
  15. package/src/core/utils/key-utils.js +0 -0
  16. package/src/index.js +0 -0
  17. package/src/isv/data/index.js +0 -0
  18. package/src/isv/deep-links/delete-product-link.js +0 -0
  19. package/src/isv/deep-links/delete-transaction-link.js +0 -0
  20. package/src/isv/deep-links/get-product-link.js +0 -0
  21. package/src/isv/deep-links/get-transaction-link.js +0 -0
  22. package/src/isv/deep-links/index.js +0 -0
  23. package/src/isv/index.js +29 -1
  24. package/src/isv/invitations/index.js +471 -0
  25. package/src/isv/oauth2/create-token-simple.js +0 -0
  26. package/src/isv/oauth2/get-token-info.js +0 -0
  27. package/src/isv/oauth2/obtain-token.js +19 -8
  28. package/src/isv/oauth2/token-helper.js +5 -2
  29. package/src/isv/poi/cancel-price.js +2 -10
  30. package/src/isv/poi/create.js +19 -0
  31. package/src/isv/poi/get-poi.js +2 -10
  32. package/src/isv/poi/get-qrcode.js +2 -10
  33. package/src/isv/poi/get-status.js +2 -10
  34. package/src/isv/poi/index.js +5 -0
  35. package/src/isv/poi/list-pois.js +2 -10
  36. package/src/isv/poi/set-price.js +217 -225
  37. package/src/isv/products/audios.js +0 -0
  38. package/src/isv/products/create-product.js +313 -313
  39. package/src/isv/products/delete-product.js +0 -0
  40. package/src/isv/products/get-product-image.js +0 -0
  41. package/src/isv/products/get-product.js +0 -0
  42. package/src/isv/products/index.js +0 -0
  43. package/src/isv/products/list-products.js +0 -0
  44. package/src/isv/products/schedules.js +0 -0
  45. package/src/isv/products/update-product.js +264 -264
  46. package/src/isv/reference/index.js +249 -0
  47. package/src/isv/shops/index.js +22 -0
  48. package/src/isv/transactions/cancel-transaction.js +43 -12
  49. package/src/isv/transactions/create-transaction.js +22 -6
  50. package/src/isv/transactions/get-status.js +18 -11
  51. package/src/isv/transactions/process-transaction.js +160 -42
  52. package/src/isv/transactions/simulate-callback.js +128 -109
  53. package/src/isv/transactions/transaction-history.js +86 -90
  54. package/src/isv/utils/auth.js +2 -2
  55. package/src/mcp-proxy.js +0 -0
  56. package/src/merchant/data/export-report.js +0 -0
  57. package/src/merchant/data/generate-report.js +19 -1
  58. package/src/merchant/data/get-export-list.js +0 -0
  59. package/src/merchant/data/get-report-requests.js +0 -0
  60. package/src/merchant/data/get-report-status.js +0 -0
  61. package/src/merchant/data/index.js +0 -0
  62. package/src/merchant/data/list-reports.js +0 -0
  63. package/src/merchant/deep-links/delete-product-link.js +0 -0
  64. package/src/merchant/deep-links/delete-transaction-link.js +0 -0
  65. package/src/merchant/deep-links/get-product-link.js +0 -0
  66. package/src/merchant/deep-links/get-transaction-link.js +0 -0
  67. package/src/merchant/deep-links/index.js +0 -0
  68. package/src/merchant/index.js +21 -1
  69. package/src/merchant/logs/index.js +366 -0
  70. package/src/merchant/products/audios.js +0 -0
  71. package/src/merchant/products/create-product.js +287 -287
  72. package/src/merchant/products/delete-product.js +0 -0
  73. package/src/merchant/products/get-product-image.js +0 -0
  74. package/src/merchant/products/get-product.js +0 -0
  75. package/src/merchant/products/index.js +0 -0
  76. package/src/merchant/products/list-products.js +0 -0
  77. package/src/merchant/products/schedules.js +0 -0
  78. package/src/merchant/products/update-product.js +281 -281
  79. package/src/merchant/shops/index.js +18 -0
  80. package/src/merchant/transactions/cancel-transaction.js +16 -19
  81. package/src/merchant/transactions/create-transaction.js +99 -19
  82. package/src/merchant/transactions/get-status.js +41 -12
  83. package/src/merchant/transactions/process-transaction.js +8 -16
  84. package/src/merchant/transactions/simulate-callback.js +68 -9
  85. package/src/merchant/transactions/transaction-history.js +275 -257
  86. package/src/payment-institution/data/index.js +0 -0
  87. package/src/payment-institution/deep-links/delete-transaction-link.js +0 -0
  88. package/src/payment-institution/deep-links/get-transaction-link.js +0 -0
  89. package/src/payment-institution/deep-links/index.js +0 -0
  90. package/src/payment-institution/index.js +0 -0
  91. package/src/payment-institution/transactions/create-pi-transaction.js +6 -14
  92. package/src/payment-institution/transactions/finalize-transaction.js +333 -340
  93. package/src/payment-institution/transactions/get-transaction-history.js +3 -11
  94. package/src/payment-institution/transactions/get-transaction-status.js +39 -12
  95. package/src/payment-institution/transactions/process-pi-transaction.js +5 -13
  96. package/src/payment-institution/transactions/simulate-pi-callback.js +49 -9
  97. package/src/payment-institution/transactions/soundbite-transaction.js +5 -13
  98. package/src/proxy-server.js +0 -0
  99. package/src/shared/api-errors.js +188 -0
  100. package/src/shared/auth-headers.js +62 -0
  101. package/src/shared/data/data-api.js +11 -10
  102. package/src/shared/deep-links/api.js +5 -4
  103. package/src/shared/index.js +0 -0
  104. package/src/shared/logs/logs-api.js +242 -0
  105. package/src/shared/poi/poi-create-api.js +419 -0
  106. package/src/shared/products/products-api.js +17 -16
  107. package/src/shared/shops/shops-api.js +155 -0
  108. package/src/tools/advanced-code-generator.js +2255 -2246
  109. package/src/utils/code-examples/common/auth-examples.js +1484 -1481
  110. package/src/utils/code-examples/common/helpers.js +7 -4
  111. package/src/utils/code-examples/common/utils-examples.js +0 -0
  112. package/src/utils/code-examples/frameworks/examples.js +4 -4
  113. package/src/utils/code-examples/index.js +0 -0
  114. package/src/utils/code-examples/isv/oauth2.js +458 -600
  115. package/src/utils/code-examples/isv/products.js +8 -8
  116. package/src/utils/code-examples/isv/transactions.js +815 -812
  117. package/src/utils/code-examples/merchant/products.js +0 -0
  118. package/src/utils/code-examples/merchant/transactions.js +9 -9
  119. package/src/utils/code-examples/payment-institution/transactions.js +0 -0
  120. package/src/utils/code-examples/shared/data.js +0 -0
  121. package/src/utils/code-examples/shared/deep-links.js +0 -0
  122. package/src/utils/code-examples/shared/soundbites.js +0 -0
  123. package/src/utils/code-examples.js +24 -24
  124. package/src/utils/format-request.js +3 -3
  125. package/src/utils/json-formatter.js +20 -20
  126. package/src/utils/server-info.js +0 -0
  127. package/MCP-SETUP.md +0 -190
@@ -1,258 +1,276 @@
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 from payware API (for completed/expired transactions)
7
- * @param {Object} params - Parameters for history request
8
- * @returns {Object} Transaction history response
9
- */
10
- export async function getTransactionHistory({ 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-history/${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?.errorCode,
46
- details: error.response?.data,
47
- throttled: error.response?.status === 415
48
- },
49
- timestamp: new Date().toISOString()
50
- };
51
- }
52
- }
53
-
54
- /**
55
- * Format transaction history for display
56
- */
57
- function formatTransactionHistory(transaction) {
58
- const statusEmojis = {
59
- 'CONFIRMED': '✅',
60
- 'DECLINED': '❌',
61
- 'FAILED': '💥',
62
- 'CANCELLED': '🚫',
63
- 'EXPIRED': '⏰'
64
- };
65
-
66
- const typeEmojis = {
67
- 'DEFAULT': '💳',
68
- 'SHIPPABLE': '📦',
69
- 'VOUCHER': '🎫',
70
- 'CHEQUE': '📝'
71
- };
72
-
73
- const status = transaction.status || 'UNKNOWN';
74
- const type = transaction.transactionType || 'DEFAULT';
75
- const statusEmoji = statusEmojis[status] || '❓';
76
- const typeEmoji = typeEmojis[type] || '💳';
77
-
78
- return {
79
- statusEmoji,
80
- typeEmoji,
81
- status,
82
- type,
83
- formattedStatus: `${statusEmoji} ${status}`,
84
- formattedType: `${typeEmoji} ${type}`
85
- };
86
- }
87
-
88
- /**
89
- * Get transaction history tool implementation
90
- */
91
- export const getTransactionHistoryTool = {
92
- name: "payware_operations_get_transaction_history",
93
- description: `Get history of completed/finalized transactions with final statuses (throttled endpoint).
94
-
95
- **Endpoint:** GET /transactions-history/{transactionId}
96
- **Use Case:** Retrieve transactions with final statuses: CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED.
97
- **⚠️ THROTTLED:** This endpoint may return HTTP 415 Too Many Requests - implement retry logic.
98
- **Note:** For ACTIVE transactions, use 'payware_transactions_get_transaction_status' instead.`,
99
- inputSchema: {
100
- type: "object",
101
- properties: {
102
- transactionId: {
103
- type: "string",
104
- description: "Transaction ID to get history for. Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
105
- pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
106
- },
107
- partnerId: {
108
- type: "string",
109
- description: "Partner ID from payware dashboard. Can use PAYWARE_PARTNER_ID env var as default.",
110
- default: getPartnerIdSafe()
111
- },
112
- privateKey: {
113
- type: "string",
114
- description: "RSA private key for JWT token creation. Can use PAYWARE_PRIVATE_KEY_PATH env var as default.",
115
- default: getPrivateKeySafe()
116
- },
117
- useSandbox: {
118
- type: "boolean",
119
- description: "Use sandbox environment for testing",
120
- default: true
121
- }
122
- },
123
- required: ["transactionId"],
124
- additionalProperties: false
125
- },
126
-
127
- async handler(args) {
128
- const { transactionId, partnerId = getPartnerIdSafe(), privateKey = getPrivateKeySafe(args.useSandbox ?? true), useSandbox = true } = args;
129
-
130
- if (!transactionId) {
131
- throw new Error("Transaction ID is required");
132
- }
133
-
134
- if (!partnerId) {
135
- throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
136
- }
137
-
138
- if (!privateKey) {
139
- throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
140
- }
141
-
142
- const result = await getTransactionHistory({ transactionId, partnerId, privateKey, useSandbox });
143
-
144
- if (result.success) {
145
- const formatInfo = formatTransactionHistory(result.transaction);
146
-
147
- // Format dates
148
- const created = result.transaction.created ? new Date(result.transaction.created * 1000).toISOString() : 'N/A';
149
- const finalized = result.transaction.finalized ? new Date(result.transaction.finalized * 1000).toISOString() : 'N/A';
150
-
151
- return {
152
- content: [{
153
- type: "text",
154
- text: `📊 **Transaction History Retrieved**
155
-
156
- **Transaction:** ${transactionId}
157
- **Type:** ${formatInfo.formattedType}
158
- **Status:** ${formatInfo.formattedStatus}
159
-
160
- **Transaction Details:**
161
- - ID: ${result.transaction.transactionId || 'N/A'}
162
- - Initiated By: ${result.transaction.initiatedBy || 'N/A'}
163
- - Amount: ${result.transaction.amount ? `${result.transaction.amount} ${result.transaction.currency}` : 'N/A'}
164
- ${result.transaction.paymentMethod ? `- Payment Method: ${result.transaction.paymentMethod}\n` : ''}- Reason: ${result.transaction.reasonL1 || 'N/A'}${result.transaction.reasonL2 ? ` (${result.transaction.reasonL2})` : ''}
165
-
166
- **Parties:**
167
- - Payee: ${result.transaction.payeeFriendlyName || 'N/A'} (${result.transaction.payeeAccount || 'N/A'})
168
- - Payer: ${result.transaction.payerFriendlyName || 'N/A'} (${result.transaction.payerAccount || 'N/A'})
169
- - Payee BIC: ${result.transaction.payeeBIC || 'N/A'}
170
- - Payer BIC: ${result.transaction.payerBIC || 'N/A'}
171
-
172
- **Timeline:**
173
- - Created: ${created}
174
- - Finalized: ${finalized}
175
- - Time to Live: ${result.transaction.timeToLive || 'N/A'} seconds
176
-
177
- **Status Information:**
178
- ${result.transaction.status ? `- Final Status: ${formatInfo.formattedStatus}` : ''}
179
- ${result.transaction.statusMessage ? `- Status Message: ${result.transaction.statusMessage}` : ''}
180
-
181
- ${result.transaction.deliveryAddress ? `
182
- **Delivery Address:**
183
- - Name: ${result.transaction.deliveryAddress.fullName || 'N/A'}
184
- - Address: ${result.transaction.deliveryAddress.streetAddressLine1 || 'N/A'}
185
- ${result.transaction.deliveryAddress.streetAddressLine2 ? ` ${result.transaction.deliveryAddress.streetAddressLine2}` : ''}
186
- - City: ${result.transaction.deliveryAddress.city || 'N/A'}, ${result.transaction.deliveryAddress.zipCode || 'N/A'}
187
- - Region: ${result.transaction.deliveryAddress.region || 'N/A'}
188
- - Country: ${result.transaction.deliveryAddress.country || 'N/A'}
189
- - Phone: ${result.transaction.deliveryAddress.phoneNumber || 'N/A'}
190
- - Email: ${result.transaction.deliveryAddress.email || 'N/A'}
191
- ` : ''}
192
-
193
- **Full Response:**
194
- \`\`\`json
195
- ${JSON.stringify(result.transaction, null, 2)}
196
- \`\`\`
197
-
198
- **Request ID:** ${result.requestId || 'N/A'}
199
- **Timestamp:** ${result.timestamp}
200
-
201
- **Status Meanings:**
202
- - ✅ CONFIRMED: Successfully finalized
203
- - ❌ DECLINED: Declined by the user, processing or finalizing payment institutions
204
- - 💥 FAILED: Failed due to technical reasons or other
205
- - 🚫 CANCELLED: Transaction canceled by the originator
206
- - ⏰ EXPIRED: Time to live of the transaction has passed
207
-
208
- **Note:** This endpoint is throttled and only returns transactions with final statuses. ACTIVE transactions cannot be retrieved here.`
209
- }]
210
- };
211
- } else {
212
- let errorText = `❌ **Failed to Get Transaction History**
213
-
214
- **Transaction ID:** ${transactionId}
215
-
216
- **Error Details:**
217
- - Message: ${result.error.message}
218
- - Status: ${result.error.status || 'N/A'}
219
- - Code: ${result.error.code || 'N/A'}`;
220
-
221
- if (result.error.throttled) {
222
- errorText += `
223
-
224
- **⚠️ THROTTLED REQUEST**
225
- This endpoint has rate limiting. You've made too many requests recently.
226
- Please wait before trying again.`;
227
- }
228
-
229
- errorText += `
230
-
231
- **Full Error Response:**
232
- \`\`\`json
233
- ${JSON.stringify(result.error.details || result.error, null, 2)}
234
- \`\`\`
235
-
236
- **Timestamp:** ${result.timestamp}
237
-
238
- **Common Issues:**
239
- 1. **ERR_MISSING_TRANSACTION**: Transaction ID not found
240
- 2. **Too Many Requests (415)**: API rate limit exceeded
241
- 3. **ERR_METHOD_NOT_ALLOWED**: HTTP method issue
242
-
243
- **Troubleshooting:**
244
- 1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
245
- 2. Ensure transaction exists and you have access to it
246
- 3. If getting rate limit errors, wait 60 seconds before retrying
247
- 4. For ACTIVE transactions, use 'payware_transactions_get_transaction_status' instead
248
- 5. This endpoint only returns transactions with final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED)`;
249
-
250
- return {
251
- content: [{
252
- type: "text",
253
- text: errorText
254
- }]
255
- };
256
- }
257
- }
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
+ import { apiErrorResult } from '../../shared/api-errors.js';
5
+
6
+ /**
7
+ * Get transaction history from payware API (for completed/expired transactions)
8
+ * @param {Object} params - Parameters for history request
9
+ * @returns {Object} Transaction history response
10
+ */
11
+ export async function getTransactionHistory({ transactionId, partnerId, privateKey, useSandbox = true }) {
12
+ if (!transactionId) {
13
+ throw new Error('Transaction ID is required');
14
+ }
15
+
16
+ if (!partnerId || !privateKey) {
17
+ throw new Error('Partner ID and private key are required for proper JWT creation');
18
+ }
19
+
20
+ // Create JWT token without body (GET request - no contentSha256 required)
21
+ const tokenData = createJWTToken(partnerId, privateKey, null);
22
+
23
+ // Required headers as per payware API documentation
24
+ const headers = {
25
+ 'Authorization': `Bearer ${tokenData.token}`,
26
+ 'Content-Type': 'application/json',
27
+ 'Api-Version': '1' // Required: current API version
28
+ };
29
+
30
+ try {
31
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
32
+ const response = await axios.get(`${baseUrl}/transactions-history/${transactionId}`, { headers });
33
+
34
+ return {
35
+ success: true,
36
+ transaction: response.data,
37
+ requestId: response.headers['x-request-id'],
38
+ timestamp: new Date().toISOString()
39
+ };
40
+ } catch (error) {
41
+ const result = apiErrorResult(error);
42
+ // 429, not 415. The server's rate limiter answers TOO_MANY_REQUESTS
43
+ // (PartnerApiRateLimitFilter); 415 is an unsupported content type, which retrying can never
44
+ // fix. Labelling a genuine 415 "throttled" told integrators to retry a request that is
45
+ // permanently malformed, while a real throttle was reported as a hard failure.
46
+ //
47
+ // Kept as its own flag on top of apiErrorResult's `retryable`: `throttled` says specifically
48
+ // "slow down", where `retryable` is also true for a 503, which means "payware is missing
49
+ // configuration" and calls for a different response. apiErrorResult supplies retryAfterSeconds.
50
+ result.error.throttled = error.response?.status === 429;
51
+ return result;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Format transaction history for display
57
+ */
58
+ function formatTransactionHistory(transaction) {
59
+ const statusEmojis = {
60
+ 'CONFIRMED': '✅',
61
+ 'DECLINED': '❌',
62
+ 'FAILED': '💥',
63
+ 'CANCELLED': '🚫',
64
+ 'EXPIRED': '⏰'
65
+ };
66
+
67
+ const typeEmojis = {
68
+ 'DEFAULT': '💳',
69
+ 'SHIPPABLE': '📦',
70
+ 'VOUCHER': '🎫',
71
+ 'CHEQUE': '📝'
72
+ };
73
+
74
+ const status = transaction.status || 'UNKNOWN';
75
+ const type = transaction.transactionType || 'DEFAULT';
76
+ const statusEmoji = statusEmojis[status] || '❓';
77
+ const typeEmoji = typeEmojis[type] || '💳';
78
+
79
+ return {
80
+ statusEmoji,
81
+ typeEmoji,
82
+ status,
83
+ type,
84
+ formattedStatus: `${statusEmoji} ${status}`,
85
+ formattedType: `${typeEmoji} ${type}`
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Get transaction history tool implementation
91
+ */
92
+ export const getTransactionHistoryTool = {
93
+ name: "payware_operations_get_transaction_history",
94
+ description: `Get history of completed/finalized transactions with final statuses.
95
+
96
+ **Endpoint:** GET /transactions-history/{transactionId}
97
+ **Use Case:** Retrieve transactions with final statuses: CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED.
98
+ **Note:** For ACTIVE transactions, use 'payware_transactions_get_transaction_status' instead.
99
+
100
+ 📦 **This is where the delivery address lives.** For a SHIPPABLE transaction, \`deliveryAddress\`
101
+ (fullName, streetAddressLine1/2, zipCode, city, region, country, phoneNumber, email) is returned
102
+ here and **only** here. It was removed from the finalized callback on 2026-08-07: a callback is
103
+ delivered to whatever certificate the merchant's endpoint happens to present, which is an acceptable
104
+ trade for a transaction id and an amount and not one for a shopper's home address. This endpoint is
105
+ JWT-authenticated, tenant-scoped and runs over a verified channel. So the pattern is: the callback
106
+ tells you the shipment is ready, and this call gives you the address to ship to.
107
+
108
+ ⚠️ **Requires Standard or Premium.** This endpoint was ungated until 2026-08-21 and is now on the
109
+ same plan gate as the rest of the transaction surface, so a **Basic** merchant - or an ISV acting on
110
+ behalf of one - now gets **403**. If reading history started failing without a code change, this is
111
+ why. Financial institutions are unaffected; banks are always Premium.
112
+
113
+ ⏱️ **Rate limited, like every payware endpoint.** A 429 carries \`ERR_RATE_LIMIT_EXCEEDED\` and a
114
+ \`Retry-After\` header, in seconds; the request was not processed, so the identical request is safe to
115
+ retry once the window passes. The failure result exposes this as \`error.throttled\`,
116
+ \`error.retryable\` and \`error.retryAfterSeconds\`.`,
117
+ inputSchema: {
118
+ type: "object",
119
+ properties: {
120
+ transactionId: {
121
+ type: "string",
122
+ description: "Transaction ID to get history for. Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
123
+ pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
124
+ },
125
+ partnerId: {
126
+ type: "string",
127
+ description: "Partner ID from payware dashboard. Can use PAYWARE_PARTNER_ID env var as default.",
128
+ default: getPartnerIdSafe()
129
+ },
130
+ privateKey: {
131
+ type: "string",
132
+ description: "RSA private key for JWT token creation. Can use PAYWARE_PRIVATE_KEY_PATH env var as default.",
133
+ default: getPrivateKeySafe()
134
+ },
135
+ useSandbox: {
136
+ type: "boolean",
137
+ description: "Use sandbox environment for testing",
138
+ default: true
139
+ }
140
+ },
141
+ required: ["transactionId"],
142
+ additionalProperties: false
143
+ },
144
+
145
+ async handler(args) {
146
+ const { transactionId, partnerId = getPartnerIdSafe(), privateKey = getPrivateKeySafe(args.useSandbox ?? true), useSandbox = true } = args;
147
+
148
+ if (!transactionId) {
149
+ throw new Error("Transaction ID is required");
150
+ }
151
+
152
+ if (!partnerId) {
153
+ throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
154
+ }
155
+
156
+ if (!privateKey) {
157
+ throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
158
+ }
159
+
160
+ const result = await getTransactionHistory({ transactionId, partnerId, privateKey, useSandbox });
161
+
162
+ if (result.success) {
163
+ const formatInfo = formatTransactionHistory(result.transaction);
164
+
165
+ // Format dates
166
+ const created = result.transaction.created ? new Date(result.transaction.created * 1000).toISOString() : 'N/A';
167
+ const finalized = result.transaction.finalized ? new Date(result.transaction.finalized * 1000).toISOString() : 'N/A';
168
+
169
+ return {
170
+ content: [{
171
+ type: "text",
172
+ text: `📊 **Transaction History Retrieved**
173
+
174
+ **Transaction:** ${transactionId}
175
+ **Type:** ${formatInfo.formattedType}
176
+ **Status:** ${formatInfo.formattedStatus}
177
+
178
+ **Transaction Details:**
179
+ - ID: ${result.transaction.transactionId || 'N/A'}
180
+ - Initiated By: ${result.transaction.initiatedBy || 'N/A'}
181
+ - Amount: ${result.transaction.amount ? `${result.transaction.amount} ${result.transaction.currency}` : 'N/A'}
182
+ ${result.transaction.paymentMethod ? `- Payment Method: ${result.transaction.paymentMethod}\n` : ''}- Reason: ${result.transaction.reasonL1 || 'N/A'}${result.transaction.reasonL2 ? ` (${result.transaction.reasonL2})` : ''}
183
+
184
+ **Parties:**
185
+ - Payee: ${result.transaction.payeeFriendlyName || 'N/A'} (${result.transaction.payeeAccount || 'N/A'})
186
+ - Payer: ${result.transaction.payerFriendlyName || 'N/A'} (${result.transaction.payerAccount || 'N/A'})
187
+ - Payee BIC: ${result.transaction.payeeBIC || 'N/A'}
188
+ - Payer BIC: ${result.transaction.payerBIC || 'N/A'}
189
+
190
+ **Timeline:**
191
+ - Created: ${created}
192
+ - Finalized: ${finalized}
193
+ - Time to Live: ${result.transaction.timeToLive || 'N/A'} seconds
194
+
195
+ **Status Information:**
196
+ ${result.transaction.status ? `- Final Status: ${formatInfo.formattedStatus}` : ''}
197
+ ${result.transaction.statusMessage ? `- Status Message: ${result.transaction.statusMessage}` : ''}
198
+
199
+ ${result.transaction.deliveryAddress ? `
200
+ **Delivery Address:**
201
+ - Name: ${result.transaction.deliveryAddress.fullName || 'N/A'}
202
+ - Address: ${result.transaction.deliveryAddress.streetAddressLine1 || 'N/A'}
203
+ ${result.transaction.deliveryAddress.streetAddressLine2 ? ` ${result.transaction.deliveryAddress.streetAddressLine2}` : ''}
204
+ - City: ${result.transaction.deliveryAddress.city || 'N/A'}, ${result.transaction.deliveryAddress.zipCode || 'N/A'}
205
+ - Region: ${result.transaction.deliveryAddress.region || 'N/A'}
206
+ - Country: ${result.transaction.deliveryAddress.country || 'N/A'}
207
+ - Phone: ${result.transaction.deliveryAddress.phoneNumber || 'N/A'}
208
+ - Email: ${result.transaction.deliveryAddress.email || 'N/A'}
209
+ ` : ''}
210
+
211
+ **Full Response:**
212
+ \`\`\`json
213
+ ${JSON.stringify(result.transaction, null, 2)}
214
+ \`\`\`
215
+
216
+ **Request ID:** ${result.requestId || 'N/A'}
217
+ **Timestamp:** ${result.timestamp}
218
+
219
+ **Status Meanings:**
220
+ - ✅ CONFIRMED: Successfully finalized
221
+ - ❌ DECLINED: Declined by the user, processing or finalizing payment institutions
222
+ - 💥 FAILED: Failed due to technical reasons or other
223
+ - 🚫 CANCELLED: Transaction canceled by the originator
224
+ - ⏰ EXPIRED: Time to live of the transaction has passed
225
+
226
+ **Note:** This endpoint is throttled and only returns transactions with final statuses. ACTIVE transactions cannot be retrieved here.`
227
+ }]
228
+ };
229
+ } else {
230
+ let errorText = `❌ **Failed to Get Transaction History**
231
+
232
+ **Transaction ID:** ${transactionId}
233
+
234
+ **Error Details:**
235
+ - Message: ${result.error.message}
236
+ - Status: ${result.error.status || 'N/A'}
237
+ - Code: ${result.error.code || 'N/A'}`;
238
+
239
+ if (result.error.throttled) {
240
+ errorText += `
241
+
242
+ **⚠️ THROTTLED REQUEST**
243
+ This endpoint has rate limiting. You've made too many requests recently.
244
+ Please wait before trying again.`;
245
+ }
246
+
247
+ errorText += `
248
+
249
+ **Full Error Response:**
250
+ \`\`\`json
251
+ ${JSON.stringify(result.error.details || result.error, null, 2)}
252
+ \`\`\`
253
+
254
+ **Timestamp:** ${result.timestamp}
255
+
256
+ **Common Issues:**
257
+ 1. **ERR_MISSING_TRANSACTION**: Transaction ID not found
258
+ 2. **Too Many Requests (429)**: API rate limit exceeded
259
+ 3. **ERR_METHOD_NOT_ALLOWED**: HTTP method issue
260
+
261
+ **Troubleshooting:**
262
+ 1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
263
+ 2. Ensure transaction exists and you have access to it
264
+ 3. If getting rate limit errors, wait 60 seconds before retrying
265
+ 4. For ACTIVE transactions, use 'payware_transactions_get_transaction_status' instead
266
+ 5. This endpoint only returns transactions with final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED)`;
267
+
268
+ return {
269
+ content: [{
270
+ type: "text",
271
+ text: errorText
272
+ }]
273
+ };
274
+ }
275
+ }
258
276
  };
File without changes
File without changes
File without changes
@@ -2,6 +2,7 @@ import axios from 'axios';
2
2
  import { createJWTToken } from '../../core/auth/jwt-token.js';
3
3
  import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
4
4
  import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
5
+ import { apiErrorResult } from '../../shared/api-errors.js';
5
6
 
6
7
  /**
7
8
  * Create a payment institution transaction via payware API
@@ -110,10 +111,10 @@ export async function createPITransaction({
110
111
  ...(type === 'BARCODE' && Object.keys(barOptions).length > 0 && { barOptions })
111
112
  };
112
113
 
113
- // Convert to deterministic minimized JSON as required by payware API for MD5 calculation
114
+ // Convert to deterministic minimized JSON as required by payware API for SHA-256 calculation
114
115
  const minimizedBodyString = createMinimizedJSON(requestBody);
115
116
 
116
- // Create JWT token with contentMd5 for the request body (POST requires contentMd5)
117
+ // Create JWT token with contentSha256 for the request body (POST requires contentSha256)
117
118
  const tokenData = createJWTToken(partnerId, privateKey, minimizedBodyString);
118
119
 
119
120
  // Required headers as per payware API documentation
@@ -125,8 +126,8 @@ export async function createPITransaction({
125
126
 
126
127
  try {
127
128
  const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
128
- // Send the exact minimized JSON string that was used for MD5 calculation
129
- // This ensures the server calculates the same MD5 hash
129
+ // Send the exact minimized JSON string that was used for SHA-256 calculation
130
+ // This ensures the server calculates the same SHA-256 hash
130
131
  const response = await axios.post(`${baseUrl}/transactions`, minimizedBodyString, {
131
132
  headers,
132
133
  // Tell axios to send the string as-is, don't serialize it again
@@ -140,16 +141,7 @@ export async function createPITransaction({
140
141
  timestamp: new Date().toISOString()
141
142
  };
142
143
  } catch (error) {
143
- return {
144
- success: false,
145
- error: {
146
- message: error.response?.data?.message || error.message,
147
- status: error.response?.status,
148
- code: error.response?.data?.code,
149
- details: error.response?.data
150
- },
151
- timestamp: new Date().toISOString()
152
- };
144
+ return apiErrorResult(error);
153
145
  }
154
146
  }
155
147