@payware/mcp-server 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +4 -0
- package/README.md +18 -0
- package/package.json +7 -9
- package/src/auth/rsa-keys.js +12 -6
- package/src/auth/sandbox-setup.js +2 -0
- package/src/config/toolsets.js +104 -0
- package/src/core/auth/jwt-factory.js +4 -1
- package/src/core/auth/jwt-token.js +4 -0
- package/src/index.js +10 -6
- package/src/isv/data/index.js +15 -14
- package/src/isv/deep-links/delete-product-link.js +3 -2
- package/src/isv/deep-links/delete-transaction-link.js +3 -2
- package/src/isv/deep-links/get-product-link.js +8 -6
- package/src/isv/deep-links/get-transaction-link.js +8 -6
- package/src/isv/index.js +6 -0
- package/src/isv/invitations/index.js +5 -0
- package/src/isv/oauth2/get-token-info.js +10 -5
- package/src/isv/oauth2/obtain-token.js +9 -4
- package/src/isv/oauth2/token-helper.js +28 -26
- package/src/isv/poi/cancel-price.js +9 -2
- package/src/isv/poi/get-poi.js +4 -3
- package/src/isv/poi/get-qrcode.js +40 -9
- package/src/isv/poi/get-status.js +196 -168
- package/src/isv/poi/list-pois.js +6 -6
- package/src/isv/poi/set-price.js +40 -53
- package/src/isv/products/audios.js +8 -2
- package/src/isv/products/create-product.js +2 -0
- package/src/isv/products/delete-product.js +2 -0
- package/src/isv/products/get-product-image.js +2 -0
- package/src/isv/products/get-product.js +2 -0
- package/src/isv/products/list-products.js +2 -0
- package/src/isv/products/schedules.js +6 -0
- package/src/isv/products/update-product.js +2 -0
- package/src/isv/reference/index.js +2 -0
- package/src/isv/transactions/cancel-transaction.js +2 -0
- package/src/isv/transactions/create-transaction.js +2 -0
- package/src/isv/transactions/get-status.js +3 -1
- package/src/isv/transactions/process-transaction.js +2 -0
- package/src/isv/transactions/simulate-callback.js +21 -10
- package/src/isv/transactions/transaction-history.js +2 -0
- package/src/merchant/data/export-report.js +2 -0
- package/src/merchant/data/generate-report.js +2 -0
- package/src/merchant/data/get-export-list.js +2 -0
- package/src/merchant/data/get-report-requests.js +2 -0
- package/src/merchant/data/get-report-status.js +2 -0
- package/src/merchant/data/index.js +15 -10
- package/src/merchant/data/list-reports.js +2 -0
- package/src/merchant/deep-links/delete-product-link.js +3 -2
- package/src/merchant/deep-links/delete-transaction-link.js +3 -2
- package/src/merchant/deep-links/get-product-link.js +8 -6
- package/src/merchant/deep-links/get-transaction-link.js +8 -6
- package/src/merchant/index.js +7 -1
- package/src/merchant/logs/index.js +4 -0
- package/src/merchant/products/audios.js +15 -14
- package/src/merchant/products/create-product.js +3 -2
- package/src/merchant/products/delete-product.js +3 -2
- package/src/merchant/products/get-product-image.js +3 -2
- package/src/merchant/products/get-product.js +3 -2
- package/src/merchant/products/list-products.js +3 -2
- package/src/merchant/products/schedules.js +11 -10
- package/src/merchant/products/update-product.js +3 -2
- package/src/merchant/transactions/cancel-transaction.js +3 -2
- package/src/merchant/transactions/create-transaction.js +3 -1
- package/src/merchant/transactions/get-status.js +4 -3
- package/src/merchant/transactions/process-transaction.js +5 -4
- package/src/merchant/transactions/simulate-callback.js +325 -313
- package/src/merchant/transactions/transaction-history.js +7 -6
- package/src/payment-institution/data/index.js +15 -14
- package/src/payment-institution/deep-links/delete-transaction-link.js +3 -2
- package/src/payment-institution/deep-links/get-transaction-link.js +8 -6
- package/src/payment-institution/transactions/create-pi-transaction.js +4 -3
- package/src/payment-institution/transactions/finalize-transaction.js +6 -3
- package/src/payment-institution/transactions/get-transaction-history.js +8 -5
- package/src/payment-institution/transactions/get-transaction-status.js +16 -13
- package/src/payment-institution/transactions/process-pi-transaction.js +7 -6
- package/src/payment-institution/transactions/simulate-pi-callback.js +388 -375
- package/src/payment-institution/transactions/soundbite-transaction.js +6 -5
- package/src/proxy-server.js +25 -0
- package/src/shared/placements/api.js +51 -0
- package/src/shared/placements/tools.js +519 -0
- package/src/shared/poi/poi-create-api.js +4 -1
- package/src/shared/products/products-api.js +36 -25
- package/src/shared/shops/shops-api.js +2 -0
- package/src/shared/tool-annotations.js +53 -0
- package/src/tools/advanced-code-generator.js +17 -265
- package/src/utils/code-examples/common/auth-examples.js +1 -1
- package/src/utils/code-examples/isv/products.js +1 -1
- package/src/utils/code-examples/isv/transactions.js +1 -1
- package/src/utils/code-examples/merchant/transactions.js +1 -1
- package/src/utils/format-request.js +2 -0
- package/src/utils/json-formatter.js +2 -0
- package/src/utils/server-info.js +2 -0
- package/src/utils/code-examples.js +0 -646
|
@@ -3,6 +3,7 @@ import { createJWTToken } from '../../core/auth/jwt-token.js';
|
|
|
3
3
|
import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
|
|
4
4
|
import { apiErrorResult } from '../../shared/api-errors.js';
|
|
5
5
|
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
6
|
+
import { CHANGES, CREATES, READS } from '../../shared/tool-annotations.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Merchant invitations - how an ISV onboards a merchant onto payware.
|
|
@@ -181,6 +182,7 @@ ${result.error.guidance ? `\n${result.error.guidance}` : ''}
|
|
|
181
182
|
|
|
182
183
|
export const createInvitationTool = {
|
|
183
184
|
name: 'payware_isv_create_invitation',
|
|
185
|
+
annotations: CREATES,
|
|
184
186
|
description: `Invite a merchant to join payware through this ISV. **This is the start of the ISV onboarding flow.**
|
|
185
187
|
|
|
186
188
|
**Endpoint:** POST /isv/invitations -> 201 Created
|
|
@@ -300,6 +302,7 @@ to start acting on their behalf.
|
|
|
300
302
|
|
|
301
303
|
export const listInvitationsTool = {
|
|
302
304
|
name: 'payware_isv_list_invitations',
|
|
305
|
+
annotations: READS,
|
|
303
306
|
description: `List the merchant invitations this ISV has created, newest first.
|
|
304
307
|
|
|
305
308
|
**Endpoint:** GET /isv/invitations - paginated
|
|
@@ -362,6 +365,7 @@ to was deleted.
|
|
|
362
365
|
|
|
363
366
|
export const getInvitationTool = {
|
|
364
367
|
name: 'payware_isv_get_invitation',
|
|
368
|
+
annotations: READS,
|
|
365
369
|
description: `Get full details of one invitation, including its link and the merchant data it pre-fills.
|
|
366
370
|
|
|
367
371
|
**Endpoint:** GET /isv/invitations/{invitationId}
|
|
@@ -416,6 +420,7 @@ ${inv.invitationLink}
|
|
|
416
420
|
|
|
417
421
|
export const cancelInvitationTool = {
|
|
418
422
|
name: 'payware_isv_cancel_invitation',
|
|
423
|
+
annotations: CHANGES,
|
|
419
424
|
description: `Cancel a PENDING invitation. **The link stops working immediately.**
|
|
420
425
|
|
|
421
426
|
**Endpoint:** DELETE /isv/invitations/{invitationId} -> 204 No Content
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
* Use this to check token status and present information in POS software UI.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { READS } from '../../shared/tool-annotations.js';
|
|
9
|
+
|
|
8
10
|
export const getTokenInfoTool = {
|
|
9
11
|
name: 'payware_authorization_oauth2_get_token_info',
|
|
12
|
+
annotations: READS,
|
|
10
13
|
description: `Get information about an OAuth2 access token.
|
|
11
14
|
|
|
12
15
|
This endpoint exposes information about access tokens, including their status.
|
|
@@ -76,18 +79,20 @@ Auth: Requires ISV JWT token`,
|
|
|
76
79
|
text: `📋 **OAuth2 Token Information**
|
|
77
80
|
|
|
78
81
|
🔑 **Token Details:**
|
|
79
|
-
- **Access Token**: ${result.
|
|
80
|
-
- **Token Type**: ${result.
|
|
82
|
+
- **Access Token**: ${result.accessToken}
|
|
83
|
+
- **Token Type**: ${result.tokenType}
|
|
81
84
|
- **Status**: ${statusEmoji[result.status]} ${result.status}
|
|
82
85
|
- **Description**: ${statusDescription[result.status]}
|
|
83
86
|
- **Scope**: ${result.scope}
|
|
84
|
-
- **Expires**: ${result.
|
|
87
|
+
- **Expires**: ${result.expiresIn == null ? 'No expiration date' : result.expiresIn === 0 ? 'Expired - rotate with POST /oauth2/tokens/{token}/rotate' : `${result.expiresIn} seconds (~${Math.floor(result.expiresIn / 86400)} days)`}
|
|
85
88
|
|
|
86
|
-
${result.status === 'GRANTED' ?
|
|
89
|
+
${result.status === 'GRANTED' && result.expiresIn === 0 ?
|
|
90
|
+
'⌛ **Token has expired - rotate it with POST /oauth2/tokens/{token}/rotate (no merchant consent needed)**' :
|
|
91
|
+
result.status === 'GRANTED' ?
|
|
87
92
|
'✅ **Token is ready for use in API requests**' :
|
|
88
93
|
result.status === 'PENDING' ?
|
|
89
94
|
'⏳ **Token is pending - wait for merchant approval**' :
|
|
90
|
-
'❌ **Token is revoked
|
|
95
|
+
'❌ **Token is revoked, and revocation is final.** Requesting a token again returns this same revoked token; the merchant must consent again through an AUTHORIZATION_ONLY invitation (payware_isv_create_invitation)'
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
📋 **Usage Notes:**
|
|
@@ -5,14 +5,20 @@
|
|
|
5
5
|
* This is the first step in the ISV authorization flow.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { CREATES } from '../../shared/tool-annotations.js';
|
|
9
|
+
|
|
8
10
|
export const obtainTokenTool = {
|
|
9
11
|
name: 'payware_authorization_oauth2_obtain_token',
|
|
12
|
+
annotations: CREATES,
|
|
10
13
|
description: `Obtain an OAuth2 access token for a merchant.
|
|
11
14
|
|
|
12
15
|
ISVs must be authorized by payware registered merchants to make requests on their behalf.
|
|
13
16
|
This endpoint allows ISVs to request a token using the merchant's credentials.
|
|
14
17
|
|
|
15
|
-
IMPORTANT:
|
|
18
|
+
IMPORTANT: A token requested this way expires 180 days after the merchant grants authorization.
|
|
19
|
+
expiresIn in the response gives the seconds remaining (null = no expiration date). Rotate it with
|
|
20
|
+
POST /oauth2/tokens/{token}/rotate, before or after expiry - no merchant consent is needed.
|
|
21
|
+
Requesting again for the same merchant returns the existing token rather than a second one.
|
|
16
22
|
Store tokens securely using strong encryption.
|
|
17
23
|
|
|
18
24
|
Endpoint: POST /oauth2/tokens
|
|
@@ -99,7 +105,7 @@ Auth: Requires ISV JWT token with aud: "https://payware.eu"`,
|
|
|
99
105
|
- **Token Type**: ${result.tokenType}
|
|
100
106
|
- **Status**: ${result.status}
|
|
101
107
|
- **Scope**: ${result.scope}
|
|
102
|
-
- **Expires**: ${result.expiresIn
|
|
108
|
+
- **Expires**: ${result.expiresIn == null ? 'No expiration date' : result.expiresIn === 0 ? 'Expired - rotate with POST /oauth2/tokens/{token}/rotate' : `${result.expiresIn} seconds (~${Math.floor(result.expiresIn / 86400)} days)`}
|
|
103
109
|
|
|
104
110
|
📋 **Copy this token for next operations:**
|
|
105
111
|
\`${result.accessToken}\`
|
|
@@ -110,7 +116,7 @@ Auth: Requires ISV JWT token with aud: "https://payware.eu"`,
|
|
|
110
116
|
- Use this token in the "sub" claim of future JWT requests
|
|
111
117
|
|
|
112
118
|
📋 **Next Steps:**
|
|
113
|
-
1. Check token status: Use token \`${result.accessToken}\` with
|
|
119
|
+
1. Check token status: Use token \`${result.accessToken}\` with payware_authorization_oauth2_get_token_info
|
|
114
120
|
2. Wait for merchant approval (status will change from PENDING to GRANTED)
|
|
115
121
|
3. Use this token in JWT "sub" claim for API requests to merchant data
|
|
116
122
|
4. Set JWT "aud" claim to the merchant's partnerId (${finalClientId}) for API calls`
|
|
@@ -191,7 +197,6 @@ ${JSON.stringify(errorDetails, null, 2)}
|
|
|
191
197
|
- Verify merchant partnerId (clientId) is correct
|
|
192
198
|
- Ensure merchant secret is properly base64 encoded
|
|
193
199
|
- Check if merchant account is active
|
|
194
|
-
- Confirm no existing token for this merchant
|
|
195
200
|
- Verify ISV JWT token is properly signed for OAuth2 requests`
|
|
196
201
|
}]
|
|
197
202
|
};
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import { obtainTokenTool } from './obtain-token.js';
|
|
7
7
|
import { getTokenInfoTool } from './get-token-info.js';
|
|
8
|
+
import { CREATES } from '../../shared/tool-annotations.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Helper tool to create or find OAuth2 tokens with clear output
|
|
11
12
|
*/
|
|
12
13
|
export const tokenHelperTool = {
|
|
13
14
|
name: 'payware_authorization_oauth2_token_helper',
|
|
15
|
+
annotations: CREATES,
|
|
14
16
|
description: `OAuth2 Token Helper - Create or manage tokens with clear output.
|
|
15
17
|
|
|
16
18
|
This tool helps you:
|
|
@@ -54,24 +56,30 @@ Use this when you need a token but aren't sure if one exists or what it is.`,
|
|
|
54
56
|
text: `📋 **OAuth2 Token Management Help**
|
|
55
57
|
|
|
56
58
|
🔑 **About OAuth2 Tokens:**
|
|
57
|
-
-
|
|
58
|
-
- Tokens
|
|
59
|
-
-
|
|
59
|
+
- Requesting a token again for the same merchant returns the existing one, not a second one
|
|
60
|
+
- Tokens requested this way expire 180 days after the merchant grants authorization
|
|
61
|
+
- Rotate with POST /oauth2/tokens/{token}/rotate - works on expired tokens too, no merchant consent needed
|
|
62
|
+
- Token status: PENDING → GRANTED (after merchant approval); REVOKED is final
|
|
60
63
|
|
|
61
64
|
🎯 **To get your token:**
|
|
62
65
|
|
|
63
|
-
**Option 1:
|
|
64
|
-
Use: \`
|
|
65
|
-
-
|
|
66
|
+
**Option 1: Request a token**
|
|
67
|
+
Use: \`payware_authorization_oauth2_obtain_token\`
|
|
68
|
+
- Returns a new PENDING token, or the existing token if this merchant already has one
|
|
66
69
|
- On failure the server names the reason (e.g. client not found, client disabled)
|
|
67
70
|
|
|
68
71
|
**Option 2: Check a known token**
|
|
69
|
-
Use: \`
|
|
70
|
-
- Shows current status (PENDING/GRANTED/REVOKED)
|
|
72
|
+
Use: \`payware_authorization_oauth2_get_token_info\` with your saved token
|
|
73
|
+
- Shows current status (PENDING/GRANTED/REVOKED) and expiry
|
|
71
74
|
|
|
72
|
-
**Option 3:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
**Option 3: If you lost the token**
|
|
76
|
+
Nothing needs revoking - the token can be retrieved:
|
|
77
|
+
- Request it again with Option 1, which returns the existing token, or
|
|
78
|
+
- Call GET /oauth2/tokens, which lists every token issued to your ISV with its value and status
|
|
79
|
+
|
|
80
|
+
⚠️ **Never ask the merchant to revoke a token to get a new one.** Revocation is final: requesting
|
|
81
|
+
again afterwards returns the same REVOKED token, and the only way back is a fresh consent through an
|
|
82
|
+
AUTHORIZATION_ONLY invitation (\`payware_isv_create_invitation\`). To replace a token value, rotate it.
|
|
75
83
|
|
|
76
84
|
🔐 **Security:**
|
|
77
85
|
- Always store tokens securely
|
|
@@ -94,25 +102,19 @@ Use: \`payware_oauth2_get_token_info\` with your saved token
|
|
|
94
102
|
type: 'text',
|
|
95
103
|
text: `⚠️ **Token Already Exists for This Merchant**
|
|
96
104
|
|
|
97
|
-
🔍 **
|
|
105
|
+
🔍 **A token already exists for this merchant, and it can be retrieved.**
|
|
98
106
|
|
|
99
107
|
📋 **To find your token:**
|
|
100
108
|
|
|
101
|
-
**Option 1:
|
|
102
|
-
-
|
|
103
|
-
- Environment variables file
|
|
104
|
-
- Secure configuration management
|
|
105
|
-
- Password manager
|
|
109
|
+
**Option 1: List your tokens**
|
|
110
|
+
Call GET /oauth2/tokens - it lists every token issued to your ISV with its value and status.
|
|
106
111
|
|
|
107
112
|
**Option 2: If you have the token value**
|
|
108
|
-
Use: \`
|
|
109
|
-
|
|
110
|
-
**Option 3: Create new token**
|
|
111
|
-
1. Contact the merchant (Partner ID: ${process.env.PAYWARE_OAUTH_CLIENT_ID || 'not configured'})
|
|
112
|
-
2. Ask them to revoke the existing token
|
|
113
|
-
3. Then use \`payware_oauth2_obtain_token\` to create a new one
|
|
113
|
+
Use: \`payware_authorization_oauth2_get_token_info\` with your token to check its status
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
**Option 3: Need a different value?**
|
|
116
|
+
Rotate it with POST /oauth2/tokens/{token}/rotate. Do not ask the merchant to revoke it - revocation
|
|
117
|
+
is final, and requesting again afterwards returns the same REVOKED token.
|
|
116
118
|
|
|
117
119
|
📋 **For immediate help:**
|
|
118
120
|
Run this tool with action='help' for more detailed guidance.`
|
|
@@ -138,8 +140,8 @@ ${token}
|
|
|
138
140
|
\`\`\`
|
|
139
141
|
|
|
140
142
|
🔄 **Next Steps:**
|
|
141
|
-
1. **SAVE THIS TOKEN** securely (you
|
|
142
|
-
2. Check status: \`
|
|
143
|
+
1. **SAVE THIS TOKEN** securely (if you lose it, GET /oauth2/tokens lists it again)
|
|
144
|
+
2. Check status: \`payware_authorization_oauth2_get_token_info\` with token: \`${token}\`
|
|
143
145
|
3. Wait for merchant approval (status will change to GRANTED)
|
|
144
146
|
4. Use token in API requests once GRANTED`
|
|
145
147
|
}]
|
|
@@ -2,6 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
3
|
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
4
|
import { apiErrorResult } from '../../shared/api-errors.js';
|
|
5
|
+
import { CHANGES } from '../../shared/tool-annotations.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Cancel pending price on a POI via ISV authentication
|
|
@@ -57,13 +58,19 @@ export async function cancelPOIPrice({ poiId, merchantPartnerId, oauth2Token, us
|
|
|
57
58
|
*/
|
|
58
59
|
export const cancelPOIPriceTool = {
|
|
59
60
|
name: "payware_poi_cancel_price",
|
|
61
|
+
annotations: CHANGES,
|
|
60
62
|
description: `Cancel a pending price on a POI, resetting it to IDLE state.
|
|
61
63
|
|
|
62
64
|
**ISV Authentication:** Uses ISV JWT with merchant partner ID and OAuth2 token.
|
|
63
65
|
**Endpoint:** DELETE /poi/{poiId}/price
|
|
64
|
-
**Use Case:** Cancel a price that was set but
|
|
66
|
+
**Use Case:** Cancel a price that was set but not yet scanned (e.g., order cancelled).
|
|
65
67
|
|
|
66
|
-
The POI
|
|
68
|
+
The POI returns to IDLE and is ready for a new price.
|
|
69
|
+
|
|
70
|
+
**Only before the scan.** The scan is the customer's bank processing the payment, so from then on a POI
|
|
71
|
+
sale cannot be cancelled by the merchant or an ISV, on any plan: this answers 409
|
|
72
|
+
ERR_POI_NO_PENDING_PAYMENT, and cancelling the transaction itself answers 409 ERR_ALREADY_PROCESSED. The
|
|
73
|
+
sale completes or expires; the POI accepts the next price meanwhile.
|
|
67
74
|
|
|
68
75
|
**Required:** POI ID, Merchant Partner ID, and OAuth2 token.`,
|
|
69
76
|
|
package/src/isv/poi/get-poi.js
CHANGED
|
@@ -2,6 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
3
|
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
4
|
import { apiErrorResult } from '../../shared/api-errors.js';
|
|
5
|
+
import { READS } from '../../shared/tool-annotations.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Get POI details via ISV authentication
|
|
@@ -61,6 +62,7 @@ export async function getPOI({ poiId, merchantPartnerId, oauth2Token, useSandbox
|
|
|
61
62
|
*/
|
|
62
63
|
export const getPOITool = {
|
|
63
64
|
name: "payware_poi_get",
|
|
65
|
+
annotations: READS,
|
|
64
66
|
description: `Get details of a specific POI (Point of Interaction).
|
|
65
67
|
|
|
66
68
|
**ISV Authentication:** Uses ISV JWT with merchant partner ID and OAuth2 token.
|
|
@@ -115,8 +117,7 @@ export const getPOITool = {
|
|
|
115
117
|
const statusEmoji = {
|
|
116
118
|
'IDLE': '🟢',
|
|
117
119
|
'READY': '🟡',
|
|
118
|
-
'BUSY': '🔴'
|
|
119
|
-
'DISABLED': '⚫'
|
|
120
|
+
'BUSY': '🔴'
|
|
120
121
|
}[poi.status] || '⚪';
|
|
121
122
|
|
|
122
123
|
return {
|
|
@@ -137,7 +138,7 @@ export const getPOITool = {
|
|
|
137
138
|
- Linked vPOS: ${poi.linkedVposCount || 0} terminals
|
|
138
139
|
|
|
139
140
|
**Current Session:**
|
|
140
|
-
${poi.status
|
|
141
|
+
${poi.status === 'READY' && poi.pendingAmount ? `- Amount: ${poi.pendingAmount} ${poi.pendingCurrency}
|
|
141
142
|
- Expires: ${poi.sessionExpiresAt || 'N/A'}
|
|
142
143
|
- Token: ${poi.sessionToken || 'N/A'}` : '- No active session'}
|
|
143
144
|
|
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import {
|
|
2
|
+
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
3
4
|
import { apiErrorResult } from '../../shared/api-errors.js';
|
|
5
|
+
import { READS } from '../../shared/tool-annotations.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* Get POI QR code image
|
|
7
|
-
*
|
|
8
|
+
* Get POI QR code image via ISV authentication
|
|
9
|
+
*
|
|
10
|
+
* Not a public endpoint: the server resolves the merchant from the token and only answers for that
|
|
11
|
+
* merchant's own POIs (ApiPOIController.getQRCode, V-05), so an unauthenticated request was refused.
|
|
8
12
|
* @param {Object} params - Parameters for QR code request
|
|
9
13
|
* @returns {Object} QR code response
|
|
10
14
|
*/
|
|
11
|
-
export async function getPOIQRCode({ poiId, format = 'PNG', useSandbox = true }) {
|
|
15
|
+
export async function getPOIQRCode({ poiId, format = 'PNG', merchantPartnerId, oauth2Token, useSandbox = true }) {
|
|
12
16
|
if (!poiId) {
|
|
13
17
|
throw new Error('POI ID is required');
|
|
14
18
|
}
|
|
15
19
|
|
|
20
|
+
if (!merchantPartnerId) {
|
|
21
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!oauth2Token) {
|
|
25
|
+
throw new Error('OAuth2 token is required for ISV operations');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Create ISV JWT token (GET request - no body)
|
|
29
|
+
const jwtData = await createJWTForPartner({
|
|
30
|
+
partnerId: getPartnerIdSafe(),
|
|
31
|
+
privateKey: getPrivateKeySafe(useSandbox),
|
|
32
|
+
requestBody: null,
|
|
33
|
+
merchantId: merchantPartnerId,
|
|
34
|
+
oauth2Token
|
|
35
|
+
});
|
|
36
|
+
|
|
16
37
|
const headers = {
|
|
38
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
17
39
|
'Api-Version': '1'
|
|
18
40
|
};
|
|
19
41
|
|
|
@@ -49,26 +71,35 @@ export async function getPOIQRCode({ poiId, format = 'PNG', useSandbox = true })
|
|
|
49
71
|
*/
|
|
50
72
|
export const getPOIQRCodeTool = {
|
|
51
73
|
name: "payware_poi_get_qrcode",
|
|
74
|
+
annotations: READS,
|
|
52
75
|
description: `Generate a QR code image for a POI that customers can scan.
|
|
53
76
|
|
|
54
77
|
**Endpoint:** GET /poi/{poiId}/image
|
|
55
|
-
**Authentication:**
|
|
78
|
+
**Authentication:** On behalf of the merchant that owns the POI
|
|
56
79
|
**Use Case:** Generate QR codes for printing or displaying on screens.
|
|
57
80
|
|
|
58
81
|
**Formats:** PNG (default), SVG, JPG
|
|
59
82
|
|
|
60
83
|
Returns base64-encoded image data that can be saved or displayed.
|
|
61
84
|
|
|
62
|
-
**Required:** POI ID
|
|
85
|
+
**Required:** POI ID, and the merchant partner ID and OAuth2 token to act on its behalf.`,
|
|
63
86
|
|
|
64
87
|
inputSchema: {
|
|
65
88
|
type: "object",
|
|
66
|
-
required: ["poiId"],
|
|
89
|
+
required: ["poiId", "merchantPartnerId", "oauth2Token"],
|
|
67
90
|
properties: {
|
|
68
91
|
poiId: {
|
|
69
92
|
type: "string",
|
|
70
93
|
description: "The POI identifier (format: pi + 8 alphanumeric chars, e.g., piABC12345)"
|
|
71
94
|
},
|
|
95
|
+
merchantPartnerId: {
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "Partner ID of the target merchant (8 alphanumeric characters)"
|
|
98
|
+
},
|
|
99
|
+
oauth2Token: {
|
|
100
|
+
type: "string",
|
|
101
|
+
description: "OAuth2 access token obtained from the merchant"
|
|
102
|
+
},
|
|
72
103
|
format: {
|
|
73
104
|
type: "string",
|
|
74
105
|
enum: ["PNG", "SVG", "JPG"],
|
|
@@ -84,11 +115,11 @@ Returns base64-encoded image data that can be saved or displayed.
|
|
|
84
115
|
},
|
|
85
116
|
|
|
86
117
|
async handler(args) {
|
|
87
|
-
const { poiId, format = 'PNG', useSandbox = true } = args;
|
|
118
|
+
const { poiId, format = 'PNG', merchantPartnerId, oauth2Token, useSandbox = true } = args;
|
|
88
119
|
|
|
89
120
|
if (!poiId) throw new Error("POI ID is required");
|
|
90
121
|
|
|
91
|
-
const result = await getPOIQRCode({ poiId, format, useSandbox });
|
|
122
|
+
const result = await getPOIQRCode({ poiId, format, merchantPartnerId, oauth2Token, useSandbox });
|
|
92
123
|
|
|
93
124
|
if (result.success) {
|
|
94
125
|
const img = result.image;
|