@payware/mcp-server 1.0.0 → 1.1.1

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 (47) hide show
  1. package/README.md +42 -4
  2. package/package.json +1 -1
  3. package/src/isv/data/index.js +23 -0
  4. package/src/isv/deep-links/delete-product-link.js +1 -1
  5. package/src/isv/deep-links/delete-transaction-link.js +1 -1
  6. package/src/isv/deep-links/get-product-link.js +1 -1
  7. package/src/isv/deep-links/get-transaction-link.js +1 -1
  8. package/src/isv/index.js +11 -1
  9. package/src/isv/poi/cancel-price.js +149 -0
  10. package/src/isv/poi/get-poi.js +190 -0
  11. package/src/isv/poi/get-qrcode.js +151 -0
  12. package/src/isv/poi/get-status.js +176 -0
  13. package/src/isv/poi/index.js +32 -0
  14. package/src/isv/poi/list-pois.js +168 -0
  15. package/src/isv/poi/set-price.js +225 -0
  16. package/src/isv/transactions/get-status.js +1 -1
  17. package/src/isv/transactions/transaction-history.js +2 -1
  18. package/src/mcp-proxy.js +2 -2
  19. package/src/merchant/data/export-report.js +3 -4
  20. package/src/merchant/data/generate-report.js +3 -4
  21. package/src/merchant/data/get-export-list.js +140 -0
  22. package/src/merchant/data/get-report-requests.js +125 -0
  23. package/src/merchant/data/get-report-status.js +3 -4
  24. package/src/merchant/data/index.js +64 -25
  25. package/src/merchant/data/list-reports.js +107 -0
  26. package/src/merchant/deep-links/delete-product-link.js +1 -1
  27. package/src/merchant/deep-links/delete-transaction-link.js +1 -1
  28. package/src/merchant/deep-links/get-product-link.js +1 -1
  29. package/src/merchant/deep-links/get-transaction-link.js +1 -1
  30. package/src/merchant/transactions/create-transaction.js +4 -2
  31. package/src/merchant/transactions/get-status.js +1 -1
  32. package/src/merchant/transactions/process-transaction.js +10 -1
  33. package/src/merchant/transactions/simulate-callback.js +11 -2
  34. package/src/merchant/transactions/transaction-history.js +1 -1
  35. package/src/payment-institution/data/index.js +23 -0
  36. package/src/payment-institution/deep-links/delete-transaction-link.js +1 -1
  37. package/src/payment-institution/deep-links/get-transaction-link.js +1 -1
  38. package/src/payment-institution/transactions/create-pi-transaction.js +2 -0
  39. package/src/payment-institution/transactions/finalize-transaction.js +1 -0
  40. package/src/payment-institution/transactions/get-transaction-history.js +1 -1
  41. package/src/payment-institution/transactions/get-transaction-status.js +1 -1
  42. package/src/payment-institution/transactions/process-pi-transaction.js +12 -0
  43. package/src/payment-institution/transactions/simulate-pi-callback.js +12 -2
  44. package/src/payment-institution/transactions/soundbite-transaction.js +2 -0
  45. package/src/shared/data/data-api.js +97 -0
  46. package/src/utils/code-examples/merchant/transactions.js +2 -1
  47. package/src/utils/code-examples/payment-institution/transactions.js +1 -0
package/README.md CHANGED
@@ -1,18 +1,41 @@
1
1
  # payware MCP Server
2
2
 
