# Simaya Midtrans Payment Server Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP. ## ๐Ÿ“‹ Daftar Isi - [Fitur Utama](#fitur-utama) - [Konfigurasi Environment](#konfigurasi-environment) - [API Endpoints](#api-endpoints) - [Payment Flow](#payment-flow) - [Testing](#testing) - [Logging](#logging) ## ๐Ÿš€ Fitur Utama ### 1. **Dual Mode Payment** - **CORE API**: Bank Transfer, Credit Card, GoPay/QRIS, Convenience Store - **SNAP**: Hosted payment interface dengan UI Midtrans ### 2. **Payment Link Generation** - Generate secure payment link dengan signature validation - Configurable TTL (Time To Live) - Token-based authentication ### 3. **ERP Integration** - Notifikasi otomatis ke sistem ERP setelah pembayaran sukses - Multi-endpoint support (comma-separated URLs) - Signature verification untuk keamanan ### 4. **Webhook Handler** - Unified webhook untuk CORE dan SNAP - Signature verification - Idempotent notification handling ### 5. **Advanced Logging** - Level-based logging (debug, info, warn, error) - In-memory log buffer - Payload masking untuk sensitive data - Jakarta timezone (WIB/UTC+7) ## โš™๏ธ Konfigurasi Environment ### Midtrans Configuration ```env # Required MIDTRANS_SERVER_KEY=your-server-key MIDTRANS_CLIENT_KEY=your-client-key MIDTRANS_IS_PRODUCTION=false # Payment Method Toggles ENABLE_BANK_TRANSFER=true ENABLE_CREDIT_CARD=true ENABLE_GOPAY=true ENABLE_CSTORE=true ``` ### Payment Link Configuration ```env # External API Access EXTERNAL_API_KEY=your-api-key # Payment Link Settings PAYMENT_LINK_SECRET=your-secret-for-signing PAYMENT_LINK_TTL_MINUTES=1440 PAYMENT_LINK_BASE=http://localhost:5174/pay ``` ### ERP Integration ```env # Single URL (legacy) ERP_NOTIFICATION_URL=https://your-erp.com/api/payment-notification ERP_CLIENT_SECRET=your-erp-client-secret # Multi-URL (recommended) ERP_NOTIFICATION_URLS=https://erp1.com/api/notif,https://erp2.com/api/notif # Toggle ERP_ENABLE_NOTIF=true ``` ### Logging Configuration ```env # Logging Level: debug, info, warn, error LOG_LEVEL=info # Expose /api/logs endpoint (dev only) LOG_EXPOSE_API=true # In-memory buffer size LOG_BUFFER_SIZE=1000 ``` ### Server Configuration ```env PORT=8000 NODE_ENV=development ``` ## ๐Ÿ“ก API Endpoints ### Health & Config #### `GET /api/health` Health check endpoint. **Response:** ```json { "ok": true, "env": { "isProduction": false, "hasServerKey": true, "hasClientKey": true } } ``` #### `GET /api/config` Get current payment configuration. **Response:** ```json { "paymentToggles": { "bank_transfer": true, "credit_card": true, "gopay": true, "cstore": true }, "midtransEnv": "sandbox", "clientKey": "SB-Mid-client-xxx" } ``` #### `POST /api/config` (Dev Only) Update payment toggles at runtime. **Request:** ```json { "paymentToggles": { "bank_transfer": false } } ``` ### Payment Operations #### `POST /api/payments/charge` Create payment transaction via Midtrans Core API. **Headers:** ``` Content-Type: application/json ``` **Request Body:** ```json { "payment_type": "bank_transfer", "transaction_details": { "order_id": "order-123", "gross_amount": 150000 }, "bank_transfer": { "bank": "bca" } } ``` **Response:** ```json { "status_code": "201", "status_message": "Success", "transaction_id": "xxx", "order_id": "order-123", "va_numbers": [ { "bank": "bca", "va_number": "12345678901" } ] } ``` #### `POST /api/payments/snap/token` Generate Snap token for hosted payment. **Request:** ```json { "transaction_details": { "order_id": "order-123", "gross_amount": 150000 }, "customer_details": { "first_name": "John", "email": "john@example.com" } } ``` **Response:** ```json { "token": "snap-token-xxx" } ``` #### `GET /api/payments/:orderId/status` Check payment status. **Response:** ```json { "status_code": "200", "transaction_status": "settlement", "order_id": "order-123", "gross_amount": "150000.00" } ``` ### Payment Link #### `POST /createtransaksi` Generate payment link (external ERP endpoint). **Headers:** ``` X-API-KEY: your-external-api-key Content-Type: application/json ``` **Request:** ```json { "mercant_id": "merchant-001", "nominal": 150000, "nama": "John Doe", "email": "john@example.com", "no_telepon": "081234567890", "item": [ { "item_id": "product-123", "nama": "Product Name", "harga": 150000, "qty": 1 } ], "allowed_methods": ["bank_transfer", "gopay"] } ``` **Response:** ```json { "status": "200", "messages": "SUCCESS", "data": { "url": "http://localhost:5174/pay/eyJ2Ijox..." } } ``` #### `GET /api/payment-links/:token` Resolve payment link token. **Response:** ```json { "order_id": "merchant-001:product-123", "nominal": 150000, "customer": { "name": "John Doe", "email": "john@example.com", "phone": "081234567890" }, "expire_at": 1733280000000, "allowed_methods": ["bank_transfer", "gopay"] } ``` ### Webhook #### `POST /api/payments/notification` Midtrans webhook handler (unified for CORE & SNAP). **Request (from Midtrans):** ```json { "order_id": "order-123", "transaction_status": "settlement", "gross_amount": "150000.00", "signature_key": "xxx" } ``` **Response:** ```json { "ok": true } ``` ### Logging (Dev Only) #### `GET /api/logs?limit=100&level=info&q=payment` Get recent logs. **Query Parameters:** - `limit`: Max entries (1-1000, default: 100) - `level`: Filter by level (debug|info|warn|error) - `q`: Search keyword **Response:** ```json { "count": 50, "items": [ { "ts": "2024-12-04T12:00:00.000+07:00", "level": "info", "msg": "charge.request", "meta": { "id": "abc123", "payment_type": "bank_transfer" } } ] } ``` ### Testing (Dev Only) #### `POST /api/echo` Echo endpoint untuk testing ERP notification. #### `POST /api/test/notify-erp` Manual trigger ERP notification. **Request:** ```json { "orderId": "order-123", "nominal": "150000", "mercant_id": "merchant-001" } ``` ## ๐Ÿ”„ Payment Flow ### 1. Payment Link Creation Flow ``` ERP System โ†’ POST /createtransaksi โ†’ Server generates token โ†’ Payment URL ``` ### 2. Payment Execution Flow ``` Customer โ†’ Payment URL โ†’ Frontend resolves token โ†’ Choose method โ†’ POST /api/payments/charge or SNAP โ†’ Midtrans ``` ### 3. Payment Completion Flow ``` Midtrans โ†’ Webhook โ†’ Verify signature โ†’ Update ledger โ†’ Notify ERP โ†’ Mark order complete ``` ### 4. ERP Notification Format ```json { "mercant_id": "merchant-001", "status_code": "200", "nominal": "150000", "signature": "sha512-hash" } ``` **Signature Calculation:** ``` SHA512(mercant_id + status_code + nominal + ERP_CLIENT_SECRET) ``` ## ๐Ÿงช Testing Lihat folder `tests/` untuk file-file testing: ```bash # Test create payment link node tests/test-create-payment-link.cjs # Test frontend payload node tests/test-frontend-payload.cjs # Test snap token node tests/test-snap-token.cjs ``` Lihat `tests/README.md` untuk detail lengkap. ## ๐Ÿ“ Logging ### Log Levels - **debug**: Detailed information, typically of interest only when diagnosing problems - **info**: General informational messages - **warn**: Warning messages for potentially harmful situations - **error**: Error events that might still allow the application to continue running ### Log Format ``` [2024-12-04T12:00:00.000+07:00] [info] charge.request {"id": "abc123", "payment_type": "bank_transfer"} ``` ### Important Log Events #### Payment Lifecycle - `charge.request`: Payment charge initiated - `charge.success`: Charge successful - `charge.error`: Charge failed - `status.request`: Status check requested - `webhook.received`: Webhook notification received #### ERP Integration - `erp.notify.start`: ERP notification started - `erp.notify.success`: ERP notified successfully - `erp.notify.error`: ERP notification failed - `erp.notify.skip`: Notification skipped (already sent or disabled) #### Security - `webhook.signature.invalid`: Invalid webhook signature - `createtransaksi.unauthorized`: Unauthorized API key ## ๐Ÿ”’ Security Features 1. **Signature Verification** - Webhook signature validation - Payment link token signing - ERP notification signing 2. **Idempotency** - Prevent duplicate order creation - Prevent duplicate ERP notifications - Block re-charge for pending orders 3. **API Key Authentication** - External API key for `/createtransaksi` - Dev mode fallback for easier local testing 4. **Payload Masking** - Sensitive fields masked in logs - Card numbers, CVV, tokens automatically hidden ## ๐Ÿš€ Running the Server ```bash # Install dependencies npm install # Start server node server/index.cjs # Server runs on http://localhost:8000 ``` ## ๐Ÿ“š Related Documentation - [Tests README](../tests/README.md) - Testing documentation - [Temp Files README](../temp/README.md) - Temporary files info - [Frontend README](../README.md) - Main project README ## ๐Ÿ› Common Issues ### Issue: "Transaction already pending" **Cause**: Order ID already has pending transaction in Midtrans **Solution**: Use existing payment instructions or create new order with different ID ### Issue: "ERP notification failed" **Cause**: ERP endpoint unreachable or signature mismatch **Solution**: Check `ERP_NOTIFICATION_URLS` and `ERP_CLIENT_SECRET` configuration ### Issue: "Invalid signature on webhook" **Cause**: Incorrect server key or webhook from unauthorized source **Solution**: Verify `MIDTRANS_SERVER_KEY` matches your Midtrans account ## ๐Ÿ“ž Support Untuk bantuan lebih lanjut, hubungi tim development atau lihat dokumentasi Midtrans: - [Midtrans API Documentation](https://docs.midtrans.com/) - [Midtrans Node.js Library](https://github.com/Midtrans/midtrans-nodejs-client)