@payware/mcp-server 1.2.0 β†’ 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 (58) hide show
  1. package/README.md +5 -0
  2. package/package.json +69 -66
  3. package/src/auth/sandbox-setup.js +186 -186
  4. package/src/isv/index.js +29 -1
  5. package/src/isv/invitations/index.js +471 -0
  6. package/src/isv/oauth2/obtain-token.js +19 -8
  7. package/src/isv/oauth2/token-helper.js +5 -2
  8. package/src/isv/poi/cancel-price.js +2 -10
  9. package/src/isv/poi/create.js +19 -0
  10. package/src/isv/poi/get-poi.js +2 -10
  11. package/src/isv/poi/get-qrcode.js +2 -10
  12. package/src/isv/poi/get-status.js +2 -10
  13. package/src/isv/poi/index.js +5 -0
  14. package/src/isv/poi/list-pois.js +2 -10
  15. package/src/isv/poi/set-price.js +217 -225
  16. package/src/isv/products/create-product.js +313 -313
  17. package/src/isv/products/update-product.js +264 -264
  18. package/src/isv/reference/index.js +249 -0
  19. package/src/isv/shops/index.js +22 -0
  20. package/src/isv/transactions/cancel-transaction.js +41 -10
  21. package/src/isv/transactions/create-transaction.js +20 -4
  22. package/src/isv/transactions/get-status.js +18 -11
  23. package/src/isv/transactions/process-transaction.js +160 -42
  24. package/src/isv/transactions/simulate-callback.js +128 -109
  25. package/src/isv/transactions/transaction-history.js +86 -90
  26. package/src/merchant/data/generate-report.js +19 -1
  27. package/src/merchant/index.js +21 -1
  28. package/src/merchant/logs/index.js +366 -0
  29. package/src/merchant/products/create-product.js +287 -287
  30. package/src/merchant/products/update-product.js +281 -281
  31. package/src/merchant/shops/index.js +18 -0
  32. package/src/merchant/transactions/cancel-transaction.js +10 -13
  33. package/src/merchant/transactions/create-transaction.js +88 -8
  34. package/src/merchant/transactions/get-status.js +40 -11
  35. package/src/merchant/transactions/process-transaction.js +2 -10
  36. package/src/merchant/transactions/simulate-callback.js +68 -9
  37. package/src/merchant/transactions/transaction-history.js +275 -257
  38. package/src/payment-institution/transactions/create-pi-transaction.js +2 -10
  39. package/src/payment-institution/transactions/finalize-transaction.js +333 -340
  40. package/src/payment-institution/transactions/get-transaction-history.js +2 -10
  41. package/src/payment-institution/transactions/get-transaction-status.js +38 -11
  42. package/src/payment-institution/transactions/process-pi-transaction.js +2 -10
  43. package/src/payment-institution/transactions/simulate-pi-callback.js +49 -9
  44. package/src/payment-institution/transactions/soundbite-transaction.js +2 -10
  45. package/src/shared/api-errors.js +188 -0
  46. package/src/shared/auth-headers.js +62 -0
  47. package/src/shared/data/data-api.js +11 -10
  48. package/src/shared/deep-links/api.js +5 -4
  49. package/src/shared/logs/logs-api.js +242 -0
  50. package/src/shared/poi/poi-create-api.js +419 -0
  51. package/src/shared/products/products-api.js +17 -16
  52. package/src/shared/shops/shops-api.js +155 -0
  53. package/src/tools/advanced-code-generator.js +2255 -2246
  54. package/src/utils/code-examples/common/auth-examples.js +1484 -1481
  55. package/src/utils/code-examples/common/helpers.js +7 -4
  56. package/src/utils/code-examples/isv/oauth2.js +458 -600
  57. package/src/utils/code-examples/isv/transactions.js +815 -812
  58. package/MCP-SETUP.md +0 -190
@@ -1,282 +1,282 @@
1
- import { updateProduct } from '../../shared/products/products-api.js';
2
- import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
3
- import { PRODUCT_TYPES, OVERLAP_PRIORITY } from '../../shared/products/products-api.js';
4
-
5
- /**
6
- * Update product tool implementation for merchants
7
- */
8
- export const updateProductTool = {
9
- name: "payware_products_update_product",
10
- description: `Update an existing product. Only provide the fields you want to change.
11
-
12
- **Product Structure:**
13
- πŸ“¦ **PRODUCT METADATA**: name, shortDescription, longDescription, sku, upc, shippable, active, shop
14
- πŸ’° **PRODUCT DATA** (prData object): type, regularPrice, currency, overlapPriority, timeToLive, activeFrom, activeTo, timeZone
15
- βš™οΈ **PRODUCT OPTIONS** (prOptions object): imageUrl, termsUrl, termsText`,
16
-
17
- inputSchema: {
18
- type: "object",
19
- properties: {
20
- productId: {
21
- type: "string",
22
- description: "Product identifier to update (starts with 'pr')",
23
- pattern: "^pr[a-zA-Z0-9]+$"
24
- },
25
- name: {
26
- type: "string",
27
- description: "Product recognizable name",
28
- maxLength: 50
29
- },
30
- shortDescription: {
31
- type: "string",
32
- description: "Short product description",
33
- maxLength: 150
34
- },
35
- longDescription: {
36
- type: "string",
37
- description: "Long product description",
38
- maxLength: 1500
39
- },
40
- sku: {
41
- type: "string",
42
- description: "Stock Keeping Unit (SKU)",
43
- maxLength: 25
44
- },
45
- upc: {
46
- type: "string",
47
- description: "Universal Product Code (UPC)",
48
- maxLength: 15
49
- },
50
- shippable: {
51
- type: "string",
52
- enum: ["TRUE", "FALSE"],
53
- description: "Indicates if product requires delivery address"
54
- },
55
- active: {
56
- type: "string",
57
- enum: ["TRUE", "FALSE"],
58
- description: "Indicates if product can serve as payment source"
59
- },
60
- shop: {
61
- type: "string",
62
- description: "Shop code",
63
- maxLength: 10
64
- },
65
- // Product Data Properties
66
- productType: {
67
- type: "string",
68
- enum: Object.values(PRODUCT_TYPES),
69
- description: "Type of product"
70
- },
71
- regularPrice: {
72
- type: "string",
73
- description: "Product regular price (positive number with max 2 decimals)"
74
- },
75
- currency: {
76
- type: "string",
77
- pattern: "^[A-Z]{3}$",
78
- description: "Price currency (3-character ISO code)"
79
- },
80
- overlapPriority: {
81
- type: "string",
82
- enum: Object.values(OVERLAP_PRIORITY),
83
- description: "Priority when overlapping price schedules exist"
84
- },
85
- timeToLive: {
86
- type: "number",
87
- description: "Time allowed for product payment in seconds (60-2592000)",
88
- minimum: 60,
89
- maximum: 2592000
90
- },
91
- activeFrom: {
92
- type: "string",
93
- pattern: "^\\d{4}-\\d{2}-\\d{2}$",
94
- description: "Product active state starting date (YYYY-MM-DD format)"
95
- },
96
- activeTo: {
97
- type: "string",
98
- pattern: "^\\d{4}-\\d{2}-\\d{2}$",
99
- description: "Product active state ending date (YYYY-MM-DD format)"
100
- },
101
- timeZone: {
102
- type: "string",
103
- description: "Product state scheduling timezone (IANA format, e.g., 'Europe/Sofia')"
104
- },
105
- // Product Options Properties
106
- imageUrl: {
107
- type: "string",
108
- description: "URL pointing to external product image resource",
109
- maxLength: 150,
110
- format: "uri"
111
- },
112
- termsUrl: {
113
- type: "string",
114
- description: "URL pointing to external terms and conditions resource",
115
- maxLength: 150,
116
- format: "uri"
117
- },
118
- termsText: {
119
- type: "string",
120
- description: "Terms and conditions text",
121
- maxLength: 3000
122
- },
123
- // Authentication
124
- partnerId: {
125
- type: "string",
126
- description: "Merchant partner ID (uses PAYWARE_PARTNER_ID env var as default)",
127
- default: getPartnerIdSafe()
128
- },
129
- privateKey: {
130
- type: "string",
131
- description: "RSA private key for authentication (uses environment-specific private key as default)",
132
- default: getPrivateKeySafe()
133
- },
134
- useSandbox: {
135
- type: "boolean",
136
- description: "Use sandbox environment",
137
- default: true
138
- }
139
- },
140
- required: ["productId"]
141
- },
142
-
143
- async handler(args) {
144
- const {
145
- productId,
146
- name,
147
- shortDescription,
148
- longDescription,
149
- sku,
150
- upc,
151
- shippable,
152
- active,
153
- shop,
154
- productType,
155
- regularPrice,
156
- currency,
157
- overlapPriority,
158
- timeToLive,
159
- activeFrom,
160
- activeTo,
161
- timeZone,
162
- imageUrl,
163
- termsUrl,
164
- termsText,
165
- partnerId = getPartnerIdSafe(),
166
- privateKey = getPrivateKeySafe(),
167
- useSandbox = true
168
- } = args;
169
-
170
- if (!productId) {
171
- throw new Error("Product ID is required");
172
- }
173
-
174
- if (!partnerId) {
175
- throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
176
- }
177
-
178
- if (!privateKey) {
179
- throw new Error("Private key is required. Provide via 'privateKey' parameter or set environment-specific private key variable.");
180
- }
181
-
182
- // Build prData object only with provided fields
183
- const prData = {};
184
- if (productType !== undefined) prData.type = productType;
185
- if (regularPrice !== undefined) prData.regularPrice = regularPrice;
186
- if (currency !== undefined) prData.currency = currency;
187
- if (overlapPriority !== undefined) prData.overlapPriority = overlapPriority;
188
- if (timeToLive !== undefined) prData.timeToLive = timeToLive;
189
- if (activeFrom !== undefined) prData.activeFrom = activeFrom;
190
- if (activeTo !== undefined) prData.activeTo = activeTo;
191
- if (timeZone !== undefined) prData.timeZone = timeZone;
192
-
193
- // Build prOptions object only with provided fields
194
- const prOptions = {};
195
- if (imageUrl !== undefined) prOptions.imageUrl = imageUrl;
196
- if (termsUrl !== undefined) prOptions.termsUrl = termsUrl;
197
- if (termsText !== undefined) prOptions.termsText = termsText;
198
-
199
- try {
200
- const result = await updateProduct({
201
- productId,
202
- name,
203
- shortDescription,
204
- longDescription,
205
- sku,
206
- upc,
207
- shippable,
208
- active,
209
- shop,
210
- prData,
211
- prOptions,
212
- partnerType: 'merchant',
213
- partnerId,
214
- privateKey,
215
- useSandbox
216
- });
217
-
218
- const product = result.data;
219
-
220
- return {
221
- content: [{
222
- type: "text",
223
- text: `βœ… **Product Updated Successfully**
224
-
225
- **Updated Product Details:**
226
- - ID: ${product.productId}
227
- - Name: ${product.name}
228
- - Type: ${product.type}
229
- - Price: ${product.regularPrice} ${product.currencyCode}
230
- - Status: ${product.active ? 'βœ… Active' : '⏸️ Inactive'}
231
- - Shop: ${product.shopCode} (${product.shopName})
232
- ${product.shortDescription ? `- Description: ${product.shortDescription}` : ''}
233
- ${product.sku ? `- SKU: ${product.sku}` : ''}
234
- ${product.upc ? `- UPC: ${product.upc}` : ''}
235
-
236
- **Product Settings:**
237
- - Shippable: ${product.shippable ? 'Yes' : 'No'}
238
- - Time to Live: ${product.timeToLive} seconds
239
- - Sale Price: ${product.salePrice} ${product.currencyCode}
240
- - Overlap Priority: ${product.overlapPriority}
241
-
242
- **Active Period:**
243
- - From: ${product.activeFromZoned || product.activeFrom}
244
- - To: ${product.activeToZoned || product.activeTo}
245
- - Timezone: ${product.timeZone}
246
-
247
- **API Response:**
248
- \`\`\`json
249
- ${JSON.stringify(product, null, 2)}
250
- \`\`\`
251
-
252
- **API Call Details:**
253
- - Endpoint: ${result.requestInfo.method} ${result.requestInfo.url}
254
- - Status: ${result.requestInfo.statusCode}
255
-
256
- **Next Steps:**
257
- - Use \`payware_products_get_product\` to view updated product details
258
- - Use \`payware_products_create_schedule\` to manage price schedules
259
- - Use \`payware_products_get_product_image\` to generate QR/barcode`
260
- }]
261
- };
262
- } catch (error) {
263
- return {
264
- content: [{
265
- type: "text",
266
- text: `❌ **Product Update Failed**
267
-
268
- **Error Details:**
269
- - Message: ${error.message}
270
- - Product ID: ${productId}
271
-
272
- **Troubleshooting:**
273
- 1. Verify the product ID is correct and exists
274
- 2. Check parameter values (dates, price format, currency)
275
- 3. Ensure JWT token is valid and not expired
276
- 4. Verify partner ID and API access
277
- 5. Check that the product belongs to your account`
278
- }]
279
- };
280
- }
281
- }
1
+ import { updateProduct } from '../../shared/products/products-api.js';
2
+ import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
3
+ import { PRODUCT_TYPES, OVERLAP_PRIORITY } from '../../shared/products/products-api.js';
4
+
5
+ /**
6
+ * Update product tool implementation for merchants
7
+ */
8
+ export const updateProductTool = {
9
+ name: "payware_products_update_product",
10
+ description: `Update an existing product. Only provide the fields you want to change.
11
+
12
+ **Product Structure:**
13
+ πŸ“¦ **PRODUCT METADATA**: name, shortDescription, longDescription, sku, upc, shippable, active, shop
14
+ πŸ’° **PRODUCT DATA** (prData object): type, regularPrice, currency, overlapPriority, timeToLive, activeFrom, activeTo, timeZone
15
+ βš™οΈ **PRODUCT OPTIONS** (prOptions object): imageUrl, termsUrl, termsText`,
16
+
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ productId: {
21
+ type: "string",
22
+ description: "Product identifier to update (starts with 'pr')",
23
+ pattern: "^pr[a-zA-Z0-9]+$"
24
+ },
25
+ name: {
26
+ type: "string",
27
+ description: "Product recognizable name",
28
+ maxLength: 50
29
+ },
30
+ shortDescription: {
31
+ type: "string",
32
+ description: "Short product description",
33
+ maxLength: 150
34
+ },
35
+ longDescription: {
36
+ type: "string",
37
+ description: "Long product description",
38
+ maxLength: 1500
39
+ },
40
+ sku: {
41
+ type: "string",
42
+ description: "Stock Keeping Unit (SKU)",
43
+ maxLength: 25
44
+ },
45
+ upc: {
46
+ type: "string",
47
+ description: "Universal Product Code (UPC)",
48
+ maxLength: 15
49
+ },
50
+ shippable: {
51
+ type: "string",
52
+ enum: ["TRUE", "FALSE"],
53
+ description: "Indicates if product requires delivery address"
54
+ },
55
+ active: {
56
+ type: "string",
57
+ enum: ["TRUE", "FALSE"],
58
+ description: "Indicates if product can serve as payment source"
59
+ },
60
+ shop: {
61
+ type: "string",
62
+ description: "Shop code",
63
+ maxLength: 10
64
+ },
65
+ // Product Data Properties
66
+ productType: {
67
+ type: "string",
68
+ enum: Object.values(PRODUCT_TYPES),
69
+ description: "Type of product"
70
+ },
71
+ regularPrice: {
72
+ type: "string",
73
+ description: "Product regular price as a decimal string. Zero or positive, at most 12 integer digits, and no more decimals than the currency's minor unit (0 for JPY, 2 for EUR, 3 for KWD, 8 for BTC). Returned as a string too."
74
+ },
75
+ currency: {
76
+ type: "string",
77
+ pattern: "^[A-Z]{3}$",
78
+ description: "Price currency (3-character ISO code)"
79
+ },
80
+ overlapPriority: {
81
+ type: "string",
82
+ enum: Object.values(OVERLAP_PRIORITY),
83
+ description: "Priority when overlapping price schedules exist"
84
+ },
85
+ timeToLive: {
86
+ type: "number",
87
+ description: "Time allowed for product payment in seconds (60-2592000)",
88
+ minimum: 60,
89
+ maximum: 2592000
90
+ },
91
+ activeFrom: {
92
+ type: "string",
93
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
94
+ description: "Product active state starting date (YYYY-MM-DD format)"
95
+ },
96
+ activeTo: {
97
+ type: "string",
98
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
99
+ description: "Product active state ending date (YYYY-MM-DD format)"
100
+ },
101
+ timeZone: {
102
+ type: "string",
103
+ description: "Product state scheduling timezone (IANA format, e.g., 'Europe/Sofia')"
104
+ },
105
+ // Product Options Properties
106
+ imageUrl: {
107
+ type: "string",
108
+ description: "URL pointing to external product image resource",
109
+ maxLength: 150,
110
+ format: "uri"
111
+ },
112
+ termsUrl: {
113
+ type: "string",
114
+ description: "URL pointing to external terms and conditions resource",
115
+ maxLength: 150,
116
+ format: "uri"
117
+ },
118
+ termsText: {
119
+ type: "string",
120
+ description: "Terms and conditions text",
121
+ maxLength: 3000
122
+ },
123
+ // Authentication
124
+ partnerId: {
125
+ type: "string",
126
+ description: "Merchant partner ID (uses PAYWARE_PARTNER_ID env var as default)",
127
+ default: getPartnerIdSafe()
128
+ },
129
+ privateKey: {
130
+ type: "string",
131
+ description: "RSA private key for authentication (uses environment-specific private key as default)",
132
+ default: getPrivateKeySafe()
133
+ },
134
+ useSandbox: {
135
+ type: "boolean",
136
+ description: "Use sandbox environment",
137
+ default: true
138
+ }
139
+ },
140
+ required: ["productId"]
141
+ },
142
+
143
+ async handler(args) {
144
+ const {
145
+ productId,
146
+ name,
147
+ shortDescription,
148
+ longDescription,
149
+ sku,
150
+ upc,
151
+ shippable,
152
+ active,
153
+ shop,
154
+ productType,
155
+ regularPrice,
156
+ currency,
157
+ overlapPriority,
158
+ timeToLive,
159
+ activeFrom,
160
+ activeTo,
161
+ timeZone,
162
+ imageUrl,
163
+ termsUrl,
164
+ termsText,
165
+ partnerId = getPartnerIdSafe(),
166
+ privateKey = getPrivateKeySafe(),
167
+ useSandbox = true
168
+ } = args;
169
+
170
+ if (!productId) {
171
+ throw new Error("Product ID is required");
172
+ }
173
+
174
+ if (!partnerId) {
175
+ throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
176
+ }
177
+
178
+ if (!privateKey) {
179
+ throw new Error("Private key is required. Provide via 'privateKey' parameter or set environment-specific private key variable.");
180
+ }
181
+
182
+ // Build prData object only with provided fields
183
+ const prData = {};
184
+ if (productType !== undefined) prData.type = productType;
185
+ if (regularPrice !== undefined) prData.regularPrice = regularPrice;
186
+ if (currency !== undefined) prData.currency = currency;
187
+ if (overlapPriority !== undefined) prData.overlapPriority = overlapPriority;
188
+ if (timeToLive !== undefined) prData.timeToLive = timeToLive;
189
+ if (activeFrom !== undefined) prData.activeFrom = activeFrom;
190
+ if (activeTo !== undefined) prData.activeTo = activeTo;
191
+ if (timeZone !== undefined) prData.timeZone = timeZone;
192
+
193
+ // Build prOptions object only with provided fields
194
+ const prOptions = {};
195
+ if (imageUrl !== undefined) prOptions.imageUrl = imageUrl;
196
+ if (termsUrl !== undefined) prOptions.termsUrl = termsUrl;
197
+ if (termsText !== undefined) prOptions.termsText = termsText;
198
+
199
+ try {
200
+ const result = await updateProduct({
201
+ productId,
202
+ name,
203
+ shortDescription,
204
+ longDescription,
205
+ sku,
206
+ upc,
207
+ shippable,
208
+ active,
209
+ shop,
210
+ prData,
211
+ prOptions,
212
+ partnerType: 'merchant',
213
+ partnerId,
214
+ privateKey,
215
+ useSandbox
216
+ });
217
+
218
+ const product = result.data;
219
+
220
+ return {
221
+ content: [{
222
+ type: "text",
223
+ text: `βœ… **Product Updated Successfully**
224
+
225
+ **Updated Product Details:**
226
+ - ID: ${product.productId}
227
+ - Name: ${product.name}
228
+ - Type: ${product.type}
229
+ - Price: ${product.regularPrice} ${product.currencyCode}
230
+ - Status: ${product.active ? 'βœ… Active' : '⏸️ Inactive'}
231
+ - Shop: ${product.shopCode} (${product.shopName})
232
+ ${product.shortDescription ? `- Description: ${product.shortDescription}` : ''}
233
+ ${product.sku ? `- SKU: ${product.sku}` : ''}
234
+ ${product.upc ? `- UPC: ${product.upc}` : ''}
235
+
236
+ **Product Settings:**
237
+ - Shippable: ${product.shippable ? 'Yes' : 'No'}
238
+ - Time to Live: ${product.timeToLive} seconds
239
+ - Sale Price: ${product.salePrice} ${product.currencyCode}
240
+ - Overlap Priority: ${product.overlapPriority}
241
+
242
+ **Active Period:**
243
+ - From: ${product.activeFromZoned || product.activeFrom}
244
+ - To: ${product.activeToZoned || product.activeTo}
245
+ - Timezone: ${product.timeZone}
246
+
247
+ **API Response:**
248
+ \`\`\`json
249
+ ${JSON.stringify(product, null, 2)}
250
+ \`\`\`
251
+
252
+ **API Call Details:**
253
+ - Endpoint: ${result.requestInfo.method} ${result.requestInfo.url}
254
+ - Status: ${result.requestInfo.statusCode}
255
+
256
+ **Next Steps:**
257
+ - Use \`payware_products_get_product\` to view updated product details
258
+ - Use \`payware_products_create_schedule\` to manage price schedules
259
+ - Use \`payware_products_get_product_image\` to generate QR/barcode`
260
+ }]
261
+ };
262
+ } catch (error) {
263
+ return {
264
+ content: [{
265
+ type: "text",
266
+ text: `❌ **Product Update Failed**
267
+
268
+ **Error Details:**
269
+ - Message: ${error.message}
270
+ - Product ID: ${productId}
271
+
272
+ **Troubleshooting:**
273
+ 1. Verify the product ID is correct and exists
274
+ 2. Check parameter values (dates, price format, currency)
275
+ 3. Ensure JWT token is valid and not expired
276
+ 4. Verify partner ID and API access
277
+ 5. Check that the product belongs to your account`
278
+ }]
279
+ };
280
+ }
281
+ }
282
282
  };