3
- Minimal MCP server for payware API integration. Enables quick merchant integration with payware APIs in sandbox environment.
3
+ [![npm version](https://badge.fury.io/js/%40payware%2Fmcp-server.svg)](https://www.npmjs.com/package/@payware/mcp-server)
4
+
5
+ Official MCP (Model Context Protocol) server for payware payment API integration. This server enables AI assistants to interact with payware APIs, automating integration workflows for all partner types.
6
+
7
+ ## Who Is This For?
8
+
9
+ - **Merchants** - Accept payments, manage products, generate transaction reports
10
+ - **ISVs (Independent Software Vendors)** - Build multi-merchant platforms with OAuth2 token management
11
+ - **Payment Institutions** - Process A2A transfers, handle Payment Choice Architecture with multiple payment methods
12
+
13
+ ## What's New in v1.1.0
14
+
15
+ - **Point of Interaction (POI)** - Full POI management: set prices, get status, generate QR codes, list and manage POIs
16
+ - **Payment Choice Architecture** - Support for `paymentMethod` field (A2A, CARD_FUNDED, BNPL, INSTANT_CREDIT) in transaction processing
4
17
 
5
18
  ## Features
6
19
 
7
20
  ### 🔐 Authentication Tools
8
21
  - **RSA Key Generation**: Generate secure 2048-bit RSA key pairs
9
- - **JWT Token Creation**: Create properly formatted JWT tokens
22
+ - **JWT Token Creation**: Create properly formatted JWT tokens
10
23
  - **Sandbox Setup**: Configure sandbox authentication
11
24
 
12
25
  ### 💳 Transaction Tools
13
26
  - **Create Transaction**: Support PLAIN, QR, and BARCODE transactions
27
+ - **Process Transaction**: Process transactions with Payment Choice Architecture support
14
28
  - **Transaction Status**: Check transaction status by ID
15
- - **Callback Simulation**: Test callback scenarios
29
+ - **Transaction History**: Get finalized transaction details
30
+ - **Callback Simulation**: Test callback scenarios for merchants and payment institutions
31
+
32
+ ### 📍 Point of Interaction (POI) Tools
33
+ - **Set Price**: Configure POI with amount, currency, and payment details
34
+ - **Cancel Price**: Clear active price from POI
35
+ - **Get POI**: Retrieve POI details and current state
36
+ - **Get Status**: Check POI transaction status
37
+ - **Get QR Code**: Generate QR code for POI payments
38
+ - **List POIs**: List all POIs for a merchant
16
39
 
17
40
  ### 🛠️ Utility Tools
18
41
  - **Advanced Code Generation**: Generate complete integration code across 8 languages (Python, Node.js, PHP, Java, C#, Go, Ruby, cURL) with 16+ framework support
@@ -25,8 +48,15 @@ Minimal MCP server for payware API integration. Enables quick merchant integrati
25
48
 
26
49
  ### 1. Installation
27
50
 
51
+ **From npm (recommended):**
28
52
  ```bash
29
- cd payware/mcp
53
+ npm install -g @payware/mcp-server
54
+ ```
55
+
56
+ **From source:**
57
+ ```bash
58
+ git clone https://github.com/payware/mcp-server.git
59
+ cd mcp-server
30
60
  npm install
31
61
  ```
32
62
 
@@ -309,6 +339,14 @@ Generate production-ready code examples for any payware operation.
309
339
  - `get_product` - Get product details
310
340
  - `list_products` - List all products
311
341
 
342
+ **POI Operations (isv):**
343
+ - `set_price` - Set price on a Point of Interaction device
344
+ - `cancel_price` - Cancel active price on POI
345
+ - `get_poi` - Get POI details
346
+ - `get_poi_status` - Get POI transaction status
347
+ - `get_poi_qrcode` - Generate QR code for POI
348
+ - `list_pois` - List all POIs for a merchant
349
+
312
350
  **OAuth2 Operations (isv only):**
313
351
  - `obtain_token` - Obtain OAuth2 access token
314
352
  - `get_token_info` - Get OAuth2 token information
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payware/mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Official MCP server for payware payment API integration",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -11,6 +11,9 @@ import {
11
11
  downloadExport,
12
12
  cancelReport,
13
13
  cancelExport,
14
+ listReports,
15
+ getReportRequests,
16
+ getExportList,
14
17
  REPORT_TYPES,
15
18
  EXPORT_FORMATS,
16
19
  LOCALES
@@ -229,6 +232,23 @@ This feature requires proper OAuth2 authorization from the merchant and is only
229
232
  };
230
233
 
231
234
  // Create all other ISV data tools
235
+ export const listReportsTool = createISVDataTool('list_reports', listReports, 'List All Available Reports', {});
236
+
237
+ export const getReportRequestsTool = createISVDataTool('get_report_requests', getReportRequests, 'Get Report Request History', {
238
+ reportId: {
239
+ type: "string",
240
+ description: "The report unit ID (path) to get execution history for (e.g., '/processedTransactions')",
241
+ enum: Object.values(REPORT_TYPES)
242
+ }
243
+ });
244
+
245
+ export const getExportListTool = createISVDataTool('get_export_list', getExportList, 'Get Export List for Request', {
246
+ requestId: {
247
+ type: "string",
248
+ description: "The request ID (UUID) to get exports for"
249
+ }
250
+ });
251
+
232
252
  export const getReportStatusTool = createISVDataTool('get_report_status', getReportStatus, 'Get Report Status', {
233
253
  requestId: {
234
254
  type: "string",
@@ -281,9 +301,12 @@ export const cancelExportTool = createISVDataTool('cancel_export', cancelExport,
281
301
  * All ISV data tools
282
302
  */
283
303
  export const isvDataTools = [
304
+ listReportsTool,
284
305
  generateReportTool,
306
+ getReportRequestsTool,
285
307
  getReportStatusTool,
286
308
  exportReportTool,
309
+ getExportListTool,
287
310
  getExportStatusTool,
288
311
  downloadExportTool,
289
312
  cancelReportTool,
@@ -100,7 +100,7 @@ export const deleteProductLinkTool = {
100
100
  - Product ID: ${productId}
101
101
  - Merchant: ${merchantPartnerId}
102
102
  - Status: Successfully deleted
103
- - Link URL: https://url.payware.eu/${productId} (now inactive)
103
+ - Link URL: https://go.payware.eu/${productId} (now inactive)
104
104
 
105
105
  **ISV Authentication:**
106
106
  - ISV Partner ID: ${isvPartnerId}
@@ -100,7 +100,7 @@ export const deleteTransactionLinkTool = {
100
100
  - Transaction ID: ${transactionId}
101
101
  - Merchant: ${merchantPartnerId}
102
102
  - Status: Successfully deleted
103
- - Link URL: https://url.payware.eu/${transactionId} (now inactive)
103
+ - Link URL: https://go.payware.eu/${transactionId} (now inactive)
104
104
 
105
105
  **ISV Authentication:**
106
106
  - ISV Partner ID: ${isvPartnerId}
@@ -13,7 +13,7 @@ export const getProductLinkTool = {
13
13
  - Requires OAuth2 token in 'sub' claim
14
14
 
15
15
  **Deep Link Format:**
16
- - Web URL: https://url.payware.eu/{productId}
16
+ - Web URL: https://go.payware.eu/{productId}
17
17
  - Mobile Redirect: payware://{productId}
18
18
 
19
19
  **Use Cases:**
@@ -13,7 +13,7 @@ export const getTransactionLinkTool = {
13
13
  - Requires OAuth2 token in 'sub' claim
14
14
 
15
15
  **Deep Link Format:**
16
- - Web URL: https://url.payware.eu/{transactionId}
16
+ - Web URL: https://go.payware.eu/{transactionId}
17
17
  - Mobile Redirect: payware://{transactionId}
18
18
 
19
19
  **Use Cases:**
package/src/isv/index.js CHANGED
@@ -25,6 +25,9 @@ import { isvProductTools } from './products/index.js';
25
25
  // Deep links tools
26
26
  import { isvDeepLinksTools } from './deep-links/index.js';
27
27
 
28
+ // POI tools
29
+ import { isvPOITools } from './poi/index.js';
30
+
28
31
  // Import shared tools
29
32
  import { sharedTools } from '../shared/index.js';
30
33
 
@@ -55,7 +58,10 @@ export const isvTools = [
55
58
  ...isvProductTools,
56
59
 
57
60
  // Deep links management
58
- ...isvDeepLinksTools
61
+ ...isvDeepLinksTools,
62
+
63
+ // POI management
64
+ ...isvPOITools
59
65
  ];
60
66
 
61
67
  /**
@@ -94,6 +100,10 @@ export function getISVTools() {
94
100
  else if (tool.name.startsWith('payware_deep_links_')) {
95
101
  newName = tool.name; // Keep deep_links grouping
96
102
  }
103
+ // POI tools keep their poi grouping
104
+ else if (tool.name.startsWith('payware_poi_')) {
105
+ newName = tool.name; // Keep poi grouping
106
+ }
97
107
 
98
108
  return {
99
109
  ...tool,
@@ -0,0 +1,149 @@
1
+ import axios from 'axios';
2
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
3
+ import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
4
+
5
+ /**
6
+ * Cancel pending price on a POI via ISV authentication
7
+ * @param {Object} params - Parameters for cancel request
8
+ * @returns {Object} Cancel response
9
+ */
10
+ export async function cancelPOIPrice({ poiId, merchantPartnerId, oauth2Token, useSandbox = true }) {
11
+ if (!poiId) {
12
+ throw new Error('POI ID is required');
13
+ }
14
+
15
+ if (!merchantPartnerId) {
16
+ throw new Error('Merchant Partner ID is required for ISV operations');
17
+ }
18
+
19
+ if (!oauth2Token) {
20
+ throw new Error('OAuth2 token is required for ISV operations');
21
+ }
22
+
23
+ const isvPartnerId = getPartnerIdSafe();
24
+ const privateKey = getPrivateKeySafe(useSandbox);
25
+
26
+ const jwtData = await createJWTForPartner({
27
+ partnerId: isvPartnerId,
28
+ privateKey,
29
+ requestBody: null,
30
+ merchantId: merchantPartnerId,
31
+ oauth2Token
32
+ });
33
+
34
+ const headers = {
35
+ 'Authorization': `Bearer ${jwtData.token}`,
36
+ 'Content-Type': 'application/json',
37
+ 'Api-Version': '1'
38
+ };
39
+
40
+ try {
41
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
42
+ const response = await axios.delete(`${baseUrl}/poi/${poiId}/price`, { headers });
43
+
44
+ return {
45
+ success: true,
46
+ requestId: response.headers['x-request-id'],
47
+ timestamp: new Date().toISOString()
48
+ };
49
+ } catch (error) {
50
+ return {
51
+ success: false,
52
+ error: {
53
+ message: error.response?.data?.message || error.message,
54
+ status: error.response?.status,
55
+ code: error.response?.data?.code,
56
+ details: error.response?.data
57
+ },
58
+ timestamp: new Date().toISOString()
59
+ };
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Cancel POI price tool implementation for ISV
65
+ */
66
+ export const cancelPOIPriceTool = {
67
+ name: "payware_poi_cancel_price",
68
+ description: `Cancel a pending price on a POI, resetting it to IDLE state.
69
+
70
+ **ISV Authentication:** Uses ISV JWT with merchant partner ID and OAuth2 token.
71
+ **Endpoint:** DELETE /poi/{poiId}/price
72
+ **Use Case:** Cancel a price that was set but customer didn't pay (e.g., order cancelled).
73
+
74
+ The POI will return to IDLE state and be ready for a new price.
75
+
76
+ **Required:** POI ID, Merchant Partner ID, and OAuth2 token.`,
77
+
78
+ inputSchema: {
79
+ type: "object",
80
+ required: ["poiId", "merchantPartnerId", "oauth2Token"],
81
+ properties: {
82
+ poiId: {
83
+ type: "string",
84
+ description: "The POI identifier (format: pi + 8 alphanumeric chars, e.g., piABC12345)"
85
+ },
86
+ merchantPartnerId: {
87
+ type: "string",
88
+ description: "Partner ID of the target merchant (8 alphanumeric characters)"
89
+ },
90
+ oauth2Token: {
91
+ type: "string",
92
+ description: "OAuth2 access token obtained from the merchant"
93
+ },
94
+ useSandbox: {
95
+ type: "boolean",
96
+ description: "Use sandbox environment for testing",
97
+ default: true
98
+ }
99
+ }
100
+ },
101
+
102
+ async handler(args) {
103
+ const { poiId, merchantPartnerId, oauth2Token, useSandbox = true } = args;
104
+
105
+ if (!poiId) throw new Error("POI ID is required");
106
+ if (!merchantPartnerId) throw new Error("Merchant Partner ID is required");
107
+ if (!oauth2Token) throw new Error("OAuth2 token is required");
108
+
109
+ const result = await cancelPOIPrice({ poiId, merchantPartnerId, oauth2Token, useSandbox });
110
+
111
+ if (result.success) {
112
+ return {
113
+ content: [{
114
+ type: "text",
115
+ text: `✅ **Price Cancelled Successfully**
116
+
117
+ **POI ID:** ${poiId}
118
+ **Status:** 🟢 IDLE (ready for new price)
119
+
120
+ The POI is now ready to accept a new price.
121
+
122
+ **ISV -> Merchant:** ${getPartnerIdSafe()} -> ${merchantPartnerId}
123
+ **Request ID:** ${result.requestId || 'N/A'}
124
+ **Timestamp:** ${result.timestamp}`
125
+ }]
126
+ };
127
+ } else {
128
+ return {
129
+ content: [{
130
+ type: "text",
131
+ text: `❌ **Failed to Cancel Price**
132
+
133
+ **POI ID:** ${poiId}
134
+
135
+ **Error:** ${result.error.message}
136
+ **Code:** ${result.error.code || 'N/A'}
137
+ **Status:** ${result.error.status || 'N/A'}
138
+
139
+ **Common Issues:**
140
+ - INVALID_POI_ID (400): POI ID format invalid (must be pi + 8 alphanumeric chars)
141
+ - POI_NOT_FOUND (404): POI doesn't exist or doesn't belong to merchant
142
+ - POI_NO_PENDING_PAYMENT (409): No pending price to cancel (POI already IDLE)
143
+
144
+ **Timestamp:** ${result.timestamp}`
145
+ }]
146
+ };
147
+ }
148
+ }
149
+ };
@@ -0,0 +1,190 @@
1
+ import axios from 'axios';
2
+ import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
3
+ import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
4
+
5
+ /**
6
+ * Get POI details via ISV authentication
7
+ * @param {Object} params - Parameters for get request
8
+ * @returns {Object} POI details response
9
+ */
10
+ export async function getPOI({ poiId, merchantPartnerId, oauth2Token, useSandbox = true }) {
11
+ if (!poiId) {
12
+ throw new Error('POI ID is required');
13
+ }
14
+
15
+ if (!merchantPartnerId) {
16
+ throw new Error('Merchant Partner ID is required for ISV operations');
17
+ }
18
+
19
+ if (!oauth2Token) {
20
+ throw new Error('OAuth2 token is required for ISV operations');
21
+ }
22
+
23
+ // Get ISV credentials
24
+ const isvPartnerId = getPartnerIdSafe();
25
+ const privateKey = getPrivateKeySafe(useSandbox);
26
+
27
+ // Create ISV JWT token (GET request - no body)
28
+ const jwtData = await createJWTForPartner({
29
+ partnerId: isvPartnerId,
30
+ privateKey,
31
+ requestBody: null,
32
+ merchantId: merchantPartnerId,
33
+ oauth2Token
34
+ });
35
+
36
+ // Required headers as per payware API documentation
37
+ const headers = {
38
+ 'Authorization': `Bearer ${jwtData.token}`,
39
+ 'Content-Type': 'application/json',
40
+ 'Api-Version': '1'
41
+ };
42
+
43
+ try {
44
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
45
+ const response = await axios.get(`${baseUrl}/poi/${poiId}`, { headers });
46
+
47
+ return {
48
+ success: true,
49
+ poi: response.data,
50
+ requestId: response.headers['x-request-id'],
51
+ timestamp: new Date().toISOString()
52
+ };
53
+ } catch (error) {
54
+ return {
55
+ success: false,
56
+ error: {
57
+ message: error.response?.data?.message || error.message,
58
+ status: error.response?.status,
59
+ code: error.response?.data?.code,
60
+ details: error.response?.data
61
+ },
62
+ timestamp: new Date().toISOString()
63
+ };
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Get POI details tool implementation for ISV
69
+ */
70
+ export const getPOITool = {
71
+ name: "payware_poi_get",
72
+ description: `Get details of a specific POI (Point of Interaction).
73
+
74
+ **ISV Authentication:** Uses ISV JWT with merchant partner ID and OAuth2 token.
75
+ **Endpoint:** GET /poi/{poiId}
76
+ **Use Case:** Retrieve full details of a physical payment point including configuration and current state.
77
+
78
+ **Required:** POI ID, Merchant Partner ID, and OAuth2 token.`,
79
+
80
+ inputSchema: {
81
+ type: "object",
82
+ required: ["poiId", "merchantPartnerId", "oauth2Token"],
83
+ properties: {
84
+ poiId: {
85
+ type: "string",
86
+ description: "The POI identifier (format: pi + 8 alphanumeric chars, e.g., piABC12345)"
87
+ },
88
+ merchantPartnerId: {
89
+ type: "string",
90
+ description: "Partner ID of the target merchant (8 alphanumeric characters)"
91
+ },
92
+ oauth2Token: {
93
+ type: "string",
94
+ description: "OAuth2 access token obtained from the merchant"
95
+ },
96
+ useSandbox: {
97
+ type: "boolean",
98
+ description: "Use sandbox environment for testing",
99
+ default: true
100
+ }
101
+ }
102
+ },
103
+
104
+ async handler(args) {
105
+ const { poiId, merchantPartnerId, oauth2Token, useSandbox = true } = args;
106
+
107
+ if (!poiId) {
108
+ throw new Error("POI ID is required");
109
+ }
110
+
111
+ if (!merchantPartnerId) {
112
+ throw new Error("Merchant Partner ID is required for ISV operations");
113
+ }
114
+
115
+ if (!oauth2Token) {
116
+ throw new Error("OAuth2 token is required for ISV operations");
117
+ }
118
+
119
+ const result = await getPOI({ poiId, merchantPartnerId, oauth2Token, useSandbox });
120
+
121
+ if (result.success) {
122
+ const poi = result.poi;
123
+ const statusEmoji = {
124
+ 'IDLE': '🟢',
125
+ 'READY': '🟡',
126
+ 'BUSY': '🔴',
127
+ 'DISABLED': '⚫'
128
+ }[poi.status] || '⚪';
129
+
130
+ return {
131
+ content: [{
132
+ type: "text",
133
+ text: `📍 **POI Details Retrieved (ISV -> Merchant: ${merchantPartnerId})**
134
+
135
+ **POI:** ${poi.name} (${poi.poiId})
136
+ **Status:** ${statusEmoji} ${poi.status}
137
+ **Active:** ${poi.isActive ? '✅ Yes' : '❌ No'}
138
+
139
+ **Location:**
140
+ - Shop: ${poi.shopName || 'N/A'} (${poi.shopCode || 'N/A'})
141
+
142
+ **Configuration:**
143
+ - Default TTL: ${poi.ttlSeconds || 120} seconds
144
+ - Callback URL: ${poi.callbackUrl || 'Not configured'}
145
+ - Linked vPOS: ${poi.linkedVposCount || 0} terminals
146
+
147
+ **Current Session:**
148
+ ${poi.status !== 'IDLE' && poi.pendingAmount ? `- Amount: ${poi.pendingAmount} ${poi.pendingCurrency}
149
+ - Expires: ${poi.sessionExpiresAt || 'N/A'}
150
+ - Token: ${poi.sessionToken || 'N/A'}` : '- No active session'}
151
+
152
+ **Timestamps:**
153
+ - Created: ${poi.createdAt || 'N/A'}
154
+ - Updated: ${poi.updatedAt || 'N/A'}
155
+
156
+ **Full Response:**
157
+ \`\`\`json
158
+ ${JSON.stringify(poi, null, 2)}
159
+ \`\`\`
160
+
161
+ **Request ID:** ${result.requestId || 'N/A'}
162
+ **Timestamp:** ${result.timestamp}`
163
+ }]
164
+ };
165
+ } else {
166
+ return {
167
+ content: [{
168
+ type: "text",
169
+ text: `❌ **Failed to Get POI Details**
170
+
171
+ **POI ID:** ${poiId}
172
+ **ISV -> Merchant:** ${getPartnerIdSafe()} -> ${merchantPartnerId}
173
+
174
+ **Error Details:**
175
+ - Message: ${result.error.message}
176
+ - Status: ${result.error.status || 'N/A'}
177
+ - Code: ${result.error.code || 'N/A'}
178
+
179
+ **Troubleshooting:**
180
+ 1. Verify POI ID format (must be pi + 8 alphanumeric chars, e.g., piABC12345)
181
+ 2. If 400 error: POI ID format is invalid (ERR_INVALID_POI_ID)
182
+ 3. If 404 error: POI not found or doesn't belong to merchant
183
+ 4. Check OAuth2 token validity
184
+
185
+ **Timestamp:** ${result.timestamp}`
186
+ }]
187
+ };
188
+ }
189
+ }
190
+ };
@@ -0,0 +1,151 @@
1
+ import axios from 'axios';
2
+ import { getSandboxUrl, getProductionUrl } from '../../config/env.js';
3
+
4
+ /**
5
+ * Get POI QR code image
6
+ * Note: This endpoint is public and doesn't require authentication
7
+ * @param {Object} params - Parameters for QR code request
8
+ * @returns {Object} QR code response
9
+ */
10
+ export async function getPOIQRCode({ poiId, format = 'PNG', useSandbox = true }) {
11
+ if (!poiId) {
12
+ throw new Error('POI ID is required');
13
+ }
14
+
15
+ const headers = {
16
+ 'Api-Version': '1'
17
+ };
18
+
19
+ try {
20
+ const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
21
+ const response = await axios.get(`${baseUrl}/poi/${poiId}/image`, {
22
+ headers,
23
+ params: { format },
24
+ responseType: 'arraybuffer'
25
+ });
26
+
27
+ const contentType = response.headers['content-type'];
28
+ const base64Image = Buffer.from(response.data).toString('base64');
29
+
30
+ return {
31
+ success: true,
32
+ image: {
33
+ base64: base64Image,
34
+ contentType,
35
+ format,
36
+ size: response.data.length
37
+ },
38
+ requestId: response.headers['x-request-id'],
39
+ timestamp: new Date().toISOString()
40
+ };
41
+ } catch (error) {
42
+ return {
43
+ success: false,
44
+ error: {
45
+ message: error.response?.data?.message || error.message,
46
+ status: error.response?.status,
47
+ code: error.response?.data?.code,
48
+ details: error.response?.data
49
+ },
50
+ timestamp: new Date().toISOString()
51
+ };
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Get POI QR code tool implementation
57
+ */
58
+ export const getPOIQRCodeTool = {
59
+ name: "payware_poi_get_qrcode",
60
+ description: `Generate a QR code image for a POI that customers can scan.
61
+
62
+ **Endpoint:** GET /poi/{poiId}/image
63
+ **Authentication:** Public endpoint (no auth required)
64
+ **Use Case:** Generate QR codes for printing or displaying on screens.
65
+
66
+ **Formats:** PNG (default), SVG, JPG
67
+
68
+ Returns base64-encoded image data that can be saved or displayed.
69
+
70
+ **Required:** POI ID only.`,
71
+
72
+ inputSchema: {
73
+ type: "object",
74
+ required: ["poiId"],
75
+ properties: {
76
+ poiId: {
77
+ type: "string",
78
+ description: "The POI identifier (format: pi + 8 alphanumeric chars, e.g., piABC12345)"
79
+ },
80
+ format: {
81
+ type: "string",
82
+ enum: ["PNG", "SVG", "JPG"],
83
+ description: "Image format (default: PNG)",
84
+ default: "PNG"
85
+ },
86
+ useSandbox: {
87
+ type: "boolean",
88
+ description: "Use sandbox environment for testing",
89
+ default: true
90
+ }
91
+ }
92
+ },
93
+
94
+ async handler(args) {
95
+ const { poiId, format = 'PNG', useSandbox = true } = args;
96
+
97
+ if (!poiId) throw new Error("POI ID is required");
98
+
99
+ const result = await getPOIQRCode({ poiId, format, useSandbox });
100
+
101
+ if (result.success) {
102
+ const img = result.image;
103
+ const sizeKB = (img.size / 1024).toFixed(2);
104
+
105
+ return {
106
+ content: [{
107
+ type: "text",
108
+ text: `📱 **POI QR Code Generated**
109
+
110
+ **POI ID:** ${poiId}
111
+ **Format:** ${img.format}
112
+ **Size:** ${sizeKB} KB
113
+ **Content-Type:** ${img.contentType}
114
+
115
+ **Base64 Image Data:**
116
+ \`\`\`
117
+ ${img.base64.substring(0, 100)}...
118
+ \`\`\`
119
+
120
+ **Usage:**
121
+ - Save as file: decode base64 and write to ${poiId}.${format.toLowerCase()}
122
+ - Display in HTML: \`<img src="data:${img.contentType};base64,${img.base64.substring(0, 20)}...">\`
123
+ - Print for physical placement at point of sale
124
+
125
+ **Full base64 length:** ${img.base64.length} characters
126
+
127
+ **Request ID:** ${result.requestId || 'N/A'}
128
+ **Timestamp:** ${result.timestamp}`
129
+ }]
130
+ };
131
+ } else {
132
+ return {
133
+ content: [{
134
+ type: "text",
135
+ text: `❌ **Failed to Generate QR Code**
136
+
137
+ **POI ID:** ${poiId}
138
+
139
+ **Error:** ${result.error.message}
140
+ **Status:** ${result.error.status || 'N/A'}
141
+
142
+ **Common Issues:**
143
+ - INVALID_POI_ID (400): POI ID format invalid (must be pi + 8 alphanumeric chars)
144
+ - POI_NOT_FOUND (404): POI doesn't exist
145
+
146
+ **Timestamp:** ${result.timestamp}`
147
+ }]
148
+ };
149
+ }
150
+ }
151
+ };