# PortalPay

[![npm version](https://badge.fury.io/js/portalpay.svg)](https://www.npmjs.com/package/portalpay)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![CDN](https://img.shields.io/badge/CDN-jsDelivr-blue.svg)](https://cdn.jsdelivr.net/npm/portalpay@latest/dist/portalpay.js)

> Complete browser-based payment SDK for PortalPay. Zero-dependency IIFE bundle that works with any website or CMS.

## Overview

`portalpay` is the standalone browser bundle of the PortalPay SDK. It provides a complete payment solution that:

- 💳 **Supports Multiple Payment Methods** - Cards, Mobile Money
- 🔒 **Built-in Security** - Tamper detection and fraud prevention
- 🎨 **Customizable** - Style buttons to match your brand
- 🌐 **Universal** - Works with any website, CMS, or framework
- 📱 **Mobile-First** - Optimized for mobile payments
- 🧪 **Mock Mode** - Test without real transactions

## Quick Start

### CDN (Recommended)

Add to your HTML `<head>`:

```html
<script src="https://cdn.jsdelivr.net/npm/portalpay@1.0.0/dist/portalpay.js"></script>
```

### npm

```bash
npm install portalpay
# or
yarn add portalpay
# or
pnpm add portalpay
```

## Basic Usage

### 1. Add the Script

```html
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/portalpay@1.0.0/dist/portalpay.js"></script>
</head>
<body>
  <!-- Your content -->
</body>
</html>
```

### 2. Configure the SDK

```html
<script>
  // Global configuration (set before the SDK loads)
  window.PORTALPAY = {
    publishableKey: 'pk_live_alexpay_xxxxxxxx',
    currency: 'GHS',
    narration: 'Order Payment',
    callback: 'https://yoursite.com/success',
    cancel: 'https://yoursite.com/cancel'
  };
</script>
<script src="https://cdn.jsdelivr.net/npm/portalpay@1.0.0/dist/portalpay.js"></script>
```

### 3. Add Payment Button

```html
<!-- Fixed amount -->
<button data-checkout data-amount="5000">
  Pay GHS 50.00
</button>

<!-- Or read amount from page element -->
<span id="total">7500</span>
<button data-checkout data-amount-from="#total">
  Checkout
</button>

<!-- Or use JavaScript variable -->
<script>
  window.cartTotal = 10000;
</script>
<button data-checkout data-amount-var="cartTotal">
  Pay Now
</button>
```

## Configuration Options

### Global Configuration (window.EMBEDPAY)

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `publishableKey` | string | ✅ | Your publishable key from payment provider |
| `currency` | string | ❌ | Currency code (GHS, NGN, USD, KES, ZAR) |
| `method` | string | ❌ | Payment method: 'card' or 'mobile-money' |
| `narration` | string | ❌ | Default payment description |
| `callback` | string | ❌ | Success redirect URL |
| `cancel` | string | ❌ | Cancel redirect URL |
| `forceMock` | boolean | ❌ | Enable test mode (default: false) |
| `checkoutUrl` | string | ❌ | Custom checkout page URL (for mock mode) |

### Button Attributes

| Attribute | Description | Example |
|-----------|-------------|---------|
| `data-checkout` | Marks button as checkout trigger | `<button data-checkout>` |
| `data-amount` | Fixed payment amount | `data-amount="5000"` |
| `data-amount-from` | CSS selector for amount element | `data-amount-from="#total"` |
| `data-amount-var` | JavaScript variable name | `data-amount-var="cartTotal"` |
| `data-currency` | Override currency | `data-currency="USD"` |
| `data-narration` | Override description | `data-narration="Product #123"` |
| `data-publishable-key` | Use different publishable key | `data-publishable-key="pk_test_..."` |
| `data-force-mock` | Enable mock mode per button | `data-force-mock="true"` |

## Advanced Usage

### WooCommerce Integration

```html
<script>
  window.PORTALPAY = {
    publishableKey: 'pk_live_alexpay_xxxxxxxx',
    currency: 'GHS',
    narration: 'WooCommerce Order',
    amountVar: 'PORTALPAY_CART_TOTAL'  // Auto-sync with cart
  };
</script>
```

### Custom Styling

```css
/* Base button styles */
.portalpay-btn {
  background: #1a1714;
  color: #f5f2ee;
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  transition: background 0.15s;
}

.portalpay-btn:hover {
  background: #2d2926;
}

.portalpay-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
```

### Event Handling

```javascript
// SDK exposes PortalPay object globally
document.addEventListener('DOMContentLoaded', function() {
  // Refresh button bindings (if dynamically adding buttons)
  if (window.PortalPay) {
    window.PortalPay.refresh();
  }
});
```

## Mock Mode (Testing)

Enable test mode to simulate payments without real transactions:

```html
<script>
  window.PORTALPAY = {
    publishableKey: 'pk_test_alexpay_xxxxxxxx',
    forceMock: true,
    checkoutUrl: 'https://yoursite.com/checkout.html'
  };
</script>
```

**Test Cards:**
- ✅ **Success:** 4084 0841 2345 6789, Exp: 12/28, CVV: 123
- ❌ **Declined:** 4000 0000 0000 0002, Exp: 12/28, CVV: 456

**Test Mobile Money:**
- ✅ **Success:** 0244 123 456, Network: MTN
- ❌ **Declined:** 0244 000 000, Network: MTN

## Security Features

### Tamper Detection

The SDK automatically monitors for:
- 🖥️ **DevTools Detection** - Blocks payments if developer tools are open
- 📐 **Window Resize** - Detects suspicious window resizing
- 💰 **Amount Changes** - Validates amount hasn't been manipulated

### Domain Authorization

Your publishable key is restricted to specific domains. Configure allowed domains in your merchant dashboard.

## CMS Integrations

### WordPress

Install the [PortalPay WordPress Plugin](https://wordpress.org/plugins/portalpay) for easy integration.

```php
// Shortcode
[portalpay_button amount="5000"]Pay Now[/portalpay_button]

// With dynamic amount
[portalpay_button amount_from="#total"]Checkout[/portalpay_button]
```

### Shopify

Add to your theme's checkout page:

```liquid
<script src="https://cdn.jsdelivr.net/npm/portalpay@1.0.0/dist/portalpay.js"></script>
<script>
  window.PORTALPAY = {
    publishableKey: 'pk_live_alexpay_xxxxxxxx',
    currency: '{{ shop.currency }}',
    narration: 'Order {{ order.name }}'
  };
</script>
```

## Browser Support

- ✅ Chrome 80+
- ✅ Firefox 75+
- ✅ Safari 13+
- ✅ Edge 80+
- ✅ iOS Safari 13+
- ✅ Chrome Android 80+

## File Size

- **Gzipped:** ~4.2 KB
- **Minified:** ~10 KB

## Troubleshooting

### "Payment service not authorized for this site"

Your domain is not authorized. Add your domain in the merchant dashboard.

### "Invalid payment key"

Check that your publishable key is correct and matches the format: `pk_live_alexpay_xxxxxxxx`

### "Payment amount is missing or zero"

Ensure the amount element exists and contains a valid number:
```html
<span id="total">5000</span>  <!-- Must be just the number -->
```

### "Initialising payment service…"

The SDK is still fetching configuration. Wait a moment and try again.

## API Reference

The browser bundle exposes a global `PortalPay` object:

```typescript
interface PortalPaySDK {
  refresh(): void;  // Re-scan for buttons and bind events
}
```

## Related Packages

- [`portalpay-core`](https://www.npmjs.com/package/portalpay-core) - Core functionality
- [`portalpay-react`](https://www.npmjs.com/package/portalpay-react) - React hooks and components
- [`portalpay-vue`](https://www.npmjs.com/package/portalpay-vue) - Vue composables and components

## License

MIT © [Vesicash](https://vesicash.com)

## Support

- 📧 Email: support@vesicash.com
- 🌐 Website: https://vesicash.com/portalpay
- 📖 Documentation: https://docs.vesicash.com/portalpay

---

**Accept payments anywhere with PortalPay** 🚀
