@payware/mcp-server 1.3.2 → 1.3.3

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.
@@ -1,376 +1,386 @@
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
- paymentMethod = null,
31
- status = 'CONFIRMED',
32
- statusMessage = null,
33
- passbackParams = null,
34
- // The fee breakdown. Present on BOTH payloads whenever the transaction has a fee configuration -
35
- // FINALIZED gained them on 2026-08-21, having previously carried the total without the two
36
- // numbers that produced it. Both are INFORMATIONAL: recomputing the fee from them and submitting
37
- // that at finalize is rejected with ERR_FEE_MISMATCH. Echo `fee` back unchanged instead.
38
- feeFixed = '0.1000',
39
- feeRate = '0.0150',
40
- // Pass fee: null to model the anomaly the server reports by OMITTING the property - a
41
- // transaction with no recorded fee. Deliberately distinguishable from a genuine '0.00'.
42
- fee: feeOverride = undefined
43
- } = options;
44
-
45
- // Calculate fee like the server: |payerAmount - amount| or |payeeAmount - amount|.
46
- const transactionAmount = parseFloat(amount);
47
- let fee = '0.60'; // Default fee
48
- if (payerAmount !== null) {
49
- fee = Math.abs(parseFloat(payerAmount) - transactionAmount).toFixed(2);
50
- } else if (payeeAmount !== null) {
51
- fee = Math.abs(parseFloat(payeeAmount) - transactionAmount).toFixed(2);
52
- }
53
- if (feeOverride !== undefined) {
54
- fee = feeOverride;
55
- }
56
-
57
- // The server's payloads are @JsonInclude(NON_NULL): a property with no value is ABSENT from the
58
- // JSON rather than sent as null. Emitting "passbackParams": null here taught integrators to expect
59
- // a shape the server never sends.
60
- const feeFields = {
61
- ...(fee !== null && fee !== undefined && { fee }),
62
- ...(feeFixed !== null && feeFixed !== undefined && { feeFixed }),
63
- ...(feeRate !== null && feeRate !== undefined && { feeRate })
64
- };
65
-
66
- // Build payload based on callback type (matching Java implementation exactly)
67
- if (callbackType === 'TRANSACTION_PROCESSED') {
68
- return {
69
- callbackType,
70
- transactionId,
71
- ...(passbackParams !== null && passbackParams !== undefined && { passbackParams }),
72
- amount,
73
- ...feeFields,
74
- currency,
75
- payeeBIC,
76
- payeeAccount,
77
- payeeFriendlyName,
78
- payerBIC,
79
- payerAccount,
80
- payerFriendlyName,
81
- reasonL1,
82
- ...(reasonL2 && { reasonL2 }),
83
- timeToLive,
84
- transactionType,
85
- initiatedBy,
86
- ...(paymentMethod && { paymentMethod })
87
- };
88
- } else {
89
- // TRANSACTION_FINALIZED.
90
- //
91
- // transactionType and initiatedBy are deliberately NOT here: the server's finalized builder
92
- // never sets them, so @JsonInclude(NON_NULL) drops them. An institution that needs either for a
93
- // finalized transaction reads it from GET /transactions-history/{transactionId}.
94
- return {
95
- callbackType,
96
- transactionId,
97
- ...(passbackParams !== null && passbackParams !== undefined && { passbackParams }),
98
- amount,
99
- ...feeFields,
100
- currency,
101
- status,
102
- ...(statusMessage && { statusMessage }),
103
- ...(paymentMethod && { paymentMethod }),
104
- created: Date.now() - 300000, // Created 5 minutes ago (milliseconds)
105
- // Absent on EXPIRED: the expiry sweep transitions status in bulk and sets no finalized moment.
106
- ...(status !== 'EXPIRED' && { finalized: Date.now() })
107
- };
108
- }
109
- }
110
-
111
- /**
112
- * Simulate callback delivery for payment institutions
113
- * @param {string} callbackUrl - URL to send callback to
114
- * @param {Object} payload - Callback payload
115
- * @returns {Object} Simulation result
116
- */
117
- export async function simulatePICallbackDelivery(callbackUrl, payload) {
118
- if (!callbackUrl || !callbackUrl.startsWith('http')) {
119
- return {
120
- success: false,
121
- error: 'Invalid callback URL provided'
122
- };
123
- }
124
-
125
- // In a real implementation, this would actually send HTTP POST
126
- // For simulation, we just return what would be sent
127
- return {
128
- success: true,
129
- url: callbackUrl,
130
- payload,
131
- headers: {
132
- 'Content-Type': 'application/json',
133
- 'Authorization': 'Bearer mock-jwt-token-' + Date.now()
134
- },
135
- simulatedAt: new Date().toISOString(),
136
- note: 'This is a simulation - no actual HTTP request was made. Real payware callbacks use JWT tokens in Authorization header.'
137
- };
138
- }
139
-
140
- /**
141
- * Payment Institution callback simulation tool implementation
142
- */
143
- export const simulatePICallbackTool = {
144
- name: "payware_operations_simulate_callback",
145
- 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.",
146
- inputSchema: {
147
- type: "object",
148
- additionalProperties: false,
149
- properties: {
150
- transactionId: {
151
- type: "string",
152
- description: "Transaction ID to simulate callback for"
153
- },
154
- callbackType: {
155
- type: "string",
156
- enum: ["TRANSACTION_PROCESSED", "TRANSACTION_FINALIZED"],
157
- description: "Type of callback to simulate",
158
- default: "TRANSACTION_PROCESSED"
159
- },
160
- callbackUrl: {
161
- type: "string",
162
- description: "URL where callback would be sent (for simulation only)",
163
- format: "uri"
164
- },
165
- amount: {
166
- type: "string",
167
- description: "Transaction amount (e.g., '57.00')",
168
- default: "57.00"
169
- },
170
- currency: {
171
- type: "string",
172
- enum: ["EUR", "USD", "GBP"],
173
- description: "Transaction currency",
174
- default: "EUR"
175
- },
176
- fee: {
177
- type: "string",
178
- description: "Fee amount charged by payment institution (e.g., '0.60')",
179
- default: "0.60"
180
- },
181
- feeFixed: {
182
- type: "string",
183
- description: "Fixed fee component of the applicable fee configuration. Informational, for reconciliation - do not recompute the fee from it. Present on both callback types since 2026-08-21. Pass null to model a transaction with no fee configuration, where it is omitted.",
184
- default: "0.1000"
185
- },
186
- feeRate: {
187
- type: "string",
188
- description: "Variable rate of the applicable fee configuration, e.g. '0.0150' = 1.5%. Informational, same as feeFixed.",
189
- default: "0.0150"
190
- },
191
- payeeBIC: {
192
- type: "string",
193
- description: "Payee's BIC code",
194
- default: "SBBICID1"
195
- },
196
- payeeAccount: {
197
- type: "string",
198
- description: "Payee account identifier",
199
- default: "M-1W-1account2"
200
- },
201
- payeeFriendlyName: {
202
- type: "string",
203
- description: "Payee friendly name",
204
- default: "payware"
205
- },
206
- payerBIC: {
207
- type: "string",
208
- description: "Payer's BIC code",
209
- default: "SBBICID1"
210
- },
211
- payerAccount: {
212
- type: "string",
213
- description: "Payer account identifier",
214
- default: "payerAccount"
215
- },
216
- payerFriendlyName: {
217
- type: "string",
218
- description: "Payer friendly name",
219
- default: "Demo Financial Institution"
220
- },
221
- reasonL1: {
222
- type: "string",
223
- description: "Transaction reason line 1",
224
- default: "57"
225
- },
226
- reasonL2: {
227
- type: "string",
228
- description: "Transaction reason line 2 (optional)"
229
- },
230
- timeToLive: {
231
- type: "number",
232
- description: "Remaining time to live in seconds",
233
- default: 600
234
- },
235
- status: {
236
- type: "string",
237
- enum: ["CONFIRMED", "DECLINED", "FAILED", "CANCELLED"],
238
- description: "Transaction status (only for TRANSACTION_FINALIZED callbacks)",
239
- default: "CONFIRMED"
240
- },
241
- statusMessage: {
242
- type: "string",
243
- description: "Status message (only for TRANSACTION_FINALIZED callbacks)"
244
- },
245
- paymentMethod: {
246
- type: "string",
247
- enum: ["A2A", "CARD_FUNDED", "BNPL", "INSTANT_CREDIT"],
248
- description: "Payment method chosen by customer. A2A = direct transfer. CARD_FUNDED = card-linked account. BNPL = buy now pay later. INSTANT_CREDIT = credit line."
249
- }
250
- },
251
- required: ["transactionId"]
252
- },
253
-
254
- async handler(args) {
255
- const {
256
- transactionId,
257
- callbackType = 'TRANSACTION_PROCESSED',
258
- callbackUrl,
259
- amount = '57.00',
260
- currency = 'EUR',
261
- fee,
262
- feeFixed = '0.1000',
263
- feeRate = '0.0150',
264
- payeeBIC = 'SBBICID1',
265
- payeeAccount = 'M-1W-1account2',
266
- payeeFriendlyName = 'payware',
267
- payerBIC = 'SBBICID1',
268
- payerAccount = 'payerAccount',
269
- payerFriendlyName = 'Demo Financial Institution',
270
- reasonL1 = '57',
271
- reasonL2,
272
- timeToLive = 600,
273
- status = 'CONFIRMED',
274
- statusMessage,
275
- paymentMethod
276
- } = args;
277
-
278
- if (!transactionId) {
279
- throw new Error("Transaction ID is required");
280
- }
281
-
282
- // Generate mock callback payload
283
- const payload = generateMockPICallback(transactionId, callbackType, {
284
- amount,
285
- currency,
286
- fee,
287
- feeFixed,
288
- feeRate,
289
- payeeBIC,
290
- payeeAccount,
291
- payeeFriendlyName,
292
- payerBIC,
293
- payerAccount,
294
- payerFriendlyName,
295
- reasonL1,
296
- reasonL2,
297
- timeToLive,
298
- initiatedBy: 'PEER',
299
- transactionType: 'DEFAULT',
300
- paymentMethod,
301
- status,
302
- statusMessage
303
- });
304
-
305
- // Simulate callback delivery if URL provided
306
- let deliveryResult = null;
307
- if (callbackUrl) {
308
- deliveryResult = await simulatePICallbackDelivery(callbackUrl, payload);
309
- }
310
-
311
- const callbackEmojis = {
312
- 'TRANSACTION_PROCESSED': '🔄',
313
- 'TRANSACTION_FINALIZED': '✅'
314
- };
315
-
316
- const statusEmojis = {
317
- 'CONFIRMED': '✅',
318
- 'DECLINED': '❌',
319
- 'FAILED': '💥',
320
- 'CANCELLED': '🚫'
321
- };
322
-
323
- const callbackEmoji = callbackEmojis[callbackType] || '📨';
324
- const statusEmoji = statusEmojis[status] || '❓';
325
-
326
- return {
327
- content: [{
328
- type: "text",
329
- text: `${callbackEmoji} **Payment Institution Callback Simulation Complete**
330
-
331
- **Transaction:** ${transactionId}
332
- **Callback Type:** ${callbackType}
333
- ${callbackType === 'TRANSACTION_FINALIZED' ? `**Status:** ${statusEmoji} ${status}` : ''}
334
-
335
- **Mock Callback Payload:**
336
- \`\`\`json
337
- ${JSON.stringify(payload, null, 2)}
338
- \`\`\`
339
-
340
- ${deliveryResult ? `
341
- **Callback Delivery Simulation:**
342
- ${deliveryResult.success ? '✅ Callback would be delivered successfully' : '❌ Callback delivery would fail'}
343
-
344
- **Delivery Details:**
345
- - URL: ${deliveryResult.url || 'N/A'}
346
- - Headers: ${JSON.stringify(deliveryResult.headers || {}, null, 2)}
347
- - Simulated At: ${deliveryResult.simulatedAt || 'N/A'}
348
-
349
- **Note:** ${deliveryResult.note || 'No actual HTTP request was made'}
350
- ` : '**No callback URL provided** - only payload generated'}
351
-
352
- **Payment Institution Callback Types:**
353
- - 🔄 **TRANSACTION_PROCESSED**: Merchant has processed your transaction (ready for finalization)
354
- - ✅ **TRANSACTION_FINALIZED**: Transaction completed with final status
355
-
356
- **Transaction Flow:**
357
- 1. Payment Institution creates transaction as SRC (payer) or DST (payee)
358
- 2. Transaction can be processed by merchant OR payment institution → **TRANSACTION_PROCESSED** callback to PI
359
- 3. Transaction can be finalized ONLY by payment institution → **TRANSACTION_FINALIZED** callback to PI
360
- 4. Transaction can be cancelled ONLY by its issuer (creator)
361
-
362
- **Integration Testing:**
363
- 1. Use this payload to test your payment institution callback handler
364
- 2. Verify handling of both TRANSACTION_PROCESSED and TRANSACTION_FINALIZED
365
- 3. Test different status scenarios for finalized transactions
366
- 4. Ensure proper BIC and account information processing
367
-
368
- **Next Steps:**
369
- 1. Implement callback endpoint to receive this payload structure
370
- 2. Test with both callback types
371
- 3. Add signature verification in production
372
- 4. Set up proper error handling and retry logic`
373
- }]
374
- };
375
- }
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
+ paymentMethod = null,
31
+ status = 'CONFIRMED',
32
+ statusMessage = null,
33
+ passbackParams = null,
34
+ // The POI the payer scanned, on both payloads of a POI sale only (server S8, 2026-09-28).
35
+ poiId = null,
36
+ // The fee breakdown. Present on BOTH payloads whenever the transaction has a fee configuration -
37
+ // FINALIZED gained them on 2026-08-21, having previously carried the total without the two
38
+ // numbers that produced it. Both are INFORMATIONAL: recomputing the fee from them and submitting
39
+ // that at finalize is rejected with ERR_FEE_MISMATCH. Echo `fee` back unchanged instead.
40
+ feeFixed = '0.1000',
41
+ feeRate = '0.0150',
42
+ // Pass fee: null to model the anomaly the server reports by OMITTING the property - a
43
+ // transaction with no recorded fee. Deliberately distinguishable from a genuine '0.00'.
44
+ fee: feeOverride = undefined
45
+ } = options;
46
+
47
+ // Calculate fee like the server: |payerAmount - amount| or |payeeAmount - amount|.
48
+ const transactionAmount = parseFloat(amount);
49
+ let fee = '0.60'; // Default fee
50
+ if (payerAmount !== null) {
51
+ fee = Math.abs(parseFloat(payerAmount) - transactionAmount).toFixed(2);
52
+ } else if (payeeAmount !== null) {
53
+ fee = Math.abs(parseFloat(payeeAmount) - transactionAmount).toFixed(2);
54
+ }
55
+ if (feeOverride !== undefined) {
56
+ fee = feeOverride;
57
+ }
58
+
59
+ // The server's payloads are @JsonInclude(NON_NULL): a property with no value is ABSENT from the
60
+ // JSON rather than sent as null. Emitting "passbackParams": null here taught integrators to expect
61
+ // a shape the server never sends.
62
+ const feeFields = {
63
+ ...(fee !== null && fee !== undefined && { fee }),
64
+ ...(feeFixed !== null && feeFixed !== undefined && { feeFixed }),
65
+ ...(feeRate !== null && feeRate !== undefined && { feeRate })
66
+ };
67
+
68
+ // Build payload based on callback type (matching Java implementation exactly)
69
+ if (callbackType === 'TRANSACTION_PROCESSED') {
70
+ return {
71
+ callbackType,
72
+ transactionId,
73
+ ...(poiId && { poiId }),
74
+ ...(passbackParams !== null && passbackParams !== undefined && { passbackParams }),
75
+ amount,
76
+ ...feeFields,
77
+ currency,
78
+ payeeBIC,
79
+ payeeAccount,
80
+ payeeFriendlyName,
81
+ payerBIC,
82
+ payerAccount,
83
+ payerFriendlyName,
84
+ reasonL1,
85
+ ...(reasonL2 && { reasonL2 }),
86
+ timeToLive,
87
+ transactionType,
88
+ initiatedBy,
89
+ ...(paymentMethod && { paymentMethod })
90
+ };
91
+ } else {
92
+ // TRANSACTION_FINALIZED.
93
+ //
94
+ // transactionType and initiatedBy are deliberately NOT here: the server's finalized builder
95
+ // never sets them, so @JsonInclude(NON_NULL) drops them. An institution that needs either for a
96
+ // finalized transaction reads it from GET /transactions-history/{transactionId}.
97
+ return {
98
+ callbackType,
99
+ transactionId,
100
+ ...(poiId && { poiId }),
101
+ ...(passbackParams !== null && passbackParams !== undefined && { passbackParams }),
102
+ amount,
103
+ ...feeFields,
104
+ currency,
105
+ status,
106
+ ...(statusMessage && { statusMessage }),
107
+ ...(paymentMethod && { paymentMethod }),
108
+ created: Date.now() - 300000, // Created 5 minutes ago (milliseconds)
109
+ // Absent on EXPIRED: the expiry sweep transitions status in bulk and sets no finalized moment.
110
+ ...(status !== 'EXPIRED' && { finalized: Date.now() })
111
+ };
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Simulate callback delivery for payment institutions
117
+ * @param {string} callbackUrl - URL to send callback to
118
+ * @param {Object} payload - Callback payload
119
+ * @returns {Object} Simulation result
120
+ */
121
+ export async function simulatePICallbackDelivery(callbackUrl, payload) {
122
+ if (!callbackUrl || !callbackUrl.startsWith('http')) {
123
+ return {
124
+ success: false,
125
+ error: 'Invalid callback URL provided'
126
+ };
127
+ }
128
+
129
+ // In a real implementation, this would actually send HTTP POST
130
+ // For simulation, we just return what would be sent
131
+ return {
132
+ success: true,
133
+ url: callbackUrl,
134
+ payload,
135
+ headers: {
136
+ 'Content-Type': 'application/json',
137
+ 'Authorization': 'Bearer mock-jwt-token-' + Date.now()
138
+ },
139
+ simulatedAt: new Date().toISOString(),
140
+ note: 'This is a simulation - no actual HTTP request was made. Real payware callbacks use JWT tokens in Authorization header.'
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Payment Institution callback simulation tool implementation
146
+ */
147
+ export const simulatePICallbackTool = {
148
+ name: "payware_operations_simulate_callback",
149
+ 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.",
150
+ inputSchema: {
151
+ type: "object",
152
+ additionalProperties: false,
153
+ properties: {
154
+ transactionId: {
155
+ type: "string",
156
+ description: "Transaction ID to simulate callback for"
157
+ },
158
+ callbackType: {
159
+ type: "string",
160
+ enum: ["TRANSACTION_PROCESSED", "TRANSACTION_FINALIZED"],
161
+ description: "Type of callback to simulate",
162
+ default: "TRANSACTION_PROCESSED"
163
+ },
164
+ callbackUrl: {
165
+ type: "string",
166
+ description: "URL where callback would be sent (for simulation only)",
167
+ format: "uri"
168
+ },
169
+ amount: {
170
+ type: "string",
171
+ description: "Transaction amount (e.g., '57.00')",
172
+ default: "57.00"
173
+ },
174
+ currency: {
175
+ type: "string",
176
+ enum: ["EUR", "USD", "GBP"],
177
+ description: "Transaction currency",
178
+ default: "EUR"
179
+ },
180
+ fee: {
181
+ type: "string",
182
+ description: "Fee amount charged by payment institution (e.g., '0.60')",
183
+ default: "0.60"
184
+ },
185
+ feeFixed: {
186
+ type: "string",
187
+ description: "Fixed fee component of the applicable fee configuration. Informational, for reconciliation - do not recompute the fee from it. Present on both callback types since 2026-08-21. Pass null to model a transaction with no fee configuration, where it is omitted.",
188
+ default: "0.1000"
189
+ },
190
+ feeRate: {
191
+ type: "string",
192
+ description: "Variable rate of the applicable fee configuration, e.g. '0.0150' = 1.5%. Informational, same as feeFixed.",
193
+ default: "0.0150"
194
+ },
195
+ payeeBIC: {
196
+ type: "string",
197
+ description: "Payee's BIC code",
198
+ default: "SBBICID1"
199
+ },
200
+ payeeAccount: {
201
+ type: "string",
202
+ description: "Payee account identifier",
203
+ default: "M-1W-1account2"
204
+ },
205
+ payeeFriendlyName: {
206
+ type: "string",
207
+ description: "Payee friendly name",
208
+ default: "payware"
209
+ },
210
+ payerBIC: {
211
+ type: "string",
212
+ description: "Payer's BIC code",
213
+ default: "SBBICID1"
214
+ },
215
+ payerAccount: {
216
+ type: "string",
217
+ description: "Payer account identifier",
218
+ default: "payerAccount"
219
+ },
220
+ payerFriendlyName: {
221
+ type: "string",
222
+ description: "Payer friendly name",
223
+ default: "Demo Financial Institution"
224
+ },
225
+ reasonL1: {
226
+ type: "string",
227
+ description: "Transaction reason line 1",
228
+ default: "57"
229
+ },
230
+ reasonL2: {
231
+ type: "string",
232
+ description: "Transaction reason line 2 (optional)"
233
+ },
234
+ timeToLive: {
235
+ type: "number",
236
+ description: "Remaining time to live in seconds",
237
+ default: 600
238
+ },
239
+ status: {
240
+ type: "string",
241
+ enum: ["CONFIRMED", "DECLINED", "FAILED", "CANCELLED"],
242
+ description: "Transaction status (only for TRANSACTION_FINALIZED callbacks)",
243
+ default: "CONFIRMED"
244
+ },
245
+ statusMessage: {
246
+ type: "string",
247
+ description: "Status message (only for TRANSACTION_FINALIZED callbacks)"
248
+ },
249
+ paymentMethod: {
250
+ type: "string",
251
+ enum: ["A2A", "CARD_FUNDED", "BNPL", "INSTANT_CREDIT"],
252
+ description: "Payment method chosen by customer. A2A = direct transfer. CARD_FUNDED = card-linked account. BNPL = buy now pay later. INSTANT_CREDIT = credit line."
253
+ },
254
+ poiId: {
255
+ type: "string",
256
+ description: "Set to simulate a POI sale: both payloads then carry the poiId the payer scanned"
257
+ }
258
+ },
259
+ required: ["transactionId"]
260
+ },
261
+
262
+ async handler(args) {
263
+ const {
264
+ transactionId,
265
+ callbackType = 'TRANSACTION_PROCESSED',
266
+ callbackUrl,
267
+ amount = '57.00',
268
+ currency = 'EUR',
269
+ fee,
270
+ feeFixed = '0.1000',
271
+ feeRate = '0.0150',
272
+ payeeBIC = 'SBBICID1',
273
+ payeeAccount = 'M-1W-1account2',
274
+ payeeFriendlyName = 'payware',
275
+ payerBIC = 'SBBICID1',
276
+ payerAccount = 'payerAccount',
277
+ payerFriendlyName = 'Demo Financial Institution',
278
+ reasonL1 = '57',
279
+ reasonL2,
280
+ timeToLive = 600,
281
+ status = 'CONFIRMED',
282
+ statusMessage,
283
+ paymentMethod,
284
+ poiId
285
+ } = args;
286
+
287
+ if (!transactionId) {
288
+ throw new Error("Transaction ID is required");
289
+ }
290
+
291
+ // Generate mock callback payload
292
+ const payload = generateMockPICallback(transactionId, callbackType, {
293
+ amount,
294
+ currency,
295
+ fee,
296
+ feeFixed,
297
+ feeRate,
298
+ payeeBIC,
299
+ payeeAccount,
300
+ payeeFriendlyName,
301
+ payerBIC,
302
+ payerAccount,
303
+ payerFriendlyName,
304
+ reasonL1,
305
+ reasonL2,
306
+ timeToLive,
307
+ initiatedBy: 'PEER',
308
+ transactionType: 'DEFAULT',
309
+ paymentMethod,
310
+ status,
311
+ statusMessage,
312
+ poiId
313
+ });
314
+
315
+ // Simulate callback delivery if URL provided
316
+ let deliveryResult = null;
317
+ if (callbackUrl) {
318
+ deliveryResult = await simulatePICallbackDelivery(callbackUrl, payload);
319
+ }
320
+
321
+ const callbackEmojis = {
322
+ 'TRANSACTION_PROCESSED': '🔄',
323
+ 'TRANSACTION_FINALIZED': '✅'
324
+ };
325
+
326
+ const statusEmojis = {
327
+ 'CONFIRMED': '✅',
328
+ 'DECLINED': '❌',
329
+ 'FAILED': '💥',
330
+ 'CANCELLED': '🚫'
331
+ };
332
+
333
+ const callbackEmoji = callbackEmojis[callbackType] || '📨';
334
+ const statusEmoji = statusEmojis[status] || '❓';
335
+
336
+ return {
337
+ content: [{
338
+ type: "text",
339
+ text: `${callbackEmoji} **Payment Institution Callback Simulation Complete**
340
+
341
+ **Transaction:** ${transactionId}
342
+ **Callback Type:** ${callbackType}
343
+ ${callbackType === 'TRANSACTION_FINALIZED' ? `**Status:** ${statusEmoji} ${status}` : ''}
344
+
345
+ **Mock Callback Payload:**
346
+ \`\`\`json
347
+ ${JSON.stringify(payload, null, 2)}
348
+ \`\`\`
349
+
350
+ ${deliveryResult ? `
351
+ **Callback Delivery Simulation:**
352
+ ${deliveryResult.success ? '✅ Callback would be delivered successfully' : '❌ Callback delivery would fail'}
353
+
354
+ **Delivery Details:**
355
+ - URL: ${deliveryResult.url || 'N/A'}
356
+ - Headers: ${JSON.stringify(deliveryResult.headers || {}, null, 2)}
357
+ - Simulated At: ${deliveryResult.simulatedAt || 'N/A'}
358
+
359
+ **Note:** ${deliveryResult.note || 'No actual HTTP request was made'}
360
+ ` : '**No callback URL provided** - only payload generated'}
361
+
362
+ **Payment Institution Callback Types:**
363
+ - 🔄 **TRANSACTION_PROCESSED**: Merchant has processed your transaction (ready for finalization)
364
+ - ✅ **TRANSACTION_FINALIZED**: Transaction completed with final status
365
+
366
+ **Transaction Flow:**
367
+ 1. Payment Institution creates transaction as SRC (payer) or DST (payee)
368
+ 2. Transaction can be processed by merchant OR payment institution → **TRANSACTION_PROCESSED** callback to PI
369
+ 3. Transaction can be finalized ONLY by payment institution → **TRANSACTION_FINALIZED** callback to PI
370
+ 4. Transaction can be cancelled ONLY by its issuer (creator)
371
+
372
+ **Integration Testing:**
373
+ 1. Use this payload to test your payment institution callback handler
374
+ 2. Verify handling of both TRANSACTION_PROCESSED and TRANSACTION_FINALIZED
375
+ 3. Test different status scenarios for finalized transactions
376
+ 4. Ensure proper BIC and account information processing
377
+
378
+ **Next Steps:**
379
+ 1. Implement callback endpoint to receive this payload structure
380
+ 2. Test with both callback types
381
+ 3. Add signature verification in production
382
+ 4. Set up proper error handling and retry logic`
383
+ }]
384
+ };
385
+ }
376
386
  };