@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.
Files changed (106) hide show
  1. package/.env.example +92 -0
  2. package/MCP-SETUP.md +190 -0
  3. package/README.md +483 -0
  4. package/check-keys.js +52 -0
  5. package/keys/README.md +112 -0
  6. package/mcp-config.json +9 -0
  7. package/package.json +66 -0
  8. package/payware-mcp-config.json +12 -0
  9. package/src/auth/rsa-keys.js +82 -0
  10. package/src/auth/sandbox-setup.js +187 -0
  11. package/src/config/env.js +229 -0
  12. package/src/config/partner-types.js +143 -0
  13. package/src/core/auth/jwt-factory.js +182 -0
  14. package/src/core/auth/jwt-token.js +735 -0
  15. package/src/core/utils/json-serializer.js +100 -0
  16. package/src/core/utils/key-utils.js +133 -0
  17. package/src/index.js +237 -0
  18. package/src/isv/data/index.js +291 -0
  19. package/src/isv/deep-links/delete-product-link.js +154 -0
  20. package/src/isv/deep-links/delete-transaction-link.js +154 -0
  21. package/src/isv/deep-links/get-product-link.js +167 -0
  22. package/src/isv/deep-links/get-transaction-link.js +167 -0
  23. package/src/isv/deep-links/index.js +23 -0
  24. package/src/isv/index.js +103 -0
  25. package/src/isv/oauth2/create-token-simple.js +46 -0
  26. package/src/isv/oauth2/get-token-info.js +157 -0
  27. package/src/isv/oauth2/obtain-token.js +189 -0
  28. package/src/isv/oauth2/token-helper.js +151 -0
  29. package/src/isv/products/audios.js +470 -0
  30. package/src/isv/products/create-product.js +314 -0
  31. package/src/isv/products/delete-product.js +119 -0
  32. package/src/isv/products/get-product-image.js +247 -0
  33. package/src/isv/products/get-product.js +168 -0
  34. package/src/isv/products/index.js +65 -0
  35. package/src/isv/products/list-products.js +136 -0
  36. package/src/isv/products/schedules.js +522 -0
  37. package/src/isv/products/update-product.js +265 -0
  38. package/src/isv/transactions/cancel-transaction.js +129 -0
  39. package/src/isv/transactions/create-transaction.js +361 -0
  40. package/src/isv/transactions/get-status.js +217 -0
  41. package/src/isv/transactions/process-transaction.js +145 -0
  42. package/src/isv/transactions/simulate-callback.js +146 -0
  43. package/src/isv/transactions/transaction-history.js +186 -0
  44. package/src/isv/utils/auth.js +159 -0
  45. package/src/mcp-proxy.js +150 -0
  46. package/src/merchant/data/export-report.js +108 -0
  47. package/src/merchant/data/generate-report.js +151 -0
  48. package/src/merchant/data/get-report-status.js +120 -0
  49. package/src/merchant/data/index.js +351 -0
  50. package/src/merchant/deep-links/delete-product-link.js +121 -0
  51. package/src/merchant/deep-links/delete-transaction-link.js +121 -0
  52. package/src/merchant/deep-links/get-product-link.js +134 -0
  53. package/src/merchant/deep-links/get-transaction-link.js +134 -0
  54. package/src/merchant/deep-links/index.js +23 -0
  55. package/src/merchant/index.js +92 -0
  56. package/src/merchant/products/audios.js +606 -0
  57. package/src/merchant/products/create-product.js +288 -0
  58. package/src/merchant/products/delete-product.js +111 -0
  59. package/src/merchant/products/get-product-image.js +252 -0
  60. package/src/merchant/products/get-product.js +144 -0
  61. package/src/merchant/products/index.js +65 -0
  62. package/src/merchant/products/list-products.js +112 -0
  63. package/src/merchant/products/schedules.js +646 -0
  64. package/src/merchant/products/update-product.js +282 -0
  65. package/src/merchant/transactions/cancel-transaction.js +241 -0
  66. package/src/merchant/transactions/create-transaction.js +482 -0
  67. package/src/merchant/transactions/get-status.js +196 -0
  68. package/src/merchant/transactions/process-transaction.js +349 -0
  69. package/src/merchant/transactions/simulate-callback.js +246 -0
  70. package/src/merchant/transactions/transaction-history.js +258 -0
  71. package/src/payment-institution/data/index.js +280 -0
  72. package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
  73. package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
  74. package/src/payment-institution/deep-links/index.js +17 -0
  75. package/src/payment-institution/index.js +92 -0
  76. package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
  77. package/src/payment-institution/transactions/finalize-transaction.js +340 -0
  78. package/src/payment-institution/transactions/get-transaction-history.js +269 -0
  79. package/src/payment-institution/transactions/get-transaction-status.js +234 -0
  80. package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
  81. package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
  82. package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
  83. package/src/proxy-server.js +205 -0
  84. package/src/shared/data/data-api.js +372 -0
  85. package/src/shared/deep-links/api.js +214 -0
  86. package/src/shared/index.js +44 -0
  87. package/src/shared/products/products-api.js +872 -0
  88. package/src/tools/advanced-code-generator.js +2247 -0
  89. package/src/utils/code-examples/common/auth-examples.js +1482 -0
  90. package/src/utils/code-examples/common/helpers.js +416 -0
  91. package/src/utils/code-examples/common/utils-examples.js +591 -0
  92. package/src/utils/code-examples/frameworks/examples.js +859 -0
  93. package/src/utils/code-examples/index.js +441 -0
  94. package/src/utils/code-examples/isv/oauth2.js +600 -0
  95. package/src/utils/code-examples/isv/products.js +666 -0
  96. package/src/utils/code-examples/isv/transactions.js +813 -0
  97. package/src/utils/code-examples/merchant/products.js +497 -0
  98. package/src/utils/code-examples/merchant/transactions.js +623 -0
  99. package/src/utils/code-examples/payment-institution/transactions.js +388 -0
  100. package/src/utils/code-examples/shared/data.js +607 -0
  101. package/src/utils/code-examples/shared/deep-links.js +662 -0
  102. package/src/utils/code-examples/shared/soundbites.js +808 -0
  103. package/src/utils/code-examples.js +646 -0
  104. package/src/utils/format-request.js +363 -0
  105. package/src/utils/json-formatter.js +249 -0
  106. package/src/utils/server-info.js +132 -0
