npm package: @imerchantsolutions/sdk
Description: Official iMerchant SDK for JavaScript and TypeScript
Author: iMerchant Solutions
Latest version: 1.3.3

# @imerchantsolutions/sdk

Official JavaScript/TypeScript SDK for the iMerchant Payments API.

## Installation

```bash
npm install @imerchantsolutions/sdk
# or
yarn add @imerchantsolutions/sdk
# or
pnpm add @imerchantsolutions/sdk
```

## Quick Start

```typescript
import { iMerchant } from '@imerchantsolutions/sdk';

const client = new iMerchant({
  apiKey: 'sk_test_your_api_key'
});

// Create a payment
const payment = await client.payments.create({
  amount: 1000,        // $10.00 in cents
  currency: 'usd',
  reference: 'order_123',
  description: 'Test payment'
});

console.log('Payment ID:', payment.id);
```

## Features

- **Full TypeScript support** with comprehensive type definitions
- **Payments** - Create, capture, cancel, and list payments
- **Payment Links** - Create shareable checkout URLs (no PCI required)
- **Checkout Sessions** - Embed Drop-in for PCI-compliant card collection
- **Refunds** - Process full or partial refunds
- **Customers** - Manage customer profiles
- **Subscriptions** - Handle recurring billing
- **Webhooks** - Verify webhook signatures securely

## API Reference

### Payments

#### Client-Side Encrypted Payments (Recommended)

Use client-side encryption for secure card handling without PCI scope:

**Step 1: Get Client Key (from your dashboard or API)**
```typescript
const clientKey = 'test_DR32...'; // Your client key from dashboard
```

**Step 2: Encrypt Card Data (in browser using CSE library)**
```html
<script src="${session.sdkUrl}"></script>
<script>
  const iMerchantEncrypt = new iMerchantEncrypt(clientKey);

  // Encrypt card fields
  const encryptedCard = {
    encryptedCardNumber: iMerchantEncrypt.encrypt({ number: '4111111111111111' }),
    encryptedExpiryMonth: iMerchantEncrypt.encrypt({ expiryMonth: '03' }),
    encryptedExpiryYear: iMerchantEncrypt.encrypt({ expiryYear: '2030' }),
    encryptedSecurityCode: iMerchantEncrypt.encrypt({ cvc: '737' }),
    holderName: 'John Smith'
  };

  // Send to your server
  fetch('/api/charge', {
    method: 'POST',
    body: JSON.stringify({ encryptedCard, amount: 1000 })
  });
</script>
```

**Step 3: Process Payment (on your server)**
```typescript
const payment = await client.payments.create({
  amount: 1000,           // $10.00 in cents
  currency: 'USD',
  reference: 'order_456',
  encryptedCard: {
    encryptedCardNumber: req.body.encryptedCard.encryptedCardNumber,
    encryptedExpiryMonth: req.body.encryptedCard.encryptedExpiryMonth,
    encryptedExpiryYear: req.body.encryptedCard.encryptedExpiryYear,
    encryptedSecurityCode: req.body.encryptedCard.encryptedSecurityCode,
    holderName: req.body.encryptedCard.holderName
  }
});

console.log('Payment:', payment.resultCode); // 'Authorised'
```

#### Raw Card Payments (Requires PCI Compliance)

For PCI-compliant merchants only:

```typescript
const payment = await client.payments.create({
  amount: 2000,
  currency: 'USD',
  reference: 'order_456',
  card: {
    number: '4111111111111111',
    cvv: '737',
    expiry_month: '03',
    expiry_year: '2030',
    holder: 'John Smith'
  }
});
```

#### Other Payment Operations

```typescript
// Retrieve a payment
const payment = await client.payments.retrieve('pay_abc123');

// List payments
const { data, hasMore } = await client.payments.list({
  status: 'captured',
  limit: 10
});

// Capture an authorized payment
await client.payments.capture('pay_abc123');

// Cancel a payment
await client.payments.cancel('pay_abc123');
```

### Payment Links

The easiest way to accept payments without handling card data (no PCI compliance required).

```typescript
// Create a payment link
const link = await client.paymentLinks.create({
  amount: 2500,           // $25.00 in cents
  currency: 'USD',
  description: 'Order #123',
  customerEmail: 'customer@example.com',
  customerName: 'John Doe',
  expiresAt: '2026-03-01T00:00:00Z',  // Optional
  metadata: { orderId: '123' }         // Optional
});

console.log(link.url);  // Send this URL to your customer
// e.g., https://imerchantsolutions.com/pay/abc123

// Retrieve a payment link
const link = await client.paymentLinks.retrieve('abc123');

// List payment links
const { data, pagination } = await client.paymentLinks.list({
  status: 'active',  // 'active' | 'paid' | 'cancelled' | 'expired'
  limit: 10,
  offset: 0
});

// Update a payment link
const updated = await client.paymentLinks.update('abc123', {
  description: 'Updated description',
  customerPhone: '+1234567890'
});

// Cancel a payment link
await client.paymentLinks.cancel('abc123');
```

### Checkout Sessions (Embedded Payment Forms)

For custom checkout pages with PCI-compliant card collection. Three integration options available:

| Approach | Customization | Use Case |
|----------|---------------|----------|
| **Drop-in** | Themes only | Quick integration, all payment methods |
| **Components** | Moderate | Individual payment method styling |
| **Secured Fields** | Full control | Complete UI customization |

#### Step 1: Create Session (Server-Side)

```typescript
const session = await client.checkout.createSession({
  amount: 2500,           // $25.00 in cents
  currency: 'USD',
  reference: 'order_123',
  returnUrl: 'https://yoursite.com/checkout/complete',
  shopperEmail: 'customer@example.com'
});

// Returns: { sessionId, sessionData, clientKey, environment, expiresAt, sdkUrl, sdkCssUrl }
```

#### Step 2: Initialize Checkout (Client-Side)

Include the checkout SDK (use `sdkUrl` and `sdkCssUrl` from the session response):
```html
<link rel="stylesheet" href="${session.sdkCssUrl}">
<script src="${session.sdkUrl}"></script>
```

Initialize with session data:
```javascript
const checkout = await iMerchantCheckout({
  clientKey: session.clientKey,
  environment: session.environment,  // 'test' or 'live'
  session: {
    id: session.sessionId,
    sessionData: session.sessionData
  },
  onPaymentCompleted: (result, component) => {
    // Payment successful - result.resultCode === 'Authorised'
    window.location.href = '/checkout/success';
  },
  onError: (error, component) => {
    console.error('Payment error:', error);
  }
});
```

#### Option A: Drop-in (Pre-built UI)

All payment methods in one component. Easiest integration.

```javascript
checkout.create('dropin').mount('#checkout-container');
```

```html
<div id="checkout-container"></div>
```

#### Option B: Components (Individual Payment Methods)

Mount specific payment methods with more control.

```javascript
// Card component only
checkout.create('card').mount('#card-container');

// Or specific methods
checkout.create('paypal').mount('#paypal-container');
checkout.create('applepay').mount('#applepay-container');
```

```html
<div id="card-container"></div>
<div id="paypal-container"></div>
```

#### Option C: Secured Fields (Full UI Control)

Individual input fields - you control all styling and layout.

```javascript
const card = checkout.create('securedfields', {
  type: 'card',
  styles: {
    base: {
      color: '#333',
      fontSize: '16px',
      fontFamily: 'inherit'
    },
    error: { color: '#d32f2f' },
    placeholder: { color: '#999' }
  },
  onConfigSuccess: () => {
    // Fields ready
  },
  onFieldValid: (field) => {
    // Individual field validated
  },
  onBrand: (brand) => {
    // Card brand detected (visa, mastercard, etc.)
    updateCardIcon(brand.brand);
  }
});

card.mount('#card-container');
```

```html
<div id="card-container">
  <!-- Secure iframes are injected for each field -->
  <label>Card Number</label>
  <span data-cse="encryptedCardNumber"></span>

  <label>Expiry</label>
  <span data-cse="encryptedExpiryDate"></span>

  <label>CVV</label>
  <span data-cse="encryptedSecurityCode"></span>
</div>

<button onclick="card.submit()">Pay Now</button>
```

#### Benefits

- **PCI SAQ-A Compliant** - Card data handled by secure iframes
- **No Redirect** - Payment form embedded in your checkout page
- **Multi-merchant** - Works with any merchant's API key
- **All Payment Methods** - Cards, PayPal, Apple Pay, Google Pay, etc.

### Refunds

```typescript
// Create a full refund
const refund = await client.refunds.create({
  paymentId: 'pay_abc123',
  reason: 'Customer request'
});

// Create a partial refund
const refund = await client.refunds.create({
  paymentId: 'pay_abc123',
  amount: 500,  // $5.00 in cents
  reason: 'Partial return'
});

// List refunds
const { data } = await client.refunds.list({
  paymentId: 'pay_abc123'
});
```

### Customers

```typescript
// Create a customer
const customer = await client.customers.create({
  email: 'john@example.com',
  firstName: 'John',
  lastName: 'Doe'
});

// Update a customer
const customer = await client.customers.update('cus_abc123', {
  phone: '+1234567890'
});

// List customers
const { data } = await client.customers.list({ limit: 20 });
```

### Subscriptions

```typescript
// Create a subscription
const subscription = await client.subscriptions.create({
  customerId: 'cus_abc123',
  amount: 2999,
  currency: 'usd',
  interval: 'month',
  trialDays: 14
});

// Cancel a subscription
await client.subscriptions.cancel('sub_abc123', {
  atPeriodEnd: true
});

// Pause/Resume
await client.subscriptions.pause('sub_abc123');
await client.subscriptions.resume('sub_abc123');
```

### Webhooks

```typescript
import { iMerchant } from '@imerchantsolutions/sdk';

// Express.js example
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['imerchant-signature'];

  try {
    const event = iMerchant.webhooks.verify(
      { body: req.body.toString(), signature },
      process.env.WEBHOOK_SECRET
    );

    switch (event.type) {
      case 'payment.captured':
        // Handle successful payment
        break;
      case 'payment.failed':
        // Handle failed payment
        break;
    }

    res.json({ received: true });
  } catch (err) {
    res.status(400).send('Invalid signature');
  }
});
```

## Error Handling

```typescript
import {
  iMerchant,
  APIError,
  AuthenticationError,
  ValidationError
} from '@imerchantsolutions/sdk';

try {
  await client.payments.create({ ... });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof ValidationError) {
    console.error('Validation errors:', error.errors);
  } else if (error instanceof APIError) {
    console.error(`API Error: ${error.code} - ${error.message}`);
  }
}
```

## Configuration

```typescript
const client = new iMerchant({
  apiKey: 'sk_test_...',      // Required
  baseUrl: 'https://...',     // Optional: custom API URL
  timeout: 30000,             // Optional: request timeout in ms
  apiVersion: 'v1'            // Optional: API version
});
```

## License

MIT