@incodiy/cavagate
v3.0.0
Published
Enterprise payment gateway UI suite for React & Next.js — provider-agnostic checkout, QRIS/VA renderer, admin config panel, and status tracker by Incodiy
Maintainers
Readme
Incodiy Payment Gateway
(@incodiy/cavagate)
Enterprise-grade, provider-agnostic payment gateway UI suite for React and Next.js by Incodiy.
✨ Features
🎯 Core Features
- Provider Agnostic Architecture: Works seamlessly with Midtrans, Xendit, Stripe, PayPal, and custom payment processors.
- Plug & Play Integration: Minimal setup required — just connect your payment provider and start accepting payments.
- Secure & PCI-Compliant: Built with enterprise security standards and best practices.
💳 Checkout Components
Unified Checkout Interface (
<CheckoutPanel />):- Multi-step payment flow with intuitive form validation.
- Support for multiple payment methods (Card, Bank Transfer, E-Wallet, QRIS).
- Real-time order summary with itemization and tax calculation.
- Secure customer data input with validation feedback.
- Customizable branding and color themes.
QRIS Code Renderer (
<QrisDisplay />):- High-quality QR code generation for Indonesian Quick Response Code Standard.
- Automatic copyable QRIS string for manual entry fallback.
- Real-time payment status polling with success confirmation.
- Countdown timer for payment expiration.
Virtual Account (VA) Renderer (
<VirtualAccountDisplay />):- Bank-agnostic virtual account number display with formatted UI.
- Multi-bank support: BCA, Mandiri, BNI, CIMB Niaga, and more.
- Copy-to-clipboard functionality with success feedback.
- Account holder name and payment instruction guide.
- Auto-expiration countdown with visual indicators.
🎛️ Admin & Configuration
Payment Gateway Config Panel (
<GatewayConfigModal />):- Centralized payment provider management dashboard.
- Secure credential input for API keys and merchant IDs.
- Per-provider feature toggle (e.g., enable/disable specific payment methods).
- Testing vs Production environment switcher.
- Webhook URL configuration and test trigger.
- Provider health status indicator with auto-failover setup.
Payment Method Manager (
<PaymentMethodManager />):- Visual payment method selector with icon branding.
- Enable/disable individual payment methods per provider.
- Custom payment method ordering and categorization.
- Display preference toggles (show icons, descriptions, fees).
📊 Payment Tracking & Status
Transaction Status Tracker (
<TransactionStatusBar />):- Real-time payment status display: Pending, Processing, Success, Failed, Expired.
- Detailed transaction information (ID, amount, timestamp).
- Retry payment button for failed transactions.
- Customer receipt generation and email confirmation.
Payment History View (
<PaymentHistoryPanel />):- Comprehensive transaction log with filter and search.
- Multi-status filtering: All, Completed, Pending, Failed, Refunded.
- Date range selection and export to CSV/PDF.
- Quick retry or refund action buttons.
🔐 Security & Compliance
PCI DSS Level 1 Compliant Patterns:
- No sensitive data storage on client side (tokens only).
- Server-side payment processing validation.
- Secure webhook verification with HMAC signatures.
- Rate limiting and CSRF protection helpers.
Payment Fraud Detection:
- Automatic 3D Secure integration for card payments.
- Velocity checks for unusual transaction patterns.
- IP whitelisting and geolocation validation support.
🎨 UI/UX Features
- Customizable Themes: Dark mode support with CSS variable overrides.
- Responsive Design: Mobile-first layout with touch-friendly payment flows.
- Accessibility: WCAG 2.1 AA compliance with keyboard navigation and screen reader support.
- Bilingual Support: Indonesian (
id) and English (en) UI labels out-of-the-box. - Loading & Error States: Comprehensive skeleton loaders and user-friendly error messages.
⌨️ Keyboard Navigation
- Form Shortcuts: Tab through inputs, Enter to submit, Escape to cancel.
- Menu Controls: Arrow keys for payment method selection.
- Accessibility: Full keyboard accessibility for all interactive elements.
📦 Installation
Install directly from NPM:
# Using npm
npm install @incodiy/cavagate
# Using pnpm
pnpm add @incodiy/cavagate
# Using yarn
yarn add @incodiy/cavagate
# From GitHub (always latest)
npm install git+https://github.com/incodiy/cavagate.git🚀 Quick Start Examples
1. Basic Checkout Flow
"use client";
import { useState } from "react";
import { CheckoutPanel, useCavagatePayment } from "@incodiy/cavagate";
export function CheckoutPage() {
const [isProcessing, setIsProcessing] = useState(false);
const { processPayment } = useCavagatePayment({
provider: "midtrans",
publicKey: process.env.NEXT_PUBLIC_MIDTRANS_KEY,
});
const handleCheckout = async (orderData) => {
setIsProcessing(true);
try {
const result = await processPayment(orderData);
if (result.success) {
console.log("Payment successful!", result.transactionId);
}
} catch (error) {
console.error("Payment failed:", error);
} finally {
setIsProcessing(false);
}
};
return (
<CheckoutPanel
onSubmit={handleCheckout}
isLoading={isProcessing}
orderSummary={{
items: [
{ name: "Premium Plan", quantity: 1, price: 299000 },
],
subtotal: 299000,
tax: 29900,
total: 328900,
}}
language="id"
/>
);
}2. QRIS Payment Display
import { QrisDisplay } from "@incodiy/cavagate";
export function QrisPayment() {
return (
<QrisDisplay
qrisString="00020126360014ID.CO.BRI.WWW011828370216123456789520400005303360540510.005802ID5913STORE NAME6009JAKARTA61051234462220805Incodiy6304AB12"
expiresAt={new Date(Date.now() + 15 * 60000)}
onPaymentConfirmed={() => console.log("Payment confirmed!")}
pollIntervalMs={3000}
/>
);
}3. Virtual Account Display
import { VirtualAccountDisplay } from "@incodiy/cavagate";
export function VirtualAccountPayment() {
return (
<VirtualAccountDisplay
bank="BCA"
accountNumber="1234567890"
accountHolder="PT INCODIY INDONESIA"
amount={328900}
expiresAt={new Date(Date.now() + 60 * 60000)}
onCopy={(text) => console.log("Copied:", text)}
language="id"
/>
);
}4. Admin Configuration Panel
import { GatewayConfigModal } from "@incodiy/cavagate";
export function AdminSettings() {
const [providers, setProviders] = useState({
midtrans: { enabled: true, publicKey: "", serverKey: "" },
xendit: { enabled: false, apiKey: "" },
});
return (
<GatewayConfigModal
providers={providers}
onSaveProviders={setProviders}
onTestWebhook={(provider) => {
console.log(`Testing webhook for ${provider}`);
}}
language="id"
/>
);
}5. Payment Status Tracker
import { TransactionStatusBar } from "@incodiy/cavagate";
export function OrderStatus({ transactionId }) {
return (
<TransactionStatusBar
transactionId={transactionId}
status="success"
amount={328900}
timestamp={new Date()}
onRetry={() => console.log("Retry payment")}
language="id"
showReceipt
/>
);
}6. Payment History View
import { PaymentHistoryPanel } from "@incodiy/cavagate";
export function PaymentHistory() {
const [filter, setFilter] = useState("all");
return (
<PaymentHistoryPanel
transactions={[
{
id: "TRX001",
orderId: "ORD001",
amount: 328900,
status: "success",
method: "qris",
timestamp: new Date(),
},
// ... more transactions
]}
statusFilter={filter}
onStatusFilterChange={setFilter}
onExport={(format) => console.log(`Export as ${format}`)}
language="id"
/>
);
}⚙️ Provider Configuration
Midtrans Setup
import { useCavagatePayment } from "@incodiy/cavagate";
const { processPayment } = useCavagatePayment({
provider: "midtrans",
publicKey: process.env.NEXT_PUBLIC_MIDTRANS_CLIENT_KEY,
serverKey: process.env.MIDTRANS_SERVER_KEY, // Server-side only
environment: "production", // or "sandbox"
});Xendit Setup
const { processPayment } = useCavagatePayment({
provider: "xendit",
apiKey: process.env.NEXT_PUBLIC_XENDIT_API_KEY,
publicKey: process.env.NEXT_PUBLIC_XENDIT_PUBLIC_KEY,
});Custom Provider
const { processPayment } = useCavagatePayment({
provider: "custom",
customProvider: {
processPayment: async (orderData) => {
// Your custom payment logic
},
getPaymentStatus: async (transactionId) => {
// Your custom status check
},
},
});📚 Core Components & Hooks
Components
| Component | Purpose | Props |
|-----------|---------|-------|
| <CheckoutPanel /> | Multi-step checkout form | onSubmit, orderSummary, isLoading, language |
| <QrisDisplay /> | QRIS code renderer & status tracker | qrisString, expiresAt, onPaymentConfirmed, pollIntervalMs |
| <VirtualAccountDisplay /> | Virtual account display & copy handler | bank, accountNumber, amount, expiresAt |
| <GatewayConfigModal /> | Admin payment provider config | providers, onSaveProviders, onTestWebhook |
| <PaymentMethodManager /> | Payment method selector & enabler | methods, onMethodToggle, onMethodReorder |
| <TransactionStatusBar /> | Real-time transaction status display | transactionId, status, amount, onRetry |
| <PaymentHistoryPanel /> | Transaction history view & filter | transactions, statusFilter, onExport |
Hooks
| Hook | Purpose |
|------|---------|
| useCavagatePayment(config) | Initialize payment processor and access payment methods |
| usePaymentStatus(transactionId, provider) | Poll and track real-time payment status |
| useQrisGenerator(orderData) | Generate QRIS code string from order data |
| useVirtualAccountGenerator(bank, amount) | Generate virtual account number for bank transfer |
| usePaymentMethodAvailability(provider) | Get available payment methods for provider |
🔄 Payment Flow Architecture
┌─────────────┐
│ Checkout │
│ Panel │
└──────┬──────┘
│
▼
┌──────────────────┐
│ Select Payment │
│ Method │
└──────┬───────────┘
│
├─────► Card / E-Wallet
│
├─────► QRIS Display
│
└─────► Virtual Account
(Bank Transfer)
│
▼
┌──────────────────┐
│ Process Payment │
│ (Provider API) │
└──────┬───────────┘
│
▼
┌──────────────────┐
│ Status Tracker │
│ (Poll/Webhook) │
└──────┬───────────┘
│
├─────► Success ─────► Receipt
│
└─────► Failed ──────► Retry🔐 Security Best Practices
Server-Side Payment Processing
Always process critical operations on the server:
// Server Action or API Route
export async function processPaymentServer(orderData, paymentToken) {
const payment = await midtrans.charge({
transaction_details: {
order_id: orderData.orderId,
gross_amount: orderData.total,
},
credit_card: {
token_id: paymentToken, // Token from client
},
});
return { success: true, transactionId: payment.transaction_id };
}Webhook Verification
import crypto from "crypto";
function verifyMidtransWebhook(notificationBody, serverKey) {
const { status_code, order_id, gross_amount, signature_key } = notificationBody;
const hash = crypto
.createHash("sha512")
.update(`${order_id}${status_code}${gross_amount}${serverKey}`)
.digest("hex");
return hash === signature_key;
}🎨 Theming & Customization
Dark Mode Support
<CheckoutPanel
className="dark"
theme={{
primaryColor: "#C8102E",
backgroundColor: "bg-slate-900",
textColor: "text-white",
}}
/>CSS Variables Override
:root {
--cavagate-primary: #C8102E;
--cavagate-border-radius: 0.2rem;
--cavagate-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--cavagate-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}📝 TypeScript Support
Fully typed with TypeScript. Import types:
import type {
CavagatePaymentProvider,
CheckoutPanelProps,
PaymentMethod,
Transaction,
VirtualAccountBank,
PaymentStatus,
} from "@incodiy/cavagate";🚀 Development & Build
Local Development
# Install dependencies
npm install
# Development with watch mode
npm run dev
# Type checking
npm run typecheck
# Production build
npm run buildBuild Configuration
- Format: CommonJS (CJS) + ECMAScript Modules (ESM)
- Target: ES2022
- Minification: Enabled for production
- Type Declarations: Full TypeScript support (DTS)
- Tree-shaking: Enabled for optimal code splitting
🔗 Provider Documentation
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT License © Incodiy
🔗 Links
- NPM Package: https://www.npmjs.com/package/@incodiy/cavagate
- GitHub Repository: https://github.com/incodiy/cavagate
- Changelog: CHANGELOG.md
- Incodiy: https://incodiy.com
Credits
Built by the Incodiy Team
Powered by:
