@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,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simulate payment institution callback scenarios for testing
|
|
3
|
+
* Payment institutions receive TRANSACTION_PROCESSED and TRANSACTION_FINALIZED callbacks
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate mock payment institution callback payload
|
|
8
|
+
* @param {string} transactionId - Transaction ID
|
|
9
|
+
* @param {string} callbackType - Callback type (TRANSACTION_PROCESSED, TRANSACTION_FINALIZED)
|
|
10
|
+
* @param {Object} options - Additional options
|
|
11
|
+
* @returns {Object} Mock callback payload
|
|
12
|
+
*/
|
|
13
|
+
export function generateMockPICallback(transactionId, callbackType = 'TRANSACTION_PROCESSED', options = {}) {
|
|
14
|
+
const {
|
|
15
|
+
amount = '57.00',
|
|
16
|
+
currency = 'EUR',
|
|
17
|
+
payerAmount = null,
|
|
18
|
+
payeeAmount = null,
|
|
19
|
+
payeeBIC = 'SBBICID1',
|
|
20
|
+
payeeAccount = 'M-1W-1account2',
|
|
21
|
+
payeeFriendlyName = 'payware',
|
|
22
|
+
payerBIC = 'SBBICID1',
|
|
23
|
+
payerAccount = 'payerAccount',
|
|
24
|
+
payerFriendlyName = 'Demo Financial Institution',
|
|
25
|
+
reasonL1 = '57',
|
|
26
|
+
reasonL2 = null,
|
|
27
|
+
timeToLive = 600,
|
|
28
|
+
initiatedBy = 'PEER',
|
|
29
|
+
transactionType = 'DEFAULT',
|
|
30
|
+
status = 'CONFIRMED',
|
|
31
|
+
statusMessage = null,
|
|
32
|
+
passbackParams = null
|
|
33
|
+
} = options;
|
|
34
|
+
|
|
35
|
+
// Calculate fee like Java implementation: |payerAmount - amount| or |payeeAmount - amount|
|
|
36
|
+
const transactionAmount = parseFloat(amount);
|
|
37
|
+
let fee = '0.60'; // Default fee
|
|
38
|
+
if (payerAmount !== null) {
|
|
39
|
+
fee = Math.abs(parseFloat(payerAmount) - transactionAmount).toFixed(2);
|
|
40
|
+
} else if (payeeAmount !== null) {
|
|
41
|
+
fee = Math.abs(parseFloat(payeeAmount) - transactionAmount).toFixed(2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Build payload based on callback type (matching Java implementation exactly)
|
|
45
|
+
if (callbackType === 'TRANSACTION_PROCESSED') {
|
|
46
|
+
return {
|
|
47
|
+
callbackType,
|
|
48
|
+
transactionId,
|
|
49
|
+
passbackParams,
|
|
50
|
+
amount,
|
|
51
|
+
fee,
|
|
52
|
+
currency,
|
|
53
|
+
payeeBIC,
|
|
54
|
+
payeeAccount,
|
|
55
|
+
payeeFriendlyName,
|
|
56
|
+
payerBIC,
|
|
57
|
+
payerAccount,
|
|
58
|
+
payerFriendlyName,
|
|
59
|
+
reasonL1,
|
|
60
|
+
...(reasonL2 && { reasonL2 }),
|
|
61
|
+
timeToLive,
|
|
62
|
+
transactionType,
|
|
63
|
+
initiatedBy
|
|
64
|
+
};
|
|
65
|
+
} else {
|
|
66
|
+
// TRANSACTION_FINALIZED
|
|
67
|
+
return {
|
|
68
|
+
callbackType,
|
|
69
|
+
transactionId,
|
|
70
|
+
passbackParams,
|
|
71
|
+
amount,
|
|
72
|
+
fee,
|
|
73
|
+
currency,
|
|
74
|
+
status,
|
|
75
|
+
...(statusMessage && { statusMessage }),
|
|
76
|
+
created: Date.now() - 300000, // Created 5 minutes ago (milliseconds)
|
|
77
|
+
finalized: Date.now()
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Simulate callback delivery for payment institutions
|
|
84
|
+
* @param {string} callbackUrl - URL to send callback to
|
|
85
|
+
* @param {Object} payload - Callback payload
|
|
86
|
+
* @returns {Object} Simulation result
|
|
87
|
+
*/
|
|
88
|
+
export async function simulatePICallbackDelivery(callbackUrl, payload) {
|
|
89
|
+
if (!callbackUrl || !callbackUrl.startsWith('http')) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: 'Invalid callback URL provided'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// In a real implementation, this would actually send HTTP POST
|
|
97
|
+
// For simulation, we just return what would be sent
|
|
98
|
+
return {
|
|
99
|
+
success: true,
|
|
100
|
+
url: callbackUrl,
|
|
101
|
+
payload,
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
'Authorization': 'Bearer mock-jwt-token-' + Date.now()
|
|
105
|
+
},
|
|
106
|
+
simulatedAt: new Date().toISOString(),
|
|
107
|
+
note: 'This is a simulation - no actual HTTP request was made. Real payware callbacks use JWT tokens in Authorization header.'
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Payment Institution callback simulation tool implementation
|
|
113
|
+
*/
|
|
114
|
+
export const simulatePICallbackTool = {
|
|
115
|
+
name: "payware_operations_simulate_callback",
|
|
116
|
+
description: "Simulate payment institution callback scenarios for testing webhook handling. Payment institutions receive TRANSACTION_PROCESSED when merchant processes their transaction, and TRANSACTION_FINALIZED when transaction is completed.",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
properties: {
|
|
121
|
+
transactionId: {
|
|
122
|
+
type: "string",
|
|
123
|
+
description: "Transaction ID to simulate callback for"
|
|
124
|
+
},
|
|
125
|
+
callbackType: {
|
|
126
|
+
type: "string",
|
|
127
|
+
enum: ["TRANSACTION_PROCESSED", "TRANSACTION_FINALIZED"],
|
|
128
|
+
description: "Type of callback to simulate",
|
|
129
|
+
default: "TRANSACTION_PROCESSED"
|
|
130
|
+
},
|
|
131
|
+
callbackUrl: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "URL where callback would be sent (for simulation only)",
|
|
134
|
+
format: "uri"
|
|
135
|
+
},
|
|
136
|
+
amount: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "Transaction amount (e.g., '57.00')",
|
|
139
|
+
default: "57.00"
|
|
140
|
+
},
|
|
141
|
+
currency: {
|
|
142
|
+
type: "string",
|
|
143
|
+
enum: ["EUR", "USD", "GBP"],
|
|
144
|
+
description: "Transaction currency",
|
|
145
|
+
default: "EUR"
|
|
146
|
+
},
|
|
147
|
+
fee: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "Fee amount charged by payment institution (e.g., '0.60')",
|
|
150
|
+
default: "0.60"
|
|
151
|
+
},
|
|
152
|
+
payeeBIC: {
|
|
153
|
+
type: "string",
|
|
154
|
+
description: "Payee's BIC code",
|
|
155
|
+
default: "SBBICID1"
|
|
156
|
+
},
|
|
157
|
+
payeeAccount: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Payee account identifier",
|
|
160
|
+
default: "M-1W-1account2"
|
|
161
|
+
},
|
|
162
|
+
payeeFriendlyName: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Payee friendly name",
|
|
165
|
+
default: "payware"
|
|
166
|
+
},
|
|
167
|
+
payerBIC: {
|
|
168
|
+
type: "string",
|
|
169
|
+
description: "Payer's BIC code",
|
|
170
|
+
default: "SBBICID1"
|
|
171
|
+
},
|
|
172
|
+
payerAccount: {
|
|
173
|
+
type: "string",
|
|
174
|
+
description: "Payer account identifier",
|
|
175
|
+
default: "payerAccount"
|
|
176
|
+
},
|
|
177
|
+
payerFriendlyName: {
|
|
178
|
+
type: "string",
|
|
179
|
+
description: "Payer friendly name",
|
|
180
|
+
default: "Demo Financial Institution"
|
|
181
|
+
},
|
|
182
|
+
reasonL1: {
|
|
183
|
+
type: "string",
|
|
184
|
+
description: "Transaction reason line 1",
|
|
185
|
+
default: "57"
|
|
186
|
+
},
|
|
187
|
+
reasonL2: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "Transaction reason line 2 (optional)"
|
|
190
|
+
},
|
|
191
|
+
timeToLive: {
|
|
192
|
+
type: "number",
|
|
193
|
+
description: "Remaining time to live in seconds",
|
|
194
|
+
default: 600
|
|
195
|
+
},
|
|
196
|
+
status: {
|
|
197
|
+
type: "string",
|
|
198
|
+
enum: ["CONFIRMED", "DECLINED", "FAILED", "CANCELLED"],
|
|
199
|
+
description: "Transaction status (only for TRANSACTION_FINALIZED callbacks)",
|
|
200
|
+
default: "CONFIRMED"
|
|
201
|
+
},
|
|
202
|
+
statusMessage: {
|
|
203
|
+
type: "string",
|
|
204
|
+
description: "Status message (only for TRANSACTION_FINALIZED callbacks)"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
required: ["transactionId"]
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
async handler(args) {
|
|
211
|
+
const {
|
|
212
|
+
transactionId,
|
|
213
|
+
callbackType = 'TRANSACTION_PROCESSED',
|
|
214
|
+
callbackUrl,
|
|
215
|
+
amount = '57.00',
|
|
216
|
+
currency = 'EUR',
|
|
217
|
+
fee = '0.60',
|
|
218
|
+
payeeBIC = 'SBBICID1',
|
|
219
|
+
payeeAccount = 'M-1W-1account2',
|
|
220
|
+
payeeFriendlyName = 'payware',
|
|
221
|
+
payerBIC = 'SBBICID1',
|
|
222
|
+
payerAccount = 'payerAccount',
|
|
223
|
+
payerFriendlyName = 'Demo Financial Institution',
|
|
224
|
+
reasonL1 = '57',
|
|
225
|
+
reasonL2,
|
|
226
|
+
timeToLive = 600,
|
|
227
|
+
status = 'CONFIRMED',
|
|
228
|
+
statusMessage
|
|
229
|
+
} = args;
|
|
230
|
+
|
|
231
|
+
if (!transactionId) {
|
|
232
|
+
throw new Error("Transaction ID is required");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Generate mock callback payload
|
|
236
|
+
const payload = generateMockPICallback(transactionId, callbackType, {
|
|
237
|
+
amount,
|
|
238
|
+
currency,
|
|
239
|
+
fee,
|
|
240
|
+
payeeBIC,
|
|
241
|
+
payeeAccount,
|
|
242
|
+
payeeFriendlyName,
|
|
243
|
+
payerBIC,
|
|
244
|
+
payerAccount,
|
|
245
|
+
payerFriendlyName,
|
|
246
|
+
reasonL1,
|
|
247
|
+
reasonL2,
|
|
248
|
+
timeToLive,
|
|
249
|
+
initiatedBy: 'PEER',
|
|
250
|
+
transactionType: 'DEFAULT',
|
|
251
|
+
status,
|
|
252
|
+
statusMessage
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Simulate callback delivery if URL provided
|
|
256
|
+
let deliveryResult = null;
|
|
257
|
+
if (callbackUrl) {
|
|
258
|
+
deliveryResult = await simulatePICallbackDelivery(callbackUrl, payload);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const callbackEmojis = {
|
|
262
|
+
'TRANSACTION_PROCESSED': '🔄',
|
|
263
|
+
'TRANSACTION_FINALIZED': '✅'
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const statusEmojis = {
|
|
267
|
+
'CONFIRMED': '✅',
|
|
268
|
+
'DECLINED': '❌',
|
|
269
|
+
'FAILED': '💥',
|
|
270
|
+
'CANCELLED': '🚫'
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const callbackEmoji = callbackEmojis[callbackType] || '📨';
|
|
274
|
+
const statusEmoji = statusEmojis[status] || '❓';
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
content: [{
|
|
278
|
+
type: "text",
|
|
279
|
+
text: `${callbackEmoji} **Payment Institution Callback Simulation Complete**
|
|
280
|
+
|
|
281
|
+
**Transaction:** ${transactionId}
|
|
282
|
+
**Callback Type:** ${callbackType}
|
|
283
|
+
${callbackType === 'TRANSACTION_FINALIZED' ? `**Status:** ${statusEmoji} ${status}` : ''}
|
|
284
|
+
|
|
285
|
+
**Mock Callback Payload:**
|
|
286
|
+
\`\`\`json
|
|
287
|
+
${JSON.stringify(payload, null, 2)}
|
|
288
|
+
\`\`\`
|
|
289
|
+
|
|
290
|
+
${deliveryResult ? `
|
|
291
|
+
**Callback Delivery Simulation:**
|
|
292
|
+
${deliveryResult.success ? '✅ Callback would be delivered successfully' : '❌ Callback delivery would fail'}
|
|
293
|
+
|
|
294
|
+
**Delivery Details:**
|
|
295
|
+
- URL: ${deliveryResult.url || 'N/A'}
|
|
296
|
+
- Headers: ${JSON.stringify(deliveryResult.headers || {}, null, 2)}
|
|
297
|
+
- Simulated At: ${deliveryResult.simulatedAt || 'N/A'}
|
|
298
|
+
|
|
299
|
+
**Note:** ${deliveryResult.note || 'No actual HTTP request was made'}
|
|
300
|
+
` : '**No callback URL provided** - only payload generated'}
|
|
301
|
+
|
|
302
|
+
**Payment Institution Callback Types:**
|
|
303
|
+
- 🔄 **TRANSACTION_PROCESSED**: Merchant has processed your transaction (ready for finalization)
|
|
304
|
+
- ✅ **TRANSACTION_FINALIZED**: Transaction completed with final status
|
|
305
|
+
|
|
306
|
+
**Transaction Flow:**
|
|
307
|
+
1. Payment Institution creates transaction as SRC (payer) or DST (payee)
|
|
308
|
+
2. Transaction can be processed by merchant OR payment institution → **TRANSACTION_PROCESSED** callback to PI
|
|
309
|
+
3. Transaction can be finalized ONLY by payment institution → **TRANSACTION_FINALIZED** callback to PI
|
|
310
|
+
4. Transaction can be cancelled ONLY by its issuer (creator)
|
|
311
|
+
|
|
312
|
+
**Integration Testing:**
|
|
313
|
+
1. Use this payload to test your payment institution callback handler
|
|
314
|
+
2. Verify handling of both TRANSACTION_PROCESSED and TRANSACTION_FINALIZED
|
|
315
|
+
3. Test different status scenarios for finalized transactions
|
|
316
|
+
4. Ensure proper BIC and account information processing
|
|
317
|
+
|
|
318
|
+
**Next Steps:**
|
|
319
|
+
1. Implement callback endpoint to receive this payload structure
|
|
320
|
+
2. Test with both callback types
|
|
321
|
+
3. Add signature verification in production
|
|
322
|
+
4. Set up proper error handling and retry logic`
|
|
323
|
+
}]
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import FormData from 'form-data';
|
|
3
|
+
import { createJWTToken } from '../../core/auth/jwt-token.js';
|
|
4
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get transaction information using Soundbite file via payware API
|
|
9
|
+
* @param {Object} params - Soundbite transaction parameters
|
|
10
|
+
* @returns {Object} Transaction response
|
|
11
|
+
*/
|
|
12
|
+
export async function getSoundbiteTransaction({
|
|
13
|
+
filePath,
|
|
14
|
+
partnerId,
|
|
15
|
+
privateKey,
|
|
16
|
+
useSandbox = true
|
|
17
|
+
}) {
|
|
18
|
+
if (!filePath) {
|
|
19
|
+
throw new Error('filePath is required for soundbite transaction');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!partnerId || !privateKey) {
|
|
23
|
+
throw new Error('Partner ID and private key are required for proper JWT creation');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let fileBuffer;
|
|
27
|
+
try {
|
|
28
|
+
fileBuffer = readFileSync(filePath);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw new Error(`Failed to read soundbite file: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create form data
|
|
34
|
+
const formData = new FormData();
|
|
35
|
+
formData.append('file', fileBuffer, {
|
|
36
|
+
filename: filePath.split('/').pop() || 'soundbite.lo',
|
|
37
|
+
contentType: 'application/octet-stream'
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// For multipart/form-data requests, we don't calculate contentMd5 the same way
|
|
41
|
+
// The JWT token is created without content MD5 for multipart uploads
|
|
42
|
+
const tokenData = createJWTToken(partnerId, privateKey, null);
|
|
43
|
+
|
|
44
|
+
// Required headers as per payware API documentation
|
|
45
|
+
const headers = {
|
|
46
|
+
'Authorization': `Bearer ${tokenData.token}`,
|
|
47
|
+
'Api-Version': '1', // Required: current API version
|
|
48
|
+
...formData.getHeaders()
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
53
|
+
const response = await axios.post(`${baseUrl}/transactions`, formData, {
|
|
54
|
+
headers,
|
|
55
|
+
maxContentLength: Infinity,
|
|
56
|
+
maxBodyLength: Infinity
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
transaction: response.data,
|
|
62
|
+
requestId: response.headers['x-request-id'],
|
|
63
|
+
timestamp: new Date().toISOString()
|
|
64
|
+
};
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
error: {
|
|
69
|
+
message: error.response?.data?.message || error.message,
|
|
70
|
+
status: error.response?.status,
|
|
71
|
+
code: error.response?.data?.code,
|
|
72
|
+
details: error.response?.data
|
|
73
|
+
},
|
|
74
|
+
timestamp: new Date().toISOString()
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Soundbite transaction tool implementation
|
|
81
|
+
*/
|
|
82
|
+
export const soundbiteTransactionTool = {
|
|
83
|
+
name: "payware_operations_soundbite_transaction",
|
|
84
|
+
description: `Get transaction information using a Soundbite SDK output file. This allows payment institutions to process transactions using audio-based identifiers.
|
|
85
|
+
|
|
86
|
+
**Soundbite Integration:**
|
|
87
|
+
- Upload Soundbite SDK output file (.lo extension)
|
|
88
|
+
- File contains audio-encoded transaction identifier
|
|
89
|
+
- Alternative to QR/barcode scanning for accessibility
|
|
90
|
+
- Returns same transaction information as regular transaction lookup
|
|
91
|
+
|
|
92
|
+
**File Requirements:**
|
|
93
|
+
- File must be output from Soundbite SDK
|
|
94
|
+
- Supported file format: .lo (Soundbite format)
|
|
95
|
+
- File must contain valid transaction identifier
|
|
96
|
+
- Maximum file size limits apply
|
|
97
|
+
|
|
98
|
+
**API Request:**
|
|
99
|
+
- Uses multipart/form-data content type
|
|
100
|
+
- File uploaded as form field named 'file'
|
|
101
|
+
- JWT authentication without contentMd5 (multipart upload)`,
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
filePath: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "Absolute path to the Soundbite SDK output file (typically with .lo extension)"
|
|
108
|
+
},
|
|
109
|
+
partnerId: {
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "Partner ID from payware dashboard. Uses PAYWARE_PARTNER_ID env var as default.",
|
|
112
|
+
default: getPartnerIdSafe()
|
|
113
|
+
},
|
|
114
|
+
privateKey: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "RSA private key for JWT token creation. Uses environment-specific private key as default.",
|
|
117
|
+
default: getPrivateKeySafe()
|
|
118
|
+
},
|
|
119
|
+
useSandbox: {
|
|
120
|
+
type: "boolean",
|
|
121
|
+
description: "Use sandbox environment for testing",
|
|
122
|
+
default: true
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
required: ["filePath"]
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async handler(args) {
|
|
129
|
+
const {
|
|
130
|
+
filePath,
|
|
131
|
+
partnerId = getPartnerIdSafe(),
|
|
132
|
+
privateKey = getPrivateKeySafe(args.useSandbox ?? true),
|
|
133
|
+
useSandbox = true
|
|
134
|
+
} = args;
|
|
135
|
+
|
|
136
|
+
if (!filePath) {
|
|
137
|
+
throw new Error("filePath is required for soundbite transaction");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!partnerId) {
|
|
141
|
+
throw new Error("Partner ID is required. Provide via 'partnerId' parameter or set PAYWARE_PARTNER_ID environment variable.");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!privateKey) {
|
|
145
|
+
throw new Error("Private key is required. Provide via 'privateKey' parameter or set PAYWARE_PRIVATE_KEY environment variable.");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const result = await getSoundbiteTransaction({
|
|
149
|
+
filePath,
|
|
150
|
+
partnerId,
|
|
151
|
+
privateKey,
|
|
152
|
+
useSandbox
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (result.success) {
|
|
156
|
+
const tx = result.transaction;
|
|
157
|
+
const createdDate = tx.created ? new Date(tx.created * 1000).toISOString() : 'N/A';
|
|
158
|
+
const typeDisplay = tx.transactionType || 'DEFAULT';
|
|
159
|
+
const initiatorDisplay = tx.initiatedBy || 'UNKNOWN';
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
content: [{
|
|
163
|
+
type: "text",
|
|
164
|
+
text: `🔊 **Soundbite Transaction Retrieved Successfully**
|
|
165
|
+
|
|
166
|
+
**Transaction Information:**
|
|
167
|
+
- ID: ${tx.transactionId || 'N/A'}
|
|
168
|
+
- Type: ${typeDisplay}
|
|
169
|
+
- Initiated By: ${initiatorDisplay}
|
|
170
|
+
- Status: ⏳ ACTIVE
|
|
171
|
+
- Created: ${createdDate}
|
|
172
|
+
- Remaining TTL: ${tx.timeToLive || 'N/A'} seconds
|
|
173
|
+
|
|
174
|
+
**Transaction Details:**
|
|
175
|
+
- Amount: ${tx.amount || 'N/A'} ${tx.currency || 'N/A'}
|
|
176
|
+
- Reason L1: ${tx.reasonL1 || 'N/A'}
|
|
177
|
+
${tx.reasonL2 ? `- Reason L2: ${tx.reasonL2}` : ''}
|
|
178
|
+
|
|
179
|
+
**Payee Information:**
|
|
180
|
+
- Account: ${tx.payeeAccount || 'N/A'}
|
|
181
|
+
- Friendly Name: ${tx.payeeFriendlyName || 'N/A'}
|
|
182
|
+
- BIC: ${tx.payeeBIC || 'N/A'}
|
|
183
|
+
|
|
184
|
+
**Payer Information:**
|
|
185
|
+
- Account: ${tx.payerAccount || 'N/A'}
|
|
186
|
+
- Friendly Name: ${tx.payerFriendlyName || 'N/A'}
|
|
187
|
+
- BIC: ${tx.payerBIC || 'N/A'}
|
|
188
|
+
|
|
189
|
+
**Soundbite Details:**
|
|
190
|
+
- File Path: ${filePath}
|
|
191
|
+
- File Name: ${filePath.split('/').pop()}
|
|
192
|
+
- Processing Method: Audio-based transaction identifier
|
|
193
|
+
|
|
194
|
+
**Full API Response:**
|
|
195
|
+
\`\`\`json
|
|
196
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
197
|
+
\`\`\`
|
|
198
|
+
|
|
199
|
+
**API Call Details:**
|
|
200
|
+
- Endpoint: POST ${baseUrl}/transactions (multipart/form-data)
|
|
201
|
+
- Request ID: ${result.requestId || 'N/A'}
|
|
202
|
+
- Timestamp: ${result.timestamp}
|
|
203
|
+
|
|
204
|
+
**Next Steps:**
|
|
205
|
+
1. Transaction successfully identified from soundbite file
|
|
206
|
+
2. Use transaction ID: \`${tx.transactionId || 'N/A'}\` for further operations
|
|
207
|
+
3. ${!tx.payerAccount ? 'Process this transaction if you are the payer' : 'Transaction ready for finalization'}
|
|
208
|
+
4. Use \`payware_pi_process_transaction\` to process payment
|
|
209
|
+
5. Use \`payware_pi_finalize_transaction\` to confirm/decline
|
|
210
|
+
|
|
211
|
+
**♿ Accessibility Note:**
|
|
212
|
+
- Soundbite provides audio-based alternative to QR/barcode scanning
|
|
213
|
+
- Enables accessible payment processing for visually impaired users
|
|
214
|
+
- Same functionality as visual transaction identifiers`
|
|
215
|
+
}]
|
|
216
|
+
};
|
|
217
|
+
} else {
|
|
218
|
+
return {
|
|
219
|
+
content: [{
|
|
220
|
+
type: "text",
|
|
221
|
+
text: `❌ **Soundbite Transaction Processing Failed**
|
|
222
|
+
|
|
223
|
+
**File Path:** ${filePath}
|
|
224
|
+
|
|
225
|
+
**Error Details:**
|
|
226
|
+
- Message: ${result.error.message}
|
|
227
|
+
- Status: ${result.error.status || 'N/A'}
|
|
228
|
+
- Code: ${result.error.code || 'N/A'}
|
|
229
|
+
|
|
230
|
+
**Full Error Response:**
|
|
231
|
+
\`\`\`json
|
|
232
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
233
|
+
\`\`\`
|
|
234
|
+
|
|
235
|
+
**Timestamp:** ${result.timestamp}
|
|
236
|
+
|
|
237
|
+
**Common Soundbite Issues:**
|
|
238
|
+
1. **File Not Found**: Verify the file path is correct and accessible
|
|
239
|
+
2. **Invalid File Format**: Ensure file is a valid Soundbite SDK output (.lo format)
|
|
240
|
+
3. **Corrupted Audio Data**: File may be corrupted or invalid
|
|
241
|
+
4. **Transaction Not Found**: Audio may not contain valid transaction identifier
|
|
242
|
+
5. **File Size Limits**: File may exceed maximum upload size
|
|
243
|
+
6. **Authentication Issues**: Verify JWT token and partner credentials
|
|
244
|
+
|
|
245
|
+
**Troubleshooting:**
|
|
246
|
+
1. **File Path**: Ensure file path is absolute and file exists
|
|
247
|
+
2. **File Format**: Verify file is output from Soundbite SDK (usually .lo extension)
|
|
248
|
+
3. **File Integrity**: Check file is not corrupted or modified
|
|
249
|
+
4. **Audio Quality**: Ensure soundbite was captured with sufficient quality
|
|
250
|
+
5. **Transaction Validity**: Verify the original transaction hasn't expired
|
|
251
|
+
6. **Permissions**: Check file read permissions
|
|
252
|
+
|
|
253
|
+
**File Requirements:**
|
|
254
|
+
- ✅ Valid Soundbite SDK output file
|
|
255
|
+
- ✅ Readable file permissions
|
|
256
|
+
- ✅ File size within limits
|
|
257
|
+
- ✅ Contains valid transaction identifier
|
|
258
|
+
- ✅ Transaction still active/valid
|
|
259
|
+
|
|
260
|
+
**Alternative Actions:**
|
|
261
|
+
- Try capturing soundbite again if audio quality was poor
|
|
262
|
+
- Use QR/barcode scanning as alternative
|
|
263
|
+
- Verify original transaction is still active
|
|
264
|
+
- Check Soundbite SDK integration and file generation`
|
|
265
|
+
}]
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|