@@ -0,0 +1,18 @@
1
+ import { buildListShopsTool } from '../../shared/shops/shops-api.js';
2
+ import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
3
+
4
+ /**
5
+ * Shop tools for the merchant role.
6
+ *
7
+ * The tool body is shared with the ISV role - the only thing that differs is how the request is
8
+ * signed and, on the server side, which shops come back. See shared/shops/shops-api.js.
9
+ */
10
+ export const listShopsTool = buildListShopsTool({
11
+ partnerType: 'merchant',
12
+ resolveAuth: (args) => ({
13
+ partnerId: args.partnerId || getPartnerIdSafe(),
14
+ privateKey: args.privateKey || getPrivateKeySafe(args.useSandbox ?? true)
15
+ })
16
+ });
17
+
18
+ export const merchantShopTools = [listShopsTool];
@@ -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
  * Cancel a transaction via payware API
@@ -66,16 +67,7 @@ export async function cancelTransaction({
66
67
  timestamp: new Date().toISOString()
67
68
  };
68
69
  } catch (error) {
69
- return {
70
- success: false,
71
- error: {
72
- message: error.response?.data?.message || error.message,
73
- status: error.response?.status,
74
- code: error.response?.data?.errorCode,
75
- details: error.response?.data
76
- },
77
- timestamp: new Date().toISOString()
78
- };
70
+ return apiErrorResult(error);
79
71
  }
80
72
  }
81
73
 
@@ -91,8 +83,13 @@ export const cancelTransactionTool = {
91
83
  properties: {
92
84
  transactionId: {
93
85
  type: "string",
94
- description: "Transaction ID to cancel (must be ACTIVE transaction created by this merchant). Format: 2-char prefix + 8-char ID. Supports: 'pw' (standard), 'pr' (product), 'ps' (soundbite)",
95
- pattern: "^(pw|pr|ps)[0-9A-Za-z]{8}$"
86
+ // 'pw' only. A product ('pr') or soundbite ('ps') id is resolved to a real transaction on the
87
+ // process path, but the finalize path this tool uses looks the id up literally and answers
88
+ // 404 for anything else - so an assistant following the old schema PATCHed a product id to
89
+ // "cancel a product payment", read the 404 as "already gone", and left the product live and
90
+ // scannable. Products are taken down through the products API, not by cancelling them.
91
+ description: "Transaction ID to cancel (must be an ACTIVE 'pw' transaction created by this merchant). Format: 'pw' + 8 characters. Product ('pr') and soundbite ('ps') ids are NOT cancellable - deactivate those through the products API.",
92
+ pattern: "^pw[0-9A-Za-z]{8}$"
96
93
  },
97
94
  statusMessage: {
98
95
  type: "string",
@@ -228,7 +225,7 @@ ${JSON.stringify(result.error.details || result.error, null, 2)}
228
225
  - ⚠️ **Before Expiry**: Cannot cancel expired transactions
229
226
 
230
227
  **Troubleshooting:**
231
- 1. Verify transaction ID is correct: 10 characters total, starts with 'pw' (standard), 'pr' (product), or 'ps' (soundbite)
228
+ 1. Verify transaction ID is correct: 10 characters total, starting with 'pw'. Product ('pr') and soundbite ('ps') ids cannot be cancelled - this endpoint resolves the id literally and answers 404 for them; deactivate those through the products API instead.
232
229
  2. **Ensure you are the transaction creator** (not just any merchant)
233
230
  3. Check transaction hasn't been processed already by anyone
234
231
  4. Verify status message is under 100 characters