npm package: @reflexpay/onetap-web-sdk
Description: Production-ready embeddable JavaScript Web SDK for ReflexPay payment flow
Author: ReflexPay
Latest version: 1.0.1

# ReflexPay OneTap Web SDK

[![npm version](https://img.shields.io/npm/v/@reflexpay/onetap-web-sdk.svg)](https://www.npmjs.com/package/@reflexpay/onetap-web-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

A production-ready, embeddable JavaScript Web SDK for making payments via FLEX.

## Features

✅ **Framework-agnostic** - Works with vanilla JS, React, Vue, Angular, etc.  
✅ **Zero dependencies** - Lightweight and fast  
✅ **TypeScript native** - Full type safety and IntelliSense  
✅ **Shadow DOM** - Isolated styles that won't conflict with your app  
✅ **Accessibility** - Full keyboard navigation and screen reader support  
✅ **Mobile-friendly** - Responsive design that works on all devices  
✅ **Production-ready** - Error handling, timeouts, cleanup, and more

## Installation

### Via npm

```bash
npm install @reflexpay/onetap-web-sdk
```

### Via CDN

```html
<script src="https://cdn.jsdelivr.net/npm/@reflexpay/onetap-web-sdk/dist/sdk.min.js"></script>
```

## Quick Start

### Basic Usage

```javascript
import { PaySDK } from "@reflexpay/onetap-web-sdk";

const sdk = new PaySDK({
  publicKey: "pk_test_123456789",
});

sdk.open({
  transactionId: "tx_abc123",
  onSuccess: (data) => {
    console.log("Payment successful:", data);
    // { transactionId: 'tx_abc123', paytag: 'mike123', status: 'successful' }
  },
  onError: (error) => {
    console.error("Payment failed:", error);
    // { code: 'TIMEOUT_ERROR', message: '...' }
  },
  onClose: () => {
    console.log("Modal closed");
  },
});
```

### CDN Usage

```html
<script src="https://cdn.company.com/pay-sdk/v1/sdk.min.js"></script>
<script>
  const sdk = new PaySDK({ publicKey: "pk_test_123" });

  document.getElementById("pay-button").addEventListener("click", () => {
    sdk.open({
      transactionId: "tx_123",
      onSuccess: (data) => alert("Payment successful!"),
      onError: (error) => alert("Payment failed: " + error.message),
    });
  });
</script>
```

## API Reference

### Constructor

#### `new PaySDK(config: SDKConfig)`

Initialize the SDK with your configuration.

**Parameters:**

| Parameter         | Type      | Required | Description                                                  |
| ----------------- | --------- | -------- | ------------------------------------------------------------ |
| `publicKey`       | `string`  | ✅       | Your public API key                                          |
| `apiBaseUrl`      | `string`  | ❌       | Custom API endpoint (default: `https://api.reflexpay.com`) |
| `debug`           | `boolean` | ❌       | Enable debug logging (default: `false`)                      |
| `paymentTimeout`  | `number`  | ❌       | Timeout in ms (default: `600000` - 10 minutes)               |
| `pollingInterval` | `number`  | ❌       | Polling interval in ms (default: `5000` - 5 seconds)         |

**Example:**

```typescript
const sdk = new PaySDK({
  publicKey: "pk_test_123456789",
  debug: true,
  paymentTimeout: 900000, // 15 minutes
  pollingInterval: 3000, // 3 seconds
});
```

### Methods

#### `sdk.open(options: PaymentOptions)`

Open the payment modal.

**Parameters:**

| Parameter       | Type       | Required | Description                   |
| --------------- | ---------- | -------- | ----------------------------- |
| `transactionId` | `string`   | ✅       | Unique transaction identifier |
| `amount`        | `number`   | ❌       | Payment amount                |
| `currency`      | `string`   | ❌       | Currency code (e.g., 'USD')   |
| `metadata`      | `object`   | ❌       | Custom metadata               |
| `onSuccess`     | `function` | ❌       | Success callback              |
| `onError`       | `function` | ❌       | Error callback                |
| `onClose`       | `function` | ❌       | Close callback                |

**Example:**

```typescript
sdk.open({
  transactionId: "tx_abc123",
  amount: 5000,
  currency: "USD",
  metadata: {
    orderId: "order_123",
    customerId: "cust_456",
  },
  onSuccess: (data) => {
    console.log("Success:", data);
  },
  onError: (error) => {
    console.error("Error:", error);
  },
  onClose: () => {
    console.log("Closed");
  },
});
```

#### `sdk.close()`

Programmatically close the payment modal.

```typescript
sdk.close();
```

### Callbacks

#### `onSuccess(data: PaymentSuccessData)`

Invoked when payment is successful.

```typescript
{
  transactionId: string;
  paytag: string;
  status: "successful";
}
```

#### `onError(error: SDKError)`

Invoked when payment fails or times out.

```typescript
{
  code: string;
  message: string;
  details?: unknown;
}
```

**Error Codes:**

- `INVALID_CONFIG` - Invalid SDK configuration
- `NETWORK_ERROR` - Network connection failed
- `API_ERROR` - API returned an error
- `TIMEOUT_ERROR` - Payment timed out (10 minutes)
- `VALIDATION_ERROR` - Input validation failed
- `UNKNOWN_ERROR` - Unexpected error occurred

#### `onClose()`

Invoked when modal is closed (by user or programmatically).

## Payment Flow

The SDK implements a 3-screen flow:

### 1. PayTag Input Screen

- User enters their PayTag
- Input validation
- Loading state on submit

### 2. Pending Screen

- Shows "Payment Pending" UI
- 10-minute countdown timer
- Polls backend every 5 seconds
- Automatically transitions on success/failure

### 3. Success/Error Screen

- Shows payment result
- User can close modal

## Framework Examples

### React

```tsx
import { PaySDK } from "@reflexpay/onetap-web-sdk";
import { useState, useRef } from "react";

function CheckoutButton() {
  const sdkRef = useRef<PaySDK | null>(null);
  const [loading, setLoading] = useState(false);

  const handlePayment = () => {
    if (!sdkRef.current) {
      sdkRef.current = new PaySDK({
        publicKey: process.env.REACT_APP_PAY_SDK_KEY!,
      });
    }

    sdkRef.current.open({
      transactionId: generateTransactionId(),
      onSuccess: (data) => {
        console.log("Success:", data);
        setLoading(false);
      },
      onError: (error) => {
        console.error("Error:", error);
        setLoading(false);
      },
    });
  };

  return (
    <button onClick={handlePayment} disabled={loading}>
      Pay Now
    </button>
  );
}
```

### Vue 3

```vue
<template>
  <button @click="handlePayment" :disabled="loading">Pay Now</button>
</template>

<script setup>
import { ref } from "vue";
import { PaySDK } from "@reflexpay/onetap-web-sdk";

const loading = ref(false);
const sdk = new PaySDK({
  publicKey: import.meta.env.VITE_PAY_SDK_KEY,
});

const handlePayment = () => {
  loading.value = true;

  sdk.open({
    transactionId: generateTransactionId(),
    onSuccess: (data) => {
      console.log("Success:", data);
      loading.value = false;
    },
    onError: (error) => {
      console.error("Error:", error);
      loading.value = false;
    },
  });
};
</script>
```

### Angular

```typescript
import { Component } from "@angular/core";
import { PaySDK } from "@reflexpay/onetap-web-sdk";

@Component({
  selector: "app-checkout",
  template: `
    <button (click)="handlePayment()" [disabled]="loading">Pay Now</button>
  `,
})
export class CheckoutComponent {
  loading = false;
  private sdk: PaySDK;

  constructor() {
    this.sdk = new PaySDK({
      publicKey: environment.paySDKKey,
    });
  }

  handlePayment() {
    this.loading = true;

    this.sdk.open({
      transactionId: this.generateTransactionId(),
      onSuccess: (data) => {
        console.log("Success:", data);
        this.loading = false;
      },
      onError: (error) => {
        console.error("Error:", error);
        this.loading = false;
      },
    });
  }
}
```

## Browser Support

- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- iOS Safari 14+
- Android Chrome 90+

## Security

- ✅ Never stores secrets in the browser
- ✅ Only accepts public keys
- ✅ Sanitizes all user inputs to prevent XSS
- ✅ No inline scripts or `eval()`
- ✅ Content Security Policy friendly

## Development

### Build

```bash
npm install
npm run build
```

### Development Mode

```bash
npm run dev
```

### Type Check

```bash
npm run typecheck
```

## Bundle Size

- **ESM:** ~15KB (gzipped)
- **UMD:** ~18KB (gzipped)

## License

MIT © ReflexPay

## Support

For issues and questions:

- GitHub Issues: https://github.com/reflexpay/onetap-web-sdk/issues
- Email: support@reflexpay.com
- Documentation: https://docs.reflexpay.com