@@ -0,0 +1,859 @@
1
+ /**
2
+ * Framework-specific integration examples
3
+ */
4
+
5
+ import { ExampleGenerator } from '../common/helpers.js';
6
+
7
+ /**
8
+ * Django REST Framework integration
9
+ */
10
+ export const DjangoExamples = {
11
+ /**
12
+ * Django view for transaction creation
13
+ */
14
+ transactionView: `
15
+ # views.py - Django REST Framework implementation
16
+ from rest_framework.views import APIView
17
+ from rest_framework.response import Response
18
+ from rest_framework import status
19
+ from django.conf import settings
20
+ import logging
21
+
22
+ from .payware_client import PaywareClient
23
+ from .serializers import TransactionSerializer
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ class PaywareTransactionView(APIView):
28
+ """
29
+ Handle payware transaction operations
30
+ """
31
+
32
+ def __init__(self):
33
+ super().__init__()
34
+ self.payware_client = PaywareClient(
35
+ partner_id=settings.PAYWARE_PARTNER_ID,
36
+ private_key_path=settings.PAYWARE_PRIVATE_KEY_PATH,
37
+ use_sandbox=settings.PAYWARE_USE_SANDBOX
38
+ )
39
+
40
+ def post(self, request):
41
+ """Create a new transaction"""
42
+ serializer = TransactionSerializer(data=request.data)
43
+
44
+ if not serializer.is_valid():
45
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
46
+
47
+ try:
48
+ # Prepare transaction data
49
+ transaction_data = {
50
+ 'trData': {
51
+ 'amount': serializer.validated_data['amount'],
52
+ 'currency': serializer.validated_data.get('currency', 'EUR'),
53
+ 'reasonL1': serializer.validated_data['description']
54
+ },
55
+ 'trOptions': {
56
+ 'type': 'PLAIN',
57
+ 'timeToLive': 120
58
+ }
59
+ }
60
+
61
+ # Create transaction via payware API
62
+ result = self.payware_client.create_transaction(transaction_data)
63
+
64
+ if result:
65
+ # Log successful transaction creation
66
+ logger.info(f"Transaction created: {result.get('transactionId')}")
67
+
68
+ return Response({
69
+ 'success': True,
70
+ 'transaction_id': result.get('transactionId'),
71
+ 'amount': result.get('amount'),
72
+ 'status': result.get('status'),
73
+ 'payment_url': result.get('paymentUrl')
74
+ }, status=status.HTTP_201_CREATED)
75
+ else:
76
+ logger.error("Failed to create transaction")
77
+ return Response({
78
+ 'success': False,
79
+ 'error': 'Transaction creation failed'
80
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
81
+
82
+ except Exception as e:
83
+ logger.error(f"Transaction creation error: {str(e)}")
84
+ return Response({
85
+ 'success': False,
86
+ 'error': 'Internal server error'
87
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
88
+
89
+ def get(self, request, transaction_id=None):
90
+ """Get transaction status"""
91
+ if not transaction_id:
92
+ return Response({
93
+ 'error': 'Transaction ID required'
94
+ }, status=status.HTTP_400_BAD_REQUEST)
95
+
96
+ try:
97
+ result = self.payware_client.get_transaction_status(transaction_id)
98
+
99
+ if result:
100
+ return Response({
101
+ 'success': True,
102
+ 'transaction_id': transaction_id,
103
+ 'status': result.get('status'),
104
+ 'amount': result.get('amount'),
105
+ 'currency': result.get('currency'),
106
+ 'created_at': result.get('createdAt'),
107
+ 'updated_at': result.get('updatedAt')
108
+ })
109
+ else:
110
+ return Response({
111
+ 'error': 'Transaction not found'
112
+ }, status=status.HTTP_404_NOT_FOUND)
113
+
114
+ except Exception as e:
115
+ logger.error(f"Get transaction error: {str(e)}")
116
+ return Response({
117
+ 'error': 'Internal server error'
118
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
119
+ `,
120
+
121
+ /**
122
+ * Django settings configuration
123
+ */
124
+ settings: `
125
+ # settings.py - Django configuration for payware
126
+ import os
127
+ from pathlib import Path
128
+
129
+ BASE_DIR = Path(__file__).resolve().parent.parent
130
+
131
+ # payware Configuration
132
+ PAYWARE_PARTNER_ID = os.getenv('PAYWARE_PARTNER_ID')
133
+ PAYWARE_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'keys', 'sandbox-merchant-private-key.pem')
134
+ PAYWARE_USE_SANDBOX = os.getenv('PAYWARE_USE_SANDBOX', 'true').lower() == 'true'
135
+ PAYWARE_SANDBOX_URL = 'https://sandbox.payware.eu/api'
136
+ PAYWARE_PRODUCTION_URL = 'https://api.payware.eu/api'
137
+
138
+ # Logging configuration
139
+ LOGGING = {
140
+ 'version': 1,
141
+ 'disable_existing_loggers': False,
142
+ 'handlers': {
143
+ 'file': {
144
+ 'level': 'INFO',
145
+ 'class': 'logging.FileHandler',
146
+ 'filename': 'payware.log',
147
+ },
148
+ 'console': {
149
+ 'level': 'DEBUG',
150
+ 'class': 'logging.StreamHandler',
151
+ },
152
+ },
153
+ 'loggers': {
154
+ 'payware': {
155
+ 'handlers': ['file', 'console'],
156
+ 'level': 'INFO',
157
+ 'propagate': True,
158
+ },
159
+ },
160
+ }
161
+ `,
162
+
163
+ /**
164
+ * Django URL patterns
165
+ */
166
+ urls: `
167
+ # urls.py - Django URL configuration
168
+ from django.urls import path
169
+ from .views import PaywareTransactionView
170
+
171
+ urlpatterns = [
172
+ path('api/transactions/', PaywareTransactionView.as_view(), name='create_transaction'),
173
+ path('api/transactions/<str:transaction_id>/', PaywareTransactionView.as_view(), name='get_transaction'),
174
+ ]
175
+ `
176
+ };
177
+
178
+ /**
179
+ * Express.js integration
180
+ */
181
+ export const ExpressExamples = {
182
+ /**
183
+ * Express.js routes for payware integration
184
+ */
185
+ routes: `
186
+ // routes/payware.js - Express.js implementation
187
+ const express = require('express');
188
+ const router = express.Router();
189
+ const PaywareClient = require('../lib/payware-client');
190
+ const { body, param, validationResult } = require('express-validator');
191
+
192
+ // Initialize payware client
193
+ const paywareClient = new PaywareClient({
194
+ partnerId: process.env.PAYWARE_PARTNER_ID,
195
+ privateKeyPath: process.env.PAYWARE_PRIVATE_KEY_PATH,
196
+ useSandbox: process.env.PAYWARE_USE_SANDBOX === 'true'
197
+ });
198
+
199
+ /**
200
+ * Create transaction
201
+ */
202
+ router.post('/transactions',
203
+ // Validation middleware
204
+ body('amount').isFloat({ min: 0.01 }).withMessage('Amount must be a positive number'),
205
+ body('currency').optional().isIn(['EUR', 'USD', 'GBP']).withMessage('Invalid currency'),
206
+ body('description').isLength({ min: 1, max: 255 }).withMessage('Description required'),
207
+
208
+ async (req, res) => {
209
+ // Check validation results
210
+ const errors = validationResult(req);
211
+ if (!errors.isEmpty()) {
212
+ return res.status(400).json({
213
+ success: false,
214
+ errors: errors.array()
215
+ });
216
+ }
217
+
218
+ try {
219
+ const { amount, currency = 'EUR', description } = req.body;
220
+
221
+ // Prepare transaction data
222
+ const transactionData = {
223
+ trData: {
224
+ amount: amount.toString(),
225
+ currency,
226
+ reasonL1: description
227
+ },
228
+ trOptions: {
229
+ type: 'PLAIN',
230
+ timeToLive: 120
231
+ }
232
+ };
233
+
234
+ // Create transaction
235
+ const result = await paywareClient.createTransaction(transactionData);
236
+
237
+ if (result) {
238
+ console.log(\`Transaction created: \${result.transactionId}\`);
239
+
240
+ res.status(201).json({
241
+ success: true,
242
+ transactionId: result.transactionId,
243
+ amount: result.amount,
244
+ status: result.status,
245
+ paymentUrl: result.paymentUrl
246
+ });
247
+ } else {
248
+ res.status(500).json({
249
+ success: false,
250
+ error: 'Transaction creation failed'
251
+ });
252
+ }
253
+
254
+ } catch (error) {
255
+ console.error('Transaction creation error:', error);
256
+ res.status(500).json({
257
+ success: false,
258
+ error: 'Internal server error'
259
+ });
260
+ }
261
+ }
262
+ );
263
+
264
+ /**
265
+ * Get transaction status
266
+ */
267
+ router.get('/transactions/:transactionId',
268
+ param('transactionId').isLength({ min: 1 }).withMessage('Transaction ID required'),
269
+
270
+ async (req, res) => {
271
+ const errors = validationResult(req);
272
+ if (!errors.isEmpty()) {
273
+ return res.status(400).json({
274
+ success: false,
275
+ errors: errors.array()
276
+ });
277
+ }
278
+
279
+ try {
280
+ const { transactionId } = req.params;
281
+ const result = await paywareClient.getTransactionStatus(transactionId);
282
+
283
+ if (result) {
284
+ res.json({
285
+ success: true,
286
+ transactionId,
287
+ status: result.status,
288
+ amount: result.amount,
289
+ currency: result.currency,
290
+ createdAt: result.createdAt,
291
+ updatedAt: result.updatedAt
292
+ });
293
+ } else {
294
+ res.status(404).json({
295
+ success: false,
296
+ error: 'Transaction not found'
297
+ });
298
+ }
299
+
300
+ } catch (error) {
301
+ console.error('Get transaction error:', error);
302
+ res.status(500).json({
303
+ success: false,
304
+ error: 'Internal server error'
305
+ });
306
+ }
307
+ }
308
+ );
309
+
310
+ /**
311
+ * Process transaction (merchant)
312
+ */
313
+ router.post('/transactions/:transactionId/process',
314
+ param('transactionId').isLength({ min: 1 }).withMessage('Transaction ID required'),
315
+ body('account').isLength({ min: 1 }).withMessage('Account required'),
316
+ body('friendlyName').isLength({ min: 1 }).withMessage('Friendly name required'),
317
+
318
+ async (req, res) => {
319
+ const errors = validationResult(req);
320
+ if (!errors.isEmpty()) {
321
+ return res.status(400).json({
322
+ success: false,
323
+ errors: errors.array()
324
+ });
325
+ }
326
+
327
+ try {
328
+ const { transactionId } = req.params;
329
+ const { account, friendlyName } = req.body;
330
+
331
+ const processData = {
332
+ account,
333
+ friendlyName
334
+ };
335
+
336
+ const result = await paywareClient.processTransaction(transactionId, processData);
337
+
338
+ if (result) {
339
+ res.json({
340
+ success: true,
341
+ transactionId,
342
+ status: result.status,
343
+ processedAt: result.processedAt
344
+ });
345
+ } else {
346
+ res.status(500).json({
347
+ success: false,
348
+ error: 'Transaction processing failed'
349
+ });
350
+ }
351
+
352
+ } catch (error) {
353
+ console.error('Process transaction error:', error);
354
+ res.status(500).json({
355
+ success: false,
356
+ error: 'Internal server error'
357
+ });
358
+ }
359
+ }
360
+ );
361
+
362
+ module.exports = router;
363
+ `,
364
+
365
+ /**
366
+ * Express.js middleware
367
+ */
368
+ middleware: `
369
+ // middleware/payware-auth.js - Express.js authentication middleware
370
+ const PaywareAuthenticator = require('../lib/payware-authenticator');
371
+
372
+ /**
373
+ * Middleware to authenticate payware API requests
374
+ */
375
+ function paywareAuthMiddleware(req, res, next) {
376
+ try {
377
+ // Initialize authenticator if not already done
378
+ if (!req.paywareAuth) {
379
+ req.paywareAuth = new PaywareAuthenticator({
380
+ partnerId: process.env.PAYWARE_PARTNER_ID,
381
+ privateKeyPath: process.env.PAYWARE_PRIVATE_KEY_PATH,
382
+ useSandbox: process.env.PAYWARE_USE_SANDBOX === 'true'
383
+ });
384
+ }
385
+
386
+ next();
387
+ } catch (error) {
388
+ console.error('payware authentication setup error:', error);
389
+ res.status(500).json({
390
+ success: false,
391
+ error: 'Authentication setup failed'
392
+ });
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Middleware to log payware API requests
398
+ */
399
+ function paywareLoggingMiddleware(req, res, next) {
400
+ const start = Date.now();
401
+
402
+ // Log request
403
+ console.log(\`[payware] \${req.method} \${req.path} - Request started\`);
404
+
405
+ // Override res.json to log response
406
+ const originalJson = res.json;
407
+ res.json = function(body) {
408
+ const duration = Date.now() - start;
409
+ console.log(\`[payware] \${req.method} \${req.path} - \${res.statusCode} (\${duration}ms)\`);
410
+
411
+ if (res.statusCode >= 400) {
412
+ console.error(\`[payware] Error response:\`, body);
413
+ }
414
+
415
+ return originalJson.call(this, body);
416
+ };
417
+
418
+ next();
419
+ }
420
+
421
+ module.exports = {
422
+ paywareAuthMiddleware,
423
+ paywareLoggingMiddleware
424
+ };
425
+ `,
426
+
427
+ /**
428
+ * Express.js app setup
429
+ */
430
+ app: `
431
+ // app.js - Express.js application setup
432
+ const express = require('express');
433
+ const cors = require('cors');
434
+ const helmet = require('helmet');
435
+ const rateLimit = require('express-rate-limit');
436
+ require('dotenv').config();
437
+
438
+ // Import routes and middleware
439
+ const paywareRoutes = require('./routes/payware');
440
+ const { paywareAuthMiddleware, paywareLoggingMiddleware } = require('./middleware/payware-auth');
441
+
442
+ const app = express();
443
+
444
+ // Security middleware
445
+ app.use(helmet());
446
+ app.use(cors({
447
+ origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
448
+ credentials: true
449
+ }));
450
+
451
+ // Rate limiting
452
+ const limiter = rateLimit({
453
+ windowMs: 15 * 60 * 1000, // 15 minutes
454
+ max: 100, // limit each IP to 100 requests per windowMs
455
+ message: 'Too many requests from this IP'
456
+ });
457
+ app.use('/api/', limiter);
458
+
459
+ // Body parsing
460
+ app.use(express.json({ limit: '10mb' }));
461
+ app.use(express.urlencoded({ extended: true }));
462
+
463
+ // payware-specific middleware
464
+ app.use('/api/payware', paywareLoggingMiddleware);
465
+ app.use('/api/payware', paywareAuthMiddleware);
466
+
467
+ // Routes
468
+ app.use('/api/payware', paywareRoutes);
469
+
470
+ // Health check endpoint
471
+ app.get('/health', (req, res) => {
472
+ res.json({
473
+ status: 'healthy',
474
+ timestamp: new Date().toISOString(),
475
+ payware: {
476
+ configured: !!(process.env.PAYWARE_PARTNER_ID && process.env.PAYWARE_PRIVATE_KEY_PATH),
477
+ sandbox: process.env.PAYWARE_USE_SANDBOX === 'true'
478
+ }
479
+ });
480
+ });
481
+
482
+ // Error handling middleware
483
+ app.use((error, req, res, next) => {
484
+ console.error('Application error:', error);
485
+
486
+ res.status(error.status || 500).json({
487
+ success: false,
488
+ error: process.env.NODE_ENV === 'production'
489
+ ? 'Internal server error'
490
+ : error.message
491
+ });
492
+ });
493
+
494
+ // 404 handler
495
+ app.use((req, res) => {
496
+ res.status(404).json({
497
+ success: false,
498
+ error: 'Endpoint not found'
499
+ });
500
+ });
501
+
502
+ const PORT = process.env.PORT || 3000;
503
+
504
+ app.listen(PORT, () => {
505
+ console.log(\`Server running on port \${PORT}\`);
506
+ console.log(\`payware sandbox mode: \${process.env.PAYWARE_USE_SANDBOX === 'true'}\`);
507
+ });
508
+
509
+ module.exports = app;
510
+ `
511
+ };
512
+
513
+ /**
514
+ * Laravel integration
515
+ */
516
+ export const LaravelExamples = {
517
+ /**
518
+ * Laravel controller for payware
519
+ */
520
+ controller: `
521
+ <?php
522
+ // app/Http/Controllers/PaywareController.php - Laravel implementation
523
+
524
+ namespace App\\Http\\Controllers;
525
+
526
+ use Illuminate\\Http\\Request;
527
+ use Illuminate\\Http\\Response;
528
+ use Illuminate\\Support\\Facades\\Log;
529
+ use Illuminate\\Support\\Facades\\Validator;
530
+ use App\\Services\\PaywareService;
531
+ use App\\Http\\Requests\\CreateTransactionRequest;
532
+
533
+ class PaywareController extends Controller
534
+ {
535
+ protected $paywareService;
536
+
537
+ public function __construct(PaywareService $paywareService)
538
+ {
539
+ $this->paywareService = $paywareService;
540
+ }
541
+
542
+ /**
543
+ * Create a new transaction
544
+ */
545
+ public function createTransaction(CreateTransactionRequest $request)
546
+ {
547
+ try {
548
+ $validated = $request->validated();
549
+
550
+ $transactionData = [
551
+ 'trData' => [
552
+ 'amount' => $validated['amount'],
553
+ 'currency' => $validated['currency'] ?? 'EUR',
554
+ 'reasonL1' => $validated['description']
555
+ ],
556
+ 'trOptions' => [
557
+ 'type' => 'PLAIN',
558
+ 'timeToLive' => 120
559
+ ]
560
+ ];
561
+
562
+ $result = $this->paywareService->createTransaction($transactionData);
563
+
564
+ if ($result) {
565
+ Log::info('Transaction created', ['transaction_id' => $result['transactionId']]);
566
+
567
+ return response()->json([
568
+ 'success' => true,
569
+ 'transaction_id' => $result['transactionId'],
570
+ 'amount' => $result['amount'],
571
+ 'status' => $result['status'],
572
+ 'payment_url' => $result['paymentUrl']
573
+ ], Response::HTTP_CREATED);
574
+ }
575
+
576
+ return response()->json([
577
+ 'success' => false,
578
+ 'error' => 'Transaction creation failed'
579
+ ], Response::HTTP_INTERNAL_SERVER_ERROR);
580
+
581
+ } catch (\\Exception $e) {
582
+ Log::error('Transaction creation error', ['error' => $e->getMessage()]);
583
+
584
+ return response()->json([
585
+ 'success' => false,
586
+ 'error' => 'Internal server error'
587
+ ], Response::HTTP_INTERNAL_SERVER_ERROR);
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Get transaction status
593
+ */
594
+ public function getTransactionStatus(string $transactionId)
595
+ {
596
+ try {
597
+ $result = $this->paywareService->getTransactionStatus($transactionId);
598
+
599
+ if ($result) {
600
+ return response()->json([
601
+ 'success' => true,
602
+ 'transaction_id' => $transactionId,
603
+ 'status' => $result['status'],
604
+ 'amount' => $result['amount'],
605
+ 'currency' => $result['currency'],
606
+ 'created_at' => $result['createdAt'],
607
+ 'updated_at' => $result['updatedAt']
608
+ ]);
609
+ }
610
+
611
+ return response()->json([
612
+ 'success' => false,
613
+ 'error' => 'Transaction not found'
614
+ ], Response::HTTP_NOT_FOUND);
615
+
616
+ } catch (\\Exception $e) {
617
+ Log::error('Get transaction error', ['error' => $e->getMessage()]);
618
+
619
+ return response()->json([
620
+ 'success' => false,
621
+ 'error' => 'Internal server error'
622
+ ], Response::HTTP_INTERNAL_SERVER_ERROR);
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Process transaction
628
+ */
629
+ public function processTransaction(Request $request, string $transactionId)
630
+ {
631
+ $validator = Validator::make($request->all(), [
632
+ 'account' => 'required|string|max:255',
633
+ 'friendly_name' => 'required|string|max:255'
634
+ ]);
635
+
636
+ if ($validator->fails()) {
637
+ return response()->json([
638
+ 'success' => false,
639
+ 'errors' => $validator->errors()
640
+ ], Response::HTTP_BAD_REQUEST);
641
+ }
642
+
643
+ try {
644
+ $processData = [
645
+ 'account' => $request->account,
646
+ 'friendlyName' => $request->friendly_name
647
+ ];
648
+
649
+ $result = $this->paywareService->processTransaction($transactionId, $processData);
650
+
651
+ if ($result) {
652
+ return response()->json([
653
+ 'success' => true,
654
+ 'transaction_id' => $transactionId,
655
+ 'status' => $result['status'],
656
+ 'processed_at' => $result['processedAt']
657
+ ]);
658
+ }
659
+
660
+ return response()->json([
661
+ 'success' => false,
662
+ 'error' => 'Transaction processing failed'
663
+ ], Response::HTTP_INTERNAL_SERVER_ERROR);
664
+
665
+ } catch (\\Exception $e) {
666
+ Log::error('Process transaction error', ['error' => $e->getMessage()]);
667
+
668
+ return response()->json([
669
+ 'success' => false,
670
+ 'error' => 'Internal server error'
671
+ ], Response::HTTP_INTERNAL_SERVER_ERROR);
672
+ }
673
+ }
674
+ }
675
+ `,
676
+
677
+ /**
678
+ * Laravel service class
679
+ */
680
+ service: `
681
+ <?php
682
+ // app/Services/PaywareService.php - Laravel service for payware integration
683
+
684
+ namespace App\\Services;
685
+
686
+ use Illuminate\\Support\\Facades\\Http;
687
+ use Illuminate\\Support\\Facades\\Log;
688
+ use Illuminate\\Support\\Facades\\Cache;
689
+ use App\\Exceptions\\PaywareException;
690
+
691
+ class PaywareService
692
+ {
693
+ protected $partnerId;
694
+ protected $privateKeyPath;
695
+ protected $useSandbox;
696
+ protected $baseUrl;
697
+
698
+ public function __construct()
699
+ {
700
+ $this->partnerId = config('services.payware.partner_id');
701
+ $this->privateKeyPath = config('services.payware.private_key_path');
702
+ $this->useSandbox = config('services.payware.use_sandbox', true);
703
+ $this->baseUrl = $this->useSandbox
704
+ ? config('services.payware.sandbox_url')
705
+ : config('services.payware.production_url');
706
+ }
707
+
708
+ /**
709
+ * Create JWT token for API authentication
710
+ */
711
+ protected function createJWTToken($requestBody = null)
712
+ {
713
+ // Load private key
714
+ $privateKey = file_get_contents($this->privateKeyPath);
715
+ if (!$privateKey) {
716
+ throw new PaywareException('Unable to load private key');
717
+ }
718
+
719
+ // Create JWT header
720
+ $header = [
721
+ 'alg' => 'RS256',
722
+ 'typ' => 'JWT'
723
+ ];
724
+
725
+ // Add content MD5 for requests with body
726
+ $bodyString = null;
727
+ if ($requestBody) {
728
+ $bodyString = $this->createMinimizedJSON($requestBody);
729
+ $contentMd5 = base64_encode(md5($bodyString, true));
730
+ $header['contentMd5'] = $contentMd5;
731
+ }
732
+
733
+ // Create JWT payload
734
+ $payload = [
735
+ 'iss' => $this->partnerId,
736
+ 'aud' => 'https://payware.eu',
737
+ 'iat' => time()
738
+ ];
739
+
740
+ // Create JWT token
741
+ $token = \\Firebase\\JWT\\JWT::encode($payload, $privateKey, 'RS256', null, $header);
742
+
743
+ return [
744
+ 'token' => $token,
745
+ 'bodyString' => $bodyString
746
+ ];
747
+ }
748
+
749
+ /**
750
+ * Create minimized JSON for deterministic MD5
751
+ */
752
+ protected function createMinimizedJSON($data)
753
+ {
754
+ if (is_array($data)) {
755
+ ksort($data);
756
+ foreach ($data as $key => $value) {
757
+ $data[$key] = $this->createMinimizedJSON($value);
758
+ }
759
+ }
760
+
761
+ return json_encode($data, JSON_UNESCAPED_SLASHES);
762
+ }
763
+
764
+ /**
765
+ * Make authenticated API request
766
+ */
767
+ protected function makeAPIRequest($endpoint, $method = 'GET', $requestBody = null)
768
+ {
769
+ $tokenData = $this->createJWTToken($requestBody);
770
+
771
+ $headers = [
772
+ 'Authorization' => 'Bearer ' . $tokenData['token'],
773
+ 'Content-Type' => 'application/json',
774
+ 'Api-Version' => '1'
775
+ ];
776
+
777
+ $url = $this->baseUrl . $endpoint;
778
+
779
+ $response = Http::withHeaders($headers)
780
+ ->timeout(30)
781
+ ->{strtolower($method)}($url, $requestBody ? json_decode($tokenData['bodyString'], true) : []);
782
+
783
+ if ($response->successful()) {
784
+ return $response->json();
785
+ }
786
+
787
+ Log::error('payware API request failed', [
788
+ 'endpoint' => $endpoint,
789
+ 'method' => $method,
790
+ 'status' => $response->status(),
791
+ 'response' => $response->body()
792
+ ]);
793
+
794
+ return null;
795
+ }
796
+
797
+ /**
798
+ * Create transaction
799
+ */
800
+ public function createTransaction(array $transactionData)
801
+ {
802
+ return $this->makeAPIRequest('/transactions', 'POST', $transactionData);
803
+ }
804
+
805
+ /**
806
+ * Get transaction status
807
+ */
808
+ public function getTransactionStatus(string $transactionId)
809
+ {
810
+ return $this->makeAPIRequest("/transactions/{$transactionId}");
811
+ }
812
+
813
+ /**
814
+ * Process transaction
815
+ */
816
+ public function processTransaction(string $transactionId, array $processData)
817
+ {
818
+ return $this->makeAPIRequest("/transactions/{$transactionId}", 'POST', $processData);
819
+ }
820
+
821
+ /**
822
+ * Cancel transaction
823
+ */
824
+ public function cancelTransaction(string $transactionId, array $cancelData)
825
+ {
826
+ return $this->makeAPIRequest("/transactions/{$transactionId}", 'PATCH', $cancelData);
827
+ }
828
+ }
829
+ `,
830
+
831
+ /**
832
+ * Laravel configuration
833
+ */
834
+ config: `
835
+ <?php
836
+ // config/services.php - Laravel services configuration
837
+
838
+ return [
839
+ // ... other services
840
+
841
+ 'payware' => [
842
+ 'partner_id' => env('PAYWARE_PARTNER_ID'),
843
+ 'private_key_path' => env('PAYWARE_PRIVATE_KEY_PATH'),
844
+ 'use_sandbox' => env('PAYWARE_USE_SANDBOX', true),
845
+ 'sandbox_url' => env('PAYWARE_SANDBOX_URL', 'https://sandbox.payware.eu/api'),
846
+ 'production_url' => env('PAYWARE_PRODUCTION_URL', 'https://api.payware.eu/api'),
847
+ ],
848
+ ];
849
+ `
850
+ };
851
+
852
+ /**
853
+ * Export all framework examples
854
+ */
855
+ export const FrameworkExamples = {
856
+ django: DjangoExamples,
857
+ express: ExpressExamples,
858
+ laravel: LaravelExamples
859
+ };