Midtrans-Middleware/server
Tengku Achmad 164e62c234 feat: add endpoints to list and read log files; enhance log retrieval functionality 2025-12-05 15:28:14 +07:00
..
README.md feat: update global styles and Tailwind configuration with Inter font; remove obsolete test files and add server documentation 2025-12-04 22:57:38 +07:00
index.cjs feat: add endpoints to list and read log files; enhance log retrieval functionality 2025-12-05 15:28:14 +07:00

README.md

Simaya Midtrans Payment Server

Backend Express.js server untuk integrasi pembayaran Midtrans dengan sistem ERP.

📋 Daftar Isi

🚀 Fitur Utama

1. Dual Mode Payment

  • CORE API: Bank Transfer, Credit Card, GoPay/QRIS, Convenience Store
  • SNAP: Hosted payment interface dengan UI Midtrans
  • 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

# 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
# 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

# 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

# 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

PORT=8000
NODE_ENV=development

📡 API Endpoints

Health & Config

GET /api/health

Health check endpoint.

Response:

{
  "ok": true,
  "env": {
    "isProduction": false,
    "hasServerKey": true,
    "hasClientKey": true
  }
}

GET /api/config

Get current payment configuration.

Response:

{
  "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:

{
  "paymentToggles": {
    "bank_transfer": false
  }
}

Payment Operations

POST /api/payments/charge

Create payment transaction via Midtrans Core API.

Headers:

Content-Type: application/json

Request Body:

{
  "payment_type": "bank_transfer",
  "transaction_details": {
    "order_id": "order-123",
    "gross_amount": 150000
  },
  "bank_transfer": {
    "bank": "bca"
  }
}

Response:

{
  "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:

{
  "transaction_details": {
    "order_id": "order-123",
    "gross_amount": 150000
  },
  "customer_details": {
    "first_name": "John",
    "email": "john@example.com"
  }
}

Response:

{
  "token": "snap-token-xxx"
}

GET /api/payments/:orderId/status

Check payment status.

Response:

{
  "status_code": "200",
  "transaction_status": "settlement",
  "order_id": "order-123",
  "gross_amount": "150000.00"
}

POST /createtransaksi

Generate payment link (external ERP endpoint).

Headers:

X-API-KEY: your-external-api-key
Content-Type: application/json

Request:

{
  "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:

{
  "status": "200",
  "messages": "SUCCESS",
  "data": {
    "url": "http://localhost:5174/pay/eyJ2Ijox..."
  }
}

GET /api/payment-links/:token

Resolve payment link token.

Response:

{
  "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):

{
  "order_id": "order-123",
  "transaction_status": "settlement",
  "gross_amount": "150000.00",
  "signature_key": "xxx"
}

Response:

{
  "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:

{
  "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:

{
  "orderId": "order-123",
  "nominal": "150000",
  "mercant_id": "merchant-001"
}

🔄 Payment 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

{
  "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:

# 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

# Install dependencies
npm install

# Start server
node server/index.cjs

# Server runs on http://localhost:8000

🐛 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: