@payware/mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +92 -0
- package/MCP-SETUP.md +190 -0
- package/README.md +483 -0
- package/check-keys.js +52 -0
- package/keys/README.md +112 -0
- package/mcp-config.json +9 -0
- package/package.json +66 -0
- package/payware-mcp-config.json +12 -0
- package/src/auth/rsa-keys.js +82 -0
- package/src/auth/sandbox-setup.js +187 -0
- package/src/config/env.js +229 -0
- package/src/config/partner-types.js +143 -0
- package/src/core/auth/jwt-factory.js +182 -0
- package/src/core/auth/jwt-token.js +735 -0
- package/src/core/utils/json-serializer.js +100 -0
- package/src/core/utils/key-utils.js +133 -0
- package/src/index.js +237 -0
- package/src/isv/data/index.js +291 -0
- package/src/isv/deep-links/delete-product-link.js +154 -0
- package/src/isv/deep-links/delete-transaction-link.js +154 -0
- package/src/isv/deep-links/get-product-link.js +167 -0
- package/src/isv/deep-links/get-transaction-link.js +167 -0
- package/src/isv/deep-links/index.js +23 -0
- package/src/isv/index.js +103 -0
- package/src/isv/oauth2/create-token-simple.js +46 -0
- package/src/isv/oauth2/get-token-info.js +157 -0
- package/src/isv/oauth2/obtain-token.js +189 -0
- package/src/isv/oauth2/token-helper.js +151 -0
- package/src/isv/products/audios.js +470 -0
- package/src/isv/products/create-product.js +314 -0
- package/src/isv/products/delete-product.js +119 -0
- package/src/isv/products/get-product-image.js +247 -0
- package/src/isv/products/get-product.js +168 -0
- package/src/isv/products/index.js +65 -0
- package/src/isv/products/list-products.js +136 -0
- package/src/isv/products/schedules.js +522 -0
- package/src/isv/products/update-product.js +265 -0
- package/src/isv/transactions/cancel-transaction.js +129 -0
- package/src/isv/transactions/create-transaction.js +361 -0
- package/src/isv/transactions/get-status.js +217 -0
- package/src/isv/transactions/process-transaction.js +145 -0
- package/src/isv/transactions/simulate-callback.js +146 -0
- package/src/isv/transactions/transaction-history.js +186 -0
- package/src/isv/utils/auth.js +159 -0
- package/src/mcp-proxy.js +150 -0
- package/src/merchant/data/export-report.js +108 -0
- package/src/merchant/data/generate-report.js +151 -0
- package/src/merchant/data/get-report-status.js +120 -0
- package/src/merchant/data/index.js +351 -0
- package/src/merchant/deep-links/delete-product-link.js +121 -0
- package/src/merchant/deep-links/delete-transaction-link.js +121 -0
- package/src/merchant/deep-links/get-product-link.js +134 -0
- package/src/merchant/deep-links/get-transaction-link.js +134 -0
- package/src/merchant/deep-links/index.js +23 -0
- package/src/merchant/index.js +92 -0
- package/src/merchant/products/audios.js +606 -0
- package/src/merchant/products/create-product.js +288 -0
- package/src/merchant/products/delete-product.js +111 -0
- package/src/merchant/products/get-product-image.js +252 -0
- package/src/merchant/products/get-product.js +144 -0
- package/src/merchant/products/index.js +65 -0
- package/src/merchant/products/list-products.js +112 -0
- package/src/merchant/products/schedules.js +646 -0
- package/src/merchant/products/update-product.js +282 -0
- package/src/merchant/transactions/cancel-transaction.js +241 -0
- package/src/merchant/transactions/create-transaction.js +482 -0
- package/src/merchant/transactions/get-status.js +196 -0
- package/src/merchant/transactions/process-transaction.js +349 -0
- package/src/merchant/transactions/simulate-callback.js +246 -0
- package/src/merchant/transactions/transaction-history.js +258 -0
- package/src/payment-institution/data/index.js +280 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
- package/src/payment-institution/deep-links/index.js +17 -0
- package/src/payment-institution/index.js +92 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
- package/src/payment-institution/transactions/finalize-transaction.js +340 -0
- package/src/payment-institution/transactions/get-transaction-history.js +269 -0
- package/src/payment-institution/transactions/get-transaction-status.js +234 -0
- package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
- package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
- package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
- package/src/proxy-server.js +205 -0
- package/src/shared/data/data-api.js +372 -0
- package/src/shared/deep-links/api.js +214 -0
- package/src/shared/index.js +44 -0
- package/src/shared/products/products-api.js +872 -0
- package/src/tools/advanced-code-generator.js +2247 -0
- package/src/utils/code-examples/common/auth-examples.js +1482 -0
- package/src/utils/code-examples/common/helpers.js +416 -0
- package/src/utils/code-examples/common/utils-examples.js +591 -0
- package/src/utils/code-examples/frameworks/examples.js +859 -0
- package/src/utils/code-examples/index.js +441 -0
- package/src/utils/code-examples/isv/oauth2.js +600 -0
- package/src/utils/code-examples/isv/products.js +666 -0
- package/src/utils/code-examples/isv/transactions.js +813 -0
- package/src/utils/code-examples/merchant/products.js +497 -0
- package/src/utils/code-examples/merchant/transactions.js +623 -0
- package/src/utils/code-examples/payment-institution/transactions.js +388 -0
- package/src/utils/code-examples/shared/data.js +607 -0
- package/src/utils/code-examples/shared/deep-links.js +662 -0
- package/src/utils/code-examples/shared/soundbites.js +808 -0
- package/src/utils/code-examples.js +646 -0
- package/src/utils/format-request.js +363 -0
- package/src/utils/json-formatter.js +249 -0
- package/src/utils/server-info.js +132 -0
|
@@ -0,0 +1,145 @@
|
|
|
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
|
+
* Process (finalize) a transaction via payware API as an ISV
|
|
7
|
+
*/
|
|
8
|
+
export async function processTransaction({ transactionId, merchantPartnerId, oauth2Token, action = 'CONFIRMED', useSandbox = true }) {
|
|
9
|
+
if (!transactionId) {
|
|
10
|
+
throw new Error('Transaction ID is required');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!merchantPartnerId) {
|
|
14
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!oauth2Token) {
|
|
18
|
+
throw new Error('OAuth2 token is required for ISV operations');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!['CONFIRMED', 'DECLINED'].includes(action)) {
|
|
22
|
+
throw new Error('Action must be either CONFIRMED or DECLINED');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
26
|
+
const privateKey = getPrivateKeySafe(useSandbox);
|
|
27
|
+
|
|
28
|
+
const requestBody = { action };
|
|
29
|
+
|
|
30
|
+
const jwtData = await createJWTForPartner({
|
|
31
|
+
partnerId: isvPartnerId,
|
|
32
|
+
privateKey,
|
|
33
|
+
requestBody,
|
|
34
|
+
merchantId: merchantPartnerId,
|
|
35
|
+
oauth2Token
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Use the same JSON serialization method as the JWT factory for MD5 calculation
|
|
39
|
+
const { createMinimizedJSON } = await import('../../core/utils/json-serializer.js');
|
|
40
|
+
const minimizedBodyString = createMinimizedJSON(requestBody);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
44
|
+
// Send the exact minimized JSON string that was used for MD5 calculation
|
|
45
|
+
const response = await axios.patch(`${baseUrl}/transactions/${transactionId}`, minimizedBodyString, {
|
|
46
|
+
headers: {
|
|
47
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
'Api-Version': '1'
|
|
50
|
+
},
|
|
51
|
+
// Tell axios to send the string as-is, don't serialize it again
|
|
52
|
+
transformRequest: [(data) => data]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return response.data;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error.response) {
|
|
58
|
+
throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const processTransactionTool = {
|
|
65
|
+
name: 'payware_operations_process_transaction',
|
|
66
|
+
description: `Process (finalize) a transaction as an ISV on behalf of a merchant.
|
|
67
|
+
|
|
68
|
+
Allows confirming or declining a transaction. Only ACTIVE transactions can be processed.
|
|
69
|
+
Requires ISV authentication with merchant partner ID and OAuth2 token.`,
|
|
70
|
+
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
required: ['transactionId', 'merchantPartnerId', 'oauth2Token'],
|
|
74
|
+
properties: {
|
|
75
|
+
transactionId: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Transaction ID to process'
|
|
78
|
+
},
|
|
79
|
+
merchantPartnerId: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Partner ID of the target merchant'
|
|
82
|
+
},
|
|
83
|
+
oauth2Token: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'OAuth2 access token obtained from the merchant'
|
|
86
|
+
},
|
|
87
|
+
action: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
enum: ['CONFIRMED', 'DECLINED'],
|
|
90
|
+
default: 'CONFIRMED',
|
|
91
|
+
description: 'Action to perform on the transaction'
|
|
92
|
+
},
|
|
93
|
+
useSandbox: {
|
|
94
|
+
type: 'boolean',
|
|
95
|
+
description: 'Use sandbox environment for testing',
|
|
96
|
+
default: true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
async handler(params) {
|
|
102
|
+
try {
|
|
103
|
+
const result = await processTransaction(params);
|
|
104
|
+
|
|
105
|
+
const actionEmoji = params.action === 'CONFIRMED' ? '✅' : '❌';
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
content: [{
|
|
109
|
+
type: 'text',
|
|
110
|
+
text: `${actionEmoji} Transaction ${params.action} Successfully (ISV -> Merchant: ${params.merchantPartnerId})
|
|
111
|
+
|
|
112
|
+
📋 **Processing Details:**
|
|
113
|
+
- **Transaction ID**: ${params.transactionId}
|
|
114
|
+
- **Action**: ${params.action}
|
|
115
|
+
- **New Status**: ${result.status || params.action}
|
|
116
|
+
- **ISV Partner**: ${getPartnerIdSafe()}
|
|
117
|
+
- **Target Merchant**: ${params.merchantPartnerId}
|
|
118
|
+
|
|
119
|
+
**Raw Response:**
|
|
120
|
+
\`\`\`json
|
|
121
|
+
${JSON.stringify(result, null, 2)}
|
|
122
|
+
\`\`\``
|
|
123
|
+
}]
|
|
124
|
+
};
|
|
125
|
+
} catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
content: [{
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: `❌ Transaction Processing Failed
|
|
130
|
+
|
|
131
|
+
**Error**: ${error.message}
|
|
132
|
+
|
|
133
|
+
**Processing Attempt:**
|
|
134
|
+
- Transaction ID: ${params.transactionId}
|
|
135
|
+
- Action: ${params.action}
|
|
136
|
+
- Merchant: ${params.merchantPartnerId}
|
|
137
|
+
|
|
138
|
+
**ISV Authentication:**
|
|
139
|
+
- OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
|
|
140
|
+
- ISV Partner ID: ${getPartnerIdSafe()}`
|
|
141
|
+
}]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
* Simulate a transaction callback via payware API as an ISV
|
|
7
|
+
*/
|
|
8
|
+
export async function simulateCallback({ transactionId, merchantPartnerId, oauth2Token, action = 'CONFIRMED', useSandbox = true }) {
|
|
9
|
+
if (!transactionId) {
|
|
10
|
+
throw new Error('Transaction ID is required');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!merchantPartnerId) {
|
|
14
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!oauth2Token) {
|
|
18
|
+
throw new Error('OAuth2 token is required for ISV operations');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!['CONFIRMED', 'DECLINED'].includes(action)) {
|
|
22
|
+
throw new Error('Action must be either CONFIRMED or DECLINED');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
26
|
+
const privateKey = getPrivateKeySafe(useSandbox);
|
|
27
|
+
|
|
28
|
+
const requestBody = { action };
|
|
29
|
+
|
|
30
|
+
const jwtData = await createJWTForPartner({
|
|
31
|
+
partnerId: isvPartnerId,
|
|
32
|
+
privateKey,
|
|
33
|
+
requestBody,
|
|
34
|
+
merchantId: merchantPartnerId,
|
|
35
|
+
oauth2Token
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Use the same JSON serialization method as the JWT factory for MD5 calculation
|
|
39
|
+
const { createMinimizedJSON } = await import('../../core/utils/json-serializer.js');
|
|
40
|
+
const minimizedBodyString = createMinimizedJSON(requestBody);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
44
|
+
// Send the exact minimized JSON string that was used for MD5 calculation
|
|
45
|
+
const response = await axios.post(`${baseUrl}/transactions/${transactionId}/simulate-callback`, minimizedBodyString, {
|
|
46
|
+
headers: {
|
|
47
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
'Api-Version': '1'
|
|
50
|
+
},
|
|
51
|
+
// Tell axios to send the string as-is, don't serialize it again
|
|
52
|
+
transformRequest: [(data) => data]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return response.data;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error.response) {
|
|
58
|
+
throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const simulateCallbackTool = {
|
|
65
|
+
name: 'payware_operations_simulate_callback',
|
|
66
|
+
description: `Simulate a transaction callback as an ISV on behalf of a merchant.
|
|
67
|
+
|
|
68
|
+
Triggers a callback to test webhook integration in sandbox environment.
|
|
69
|
+
Requires ISV authentication with merchant partner ID and OAuth2 token.`,
|
|
70
|
+
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
required: ['transactionId', 'merchantPartnerId', 'oauth2Token'],
|
|
74
|
+
properties: {
|
|
75
|
+
transactionId: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Transaction ID to simulate callback for'
|
|
78
|
+
},
|
|
79
|
+
merchantPartnerId: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Partner ID of the target merchant'
|
|
82
|
+
},
|
|
83
|
+
oauth2Token: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'OAuth2 access token obtained from the merchant'
|
|
86
|
+
},
|
|
87
|
+
action: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
enum: ['CONFIRMED', 'DECLINED'],
|
|
90
|
+
default: 'CONFIRMED',
|
|
91
|
+
description: 'Action to simulate in the callback'
|
|
92
|
+
},
|
|
93
|
+
useSandbox: {
|
|
94
|
+
type: 'boolean',
|
|
95
|
+
description: 'Use sandbox environment for testing',
|
|
96
|
+
default: true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
async handler(params) {
|
|
102
|
+
try {
|
|
103
|
+
const result = await simulateCallback(params);
|
|
104
|
+
|
|
105
|
+
const actionEmoji = params.action === 'CONFIRMED' ? '✅' : '❌';
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
content: [{
|
|
109
|
+
type: 'text',
|
|
110
|
+
text: `🔔 Callback Simulated Successfully (ISV -> Merchant: ${params.merchantPartnerId})
|
|
111
|
+
|
|
112
|
+
**Callback Details:**
|
|
113
|
+
- **Transaction ID**: ${params.transactionId}
|
|
114
|
+
- **Simulated Action**: ${actionEmoji} ${params.action}
|
|
115
|
+
- **ISV Partner**: ${getPartnerIdSafe()}
|
|
116
|
+
- **Target Merchant**: ${params.merchantPartnerId}
|
|
117
|
+
|
|
118
|
+
**Use Case**: Testing webhook integration in sandbox environment
|
|
119
|
+
|
|
120
|
+
**Raw Response:**
|
|
121
|
+
\`\`\`json
|
|
122
|
+
${JSON.stringify(result, null, 2)}
|
|
123
|
+
\`\`\``
|
|
124
|
+
}]
|
|
125
|
+
};
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return {
|
|
128
|
+
content: [{
|
|
129
|
+
type: 'text',
|
|
130
|
+
text: `❌ Callback Simulation Failed
|
|
131
|
+
|
|
132
|
+
**Error**: ${error.message}
|
|
133
|
+
|
|
134
|
+
**Simulation Attempt:**
|
|
135
|
+
- Transaction ID: ${params.transactionId}
|
|
136
|
+
- Action: ${params.action}
|
|
137
|
+
- Merchant: ${params.merchantPartnerId}
|
|
138
|
+
|
|
139
|
+
**ISV Authentication:**
|
|
140
|
+
- OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
|
|
141
|
+
- ISV Partner ID: ${getPartnerIdSafe()}`
|
|
142
|
+
}]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
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 transaction history from payware API as an ISV
|
|
7
|
+
*/
|
|
8
|
+
export async function getTransactionHistory({
|
|
9
|
+
merchantPartnerId,
|
|
10
|
+
oauth2Token,
|
|
11
|
+
partnerId,
|
|
12
|
+
transactionId,
|
|
13
|
+
limit = 50,
|
|
14
|
+
offset = 0,
|
|
15
|
+
status,
|
|
16
|
+
from,
|
|
17
|
+
to,
|
|
18
|
+
useSandbox = true
|
|
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
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
29
|
+
const privateKey = getPrivateKeySafe(useSandbox);
|
|
30
|
+
|
|
31
|
+
const jwtData = await createJWTForPartner({
|
|
32
|
+
partnerId: isvPartnerId,
|
|
33
|
+
privateKey,
|
|
34
|
+
requestBody: null,
|
|
35
|
+
merchantId: merchantPartnerId,
|
|
36
|
+
oauth2Token
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const params = new URLSearchParams();
|
|
40
|
+
if (partnerId) params.append('partnerId', partnerId);
|
|
41
|
+
if (transactionId) params.append('transactionId', transactionId);
|
|
42
|
+
if (limit) params.append('limit', limit.toString());
|
|
43
|
+
if (offset) params.append('offset', offset.toString());
|
|
44
|
+
if (status) params.append('status', status);
|
|
45
|
+
if (from) params.append('from', from);
|
|
46
|
+
if (to) params.append('to', to);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
50
|
+
const url = `${baseUrl}/transactions-history?${params.toString()}`;
|
|
51
|
+
const response = await axios.get(url, {
|
|
52
|
+
headers: {
|
|
53
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
'Api-Version': '1'
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return response.data;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error.response) {
|
|
62
|
+
throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const getTransactionHistoryTool = {
|
|
69
|
+
name: 'payware_operations_get_transaction_history',
|
|
70
|
+
description: `Get transaction history as an ISV on behalf of a merchant.
|
|
71
|
+
|
|
72
|
+
Retrieves both active and completed transactions with optional filtering.
|
|
73
|
+
Requires ISV authentication with merchant partner ID and OAuth2 token.`,
|
|
74
|
+
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
required: ['merchantPartnerId', 'oauth2Token'],
|
|
78
|
+
properties: {
|
|
79
|
+
merchantPartnerId: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Partner ID of the target merchant'
|
|
82
|
+
},
|
|
83
|
+
oauth2Token: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'OAuth2 access token obtained from the merchant'
|
|
86
|
+
},
|
|
87
|
+
partnerId: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
description: 'Filter by partner ID (optional)'
|
|
90
|
+
},
|
|
91
|
+
transactionId: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'Filter by specific transaction ID (optional)'
|
|
94
|
+
},
|
|
95
|
+
limit: {
|
|
96
|
+
type: 'number',
|
|
97
|
+
default: 50,
|
|
98
|
+
description: 'Maximum number of results to return'
|
|
99
|
+
},
|
|
100
|
+
offset: {
|
|
101
|
+
type: 'number',
|
|
102
|
+
default: 0,
|
|
103
|
+
description: 'Number of results to skip for pagination'
|
|
104
|
+
},
|
|
105
|
+
status: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
enum: ['ACTIVE', 'CONFIRMED', 'DECLINED', 'FAILED', 'EXPIRED', 'CANCELLED'],
|
|
108
|
+
description: 'Filter by transaction status'
|
|
109
|
+
},
|
|
110
|
+
from: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'Start date for filtering (YYYY-MM-DD format)'
|
|
113
|
+
},
|
|
114
|
+
to: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'End date for filtering (YYYY-MM-DD format)'
|
|
117
|
+
},
|
|
118
|
+
useSandbox: {
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
description: 'Use sandbox environment for testing',
|
|
121
|
+
default: true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
async handler(params) {
|
|
127
|
+
try {
|
|
128
|
+
const result = await getTransactionHistory(params);
|
|
129
|
+
|
|
130
|
+
const transactions = result.transactions || [];
|
|
131
|
+
const totalCount = result.totalCount || transactions.length;
|
|
132
|
+
|
|
133
|
+
const formatTransaction = (tx) => {
|
|
134
|
+
const statusEmojis = {
|
|
135
|
+
'ACTIVE': '⏳',
|
|
136
|
+
'CONFIRMED': '✅',
|
|
137
|
+
'DECLINED': '❌',
|
|
138
|
+
'FAILED': '⚠️',
|
|
139
|
+
'EXPIRED': '⏰',
|
|
140
|
+
'CANCELLED': '🚫'
|
|
141
|
+
};
|
|
142
|
+
const emoji = statusEmojis[tx.status] || '❓';
|
|
143
|
+
return ` ${emoji} **${tx.id}** - ${tx.trData?.amount || '0.00'} ${tx.trData?.currency || 'EUR'} - ${tx.status} - ${tx.createdAt || 'N/A'}`;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
content: [{
|
|
148
|
+
type: 'text',
|
|
149
|
+
text: `📈 **Transaction History Retrieved (ISV -> Merchant: ${params.merchantPartnerId})**
|
|
150
|
+
|
|
151
|
+
**ISV Integration:**
|
|
152
|
+
- ISV Partner: ${getPartnerIdSafe()}
|
|
153
|
+
- Target Merchant: ${params.merchantPartnerId}
|
|
154
|
+
- OAuth2 Token: ${params.oauth2Token.substring(0, 8)}...
|
|
155
|
+
|
|
156
|
+
**Results:** ${transactions.length} of ${totalCount} transactions
|
|
157
|
+
|
|
158
|
+
**Transactions:**
|
|
159
|
+
${transactions.length > 0 ? transactions.map(formatTransaction).join('\n') : ' No transactions found'}
|
|
160
|
+
|
|
161
|
+
**Applied Filters:**
|
|
162
|
+
${params.status ? `- Status: ${params.status}\n` : ''}${params.from ? `- From: ${params.from}\n` : ''}${params.to ? `- To: ${params.to}\n` : ''}${params.limit ? `- Limit: ${params.limit}\n` : ''}${params.offset ? `- Offset: ${params.offset}\n` : ''}
|
|
163
|
+
|
|
164
|
+
**Raw Response:**
|
|
165
|
+
\`\`\`json
|
|
166
|
+
${JSON.stringify(result, null, 2)}
|
|
167
|
+
\`\`\``
|
|
168
|
+
}]
|
|
169
|
+
};
|
|
170
|
+
} catch (error) {
|
|
171
|
+
return {
|
|
172
|
+
content: [{
|
|
173
|
+
type: 'text',
|
|
174
|
+
text: `❌ Transaction History Request Failed
|
|
175
|
+
|
|
176
|
+
**Error**: ${error.message}
|
|
177
|
+
|
|
178
|
+
**ISV Authentication:**
|
|
179
|
+
- Merchant Partner ID: ${params.merchantPartnerId}
|
|
180
|
+
- OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
|
|
181
|
+
- ISV Partner ID: ${getPartnerIdSafe()}`
|
|
182
|
+
}]
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISV-specific authentication utilities
|
|
3
|
+
* Handles OAuth2 and JWT token creation for ISV partners
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createJWTForPartner, getAuthHeaders } from '../../core/auth/jwt-factory.js';
|
|
7
|
+
import { getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create ISV JWT token for API requests
|
|
11
|
+
* @param {Object} options - JWT creation options
|
|
12
|
+
* @param {string} options.merchantPartnerId - Target merchant partner ID (required for API calls)
|
|
13
|
+
* @param {string} options.oauth2Token - OAuth2 token (required for API calls)
|
|
14
|
+
* @param {Object} options.requestBody - Request body for POST/PUT/PATCH requests
|
|
15
|
+
* @param {string} options.audience - JWT audience (defaults to merchant partner ID, or https://payware.eu for OAuth2 requests)
|
|
16
|
+
* @param {boolean} options.isOAuth2Request - Set to true for OAuth2 endpoint requests
|
|
17
|
+
* @param {boolean} options.isGetRequest - Set to true for GET requests (no body)
|
|
18
|
+
* @returns {string} JWT token string
|
|
19
|
+
*/
|
|
20
|
+
export async function createISVJWT(options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
merchantPartnerId,
|
|
23
|
+
oauth2Token,
|
|
24
|
+
requestBody = null,
|
|
25
|
+
audience = null,
|
|
26
|
+
isOAuth2Request = false,
|
|
27
|
+
isGetRequest = false
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
31
|
+
const privateKey = getPrivateKeySafe();
|
|
32
|
+
|
|
33
|
+
// For OAuth2 requests, we need special handling
|
|
34
|
+
if (isOAuth2Request) {
|
|
35
|
+
return await createOAuth2JWT({
|
|
36
|
+
isvPartnerId,
|
|
37
|
+
privateKey,
|
|
38
|
+
requestBody,
|
|
39
|
+
audience: audience || 'https://payware.eu'
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// For regular API requests, we need merchant partner ID and OAuth2 token
|
|
44
|
+
if (!merchantPartnerId) {
|
|
45
|
+
throw new Error('Merchant Partner ID is required for ISV API requests');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!oauth2Token) {
|
|
49
|
+
throw new Error('OAuth2 token is required for ISV API requests');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const jwtData = await createJWTForPartner({
|
|
53
|
+
partnerId: isvPartnerId,
|
|
54
|
+
privateKey,
|
|
55
|
+
requestBody: isGetRequest ? null : requestBody,
|
|
56
|
+
merchantId: merchantPartnerId,
|
|
57
|
+
oauth2Token
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return jwtData.token;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create JWT specifically for OAuth2 endpoint requests
|
|
65
|
+
* @param {Object} options - OAuth2 JWT options
|
|
66
|
+
* @returns {string} JWT token string
|
|
67
|
+
*/
|
|
68
|
+
async function createOAuth2JWT({ isvPartnerId, privateKey, requestBody, audience }) {
|
|
69
|
+
// Dynamic imports to avoid circular dependencies
|
|
70
|
+
const jwt = await import('jsonwebtoken');
|
|
71
|
+
const crypto = await import('crypto');
|
|
72
|
+
const { normalizePrivateKey } = await import('../../core/utils/key-utils.js');
|
|
73
|
+
|
|
74
|
+
const normalizedKey = normalizePrivateKey(privateKey);
|
|
75
|
+
const now = Math.floor(Date.now() / 1000);
|
|
76
|
+
|
|
77
|
+
// JWT Header
|
|
78
|
+
const header = {
|
|
79
|
+
alg: 'RS256',
|
|
80
|
+
typ: 'JWT'
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Add contentMd5 to header if request body exists
|
|
84
|
+
if (requestBody) {
|
|
85
|
+
// Use standard JSON.stringify to match axios serialization (preserves property order)
|
|
86
|
+
const bodyString = JSON.stringify(requestBody);
|
|
87
|
+
header.contentMd5 = crypto.default.createHash('md5').update(bodyString, 'utf8').digest('base64');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// JWT Payload for OAuth2 requests
|
|
91
|
+
const payload = {
|
|
92
|
+
iss: isvPartnerId, // ISV's partner ID
|
|
93
|
+
aud: audience, // https://payware.eu for OAuth2 requests
|
|
94
|
+
iat: now
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const token = jwt.default.sign(payload, normalizedKey, {
|
|
98
|
+
algorithm: 'RS256',
|
|
99
|
+
header: header
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return token;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create authentication headers for ISV requests
|
|
107
|
+
* @param {string} jwt - JWT token
|
|
108
|
+
* @param {boolean} isOAuth2Request - Whether this is for OAuth2 endpoints (no Api-Version header)
|
|
109
|
+
* @returns {Object} Headers object with Authorization and Content-Type
|
|
110
|
+
*/
|
|
111
|
+
export function createISVAuthHeaders(jwt, isOAuth2Request = false) {
|
|
112
|
+
if (isOAuth2Request) {
|
|
113
|
+
// OAuth2 endpoints don't need Api-Version header
|
|
114
|
+
return {
|
|
115
|
+
'Authorization': `Bearer ${jwt}`,
|
|
116
|
+
'Content-Type': 'application/json'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Regular API endpoints need Api-Version header
|
|
121
|
+
return getAuthHeaders(jwt);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validate ISV request parameters
|
|
126
|
+
* @param {Object} params - Parameters to validate
|
|
127
|
+
* @param {boolean} params.requireMerchant - Whether merchant partner ID is required
|
|
128
|
+
* @param {boolean} params.requireToken - Whether OAuth2 token is required
|
|
129
|
+
* @throws {Error} If validation fails
|
|
130
|
+
*/
|
|
131
|
+
export function validateISVParams({ merchantPartnerId, oauth2Token, requireMerchant = true, requireToken = true }) {
|
|
132
|
+
if (requireMerchant && !merchantPartnerId) {
|
|
133
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (requireToken && !oauth2Token) {
|
|
137
|
+
throw new Error('OAuth2 token is required for ISV API operations');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Validate partner ID format (basic validation)
|
|
141
|
+
if (merchantPartnerId && !/^[A-Z0-9]{8}$/.test(merchantPartnerId)) {
|
|
142
|
+
console.warn('Merchant Partner ID should be 8 alphanumeric characters (e.g., "PZAYNMVE")');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Extract partner information from ISV context
|
|
148
|
+
* @returns {Object} Partner information
|
|
149
|
+
*/
|
|
150
|
+
export function getISVPartnerInfo() {
|
|
151
|
+
const partnerId = getPartnerIdSafe();
|
|
152
|
+
const privateKey = getPrivateKeySafe();
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
isvPartnerId: partnerId,
|
|
156
|
+
hasPrivateKey: !!privateKey,
|
|
157
|
+
partnerType: 'isv'
|
|
158
|
+
};
|
|
159
|
+
}
|