npm package: @portous/payment-sdk
Description: Official Node.js SDK for Portous Payment Platform - Accept payments, manage tokens, and handle transactions
Author: Portous Payment Platform
Latest version: 2.1.1

# 🚀 Portous Payment SDK v2.1.0

**Official Node.js SDK for Portous Payment Platform** - Complete payment processing, tokenization, and webhook handling in one package!

✨ **NEW in v2.1.0: Full TypeScript Support!**

---

## ✨ Features

- **💳 Payment Processing**: Create payments, payment links, and process transactions
- **🔐 Card Tokenization**: Save cards securely for future payments
- **🔔 Automatic Webhooks**: Built-in webhook server with signature verification
- **📡 Event-Driven**: Listen to payment events with simple event listeners
- **⚡ Zero Configuration**: Just API key + Profile ID = ready to go!
- **🧪 Built-in Testing**: Test webhooks and connections easily
- **🛡️ Secure by Default**: Automatic HMAC-SHA256 signature verification
- **✨ Full TypeScript Support**: Complete type definitions and autocomplete
- **📦 Dual Package**: Works with both ES Modules (`import`) and CommonJS (`require`)

---

## 📦 Installation

```bash
npm install @portous/payment-sdk
```

---

## 🚀 Quick Start

### JavaScript (CommonJS)

```javascript
const { PaymentClient } = require('@portous/payment-sdk');

// Initialize SDK
const client = new PaymentClient({
  apiKey: 'your-api-key',
  profileId: 'your-profile-id',
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
});

// Listen to payment events
client.on('webhook:payment.completed', (data) => {
  console.log('💰 Payment completed!', data.amount, data.currency);
  // Update order, send email, fulfill purchase
});

// Start webhook server (automatic!)
await client.startWebhook('https://your-backend.com');

// Create payment link
const payment = await client.payments.createLink({
  amount: 100.00,
  currency: 'ILS',
  transactionType: 'sale',
  billingInfo: {
    firstName: 'John',
    lastName: 'Doe',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  metadata: {
    orderId: '12345'
  }
});

console.log('Payment URL:', payment.paymentUrl);
console.log('HTML Form:', payment.htmlForm); // For WebView
// Send this URL to customer!
```

### TypeScript (ES Modules) ✨ NEW!

```typescript
import { PaymentClient, PaymentData, Transaction, ClientConfig } from '@portous/payment-sdk';

// ✅ Full type checking and autocomplete
const config: ClientConfig = {
  apiKey: 'your-api-key',
  profileId: 'your-profile-id',
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1',
  debug: true
};

const client = new PaymentClient(config);

// ✅ Typed event listeners
client.on('webhook:payment.completed', (data: Transaction) => {
  console.log('💰 Payment completed!', data.amount, data.currency);
  console.log('Transaction ID:', data.transactionId);
  console.log('Metadata:', data.metadata);
});

// Start webhook server
await client.startWebhook('https://your-backend.com');

// ✅ Typed payment data with autocomplete
const paymentData: PaymentData = {
  amount: 100.00,
  currency: 'ILS',
  transactionType: 'sale',
  billingInfo: {
    firstName: 'John',
    lastName: 'Doe',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  customerId: 'user123',
  metadata: {
    orderId: '12345',
    description: 'Product purchase'
  }
};

const payment = await client.payments.createLink(paymentData);
console.log('Payment URL:', payment.paymentUrl);
```

---

## 📚 Complete API Reference

### 🔧 **Client Configuration**

#### **Constructor Options**

**JavaScript:**
```javascript
const client = new PaymentClient({
  apiKey: 'your-api-key',              // Required: Your API key
  profileId: 'your-profile-id',        // Required: Your profile UUID
  baseUrl: 'https://platform.com/api/v1', // Optional: Platform URL
  timeout: 30000,                       // Optional: Request timeout (ms)
  debug: false                          // Optional: Enable debug logging
});
```

**TypeScript:** ✨
```typescript
import { PaymentClient, ClientConfig } from '@portous/payment-sdk';

const config: ClientConfig = {
  apiKey: 'your-api-key',
  profileId: 'your-profile-id',
  baseUrl: 'https://platform.com/api/v1',
  timeout: 30000,
  debug: true
};

const client = new PaymentClient(config);
```

#### **Client Methods**

| Method | Description | Returns |
|--------|-------------|---------|
| `healthCheck()` | Test connection to platform | `Promise<boolean>` |
| `startWebhook(publicUrl, options?)` | Start webhook server | `Promise<Express>` |
| `registerWebhookUrl(url)` | Register webhook URL | `Promise<{success, message}>` |
| `testWebhook()` | Test webhook functionality | `Promise<object>` |
| `fetchWebhookSecret()` | Get webhook secret | `Promise<string>` |
| `verifyWebhookSignature(payload, sig, secret)` | Verify webhook signature | `boolean` |

---

### 💳 **Payments API** (`client.payments`)

#### **1. Create Payment Link**

Create a payment link for customer to complete payment.

**JavaScript:**
```javascript
const payment = await client.payments.createLink({
  amount: 250.50,
  currency: 'ILS',
  transactionType: 'sale', // 'sale', 'authorization', 'sale,create_payment_token'
  billingInfo: {
    firstName: 'John',
    lastName: 'Doe',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345',
    state: 'PS-RBH',
    country: 'PS'
  },
  customerId: 'CUST-999',  // Optional: Link to your customer
  referenceNumber: 'ORD-12345',
  metadata: {
    orderId: '12345',
    description: 'Product purchase'
  }
});

console.log('Payment URL:', payment.paymentUrl);
console.log('HTML Form:', payment.htmlForm); // For WebView integration
```

**TypeScript:** ✨
```typescript
import { PaymentData, PaymentLinkResponse } from '@portous/payment-sdk';

const paymentData: PaymentData = {
  amount: 250.50,
  currency: 'ILS',
  transactionType: 'sale',
  billingInfo: {
    firstName: 'John',
    lastName: 'Doe',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  customerId: 'CUST-999',
  referenceNumber: 'ORD-12345',
  metadata: {
    orderId: '12345'
  }
};

const payment: PaymentLinkResponse = await client.payments.createLink(paymentData);
console.log('Payment URL:', payment.paymentUrl);
```

---

#### **1a. Payment + Save Card (One Transaction)**

Charge customer AND save their card for future use in a single transaction:

**JavaScript:**
```javascript
const payment = await client.payments.createLink({
  amount: 100.00,
  currency: 'ILS',
  transactionType: 'sale,create_payment_token',  // ← Pay + Save Card!
  billingInfo: {
    firstName: 'John',
    lastName: 'Doe',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  customerId: 'CUST-999',
  referenceNumber: 'ORD-12345'
});

console.log('Payment URL:', payment.paymentUrl);
// Customer pays AND card is saved - both in one step!
```

**TypeScript:** ✨
```typescript
const paymentData: PaymentData = {
  amount: 100.00,
  currency: 'ILS',
  transactionType: 'sale,create_payment_token',
  billingInfo: { /* ... */ },
  customerId: 'CUST-999',
  metadata: {
    saveCard: true
  }
};

const payment = await client.payments.createLink(paymentData);
```

**What happens:**
1. ✅ Customer pays 100 ILS immediately
2. ✅ Card is saved as a payment token
3. ✅ You can charge this card later without customer entering details
4. ✅ Perfect for first-time purchases with subscription option

**Response:**
```javascript
{
  transactionUuid: "uuid-here",
  referenceNumber: "ORD-12345",
  hostedCheckoutUrl: "https://cybersource.com/checkout/...",
  amount: "250.50",
  currency: "ILS",
  status: "pending"
}
```

---

#### **2. Create Payment Link**

Create a shareable payment link that can be sent to customers.

```javascript
const link = await client.payments.createLink({
  amount: 100.00,
  currency: 'ILS',
  description: 'Invoice #INV-2025-001',
  customerEmail: 'customer@example.com',
  customerName: 'Jane Smith',
  referenceNumber: 'INV-2025-001',
  
  // Optional: Expiration (in seconds)
  expiresIn: 86400, // 24 hours (default: 24 hours)
  
  // Optional: Usage limits
  maxUses: 1, // Default: 1 (one-time use)
  
  // Optional: Metadata
  metadata: {
    invoiceId: 'INV-2025-001',
    customerId: 'CUST-456'
  }
});

console.log('Payment Link:', link.paymentLink);
console.log('Link ID:', link.linkId);
console.log('Expires At:', link.expiresAt);
```

**Response:**
```javascript
{
  linkId: "abc123xyz",
  transactionUuid: "uuid-here",
  paymentLink: "https://platform.com/p/abc123xyz",
  shortLink: "https://platform.com/p/abc123xyz",
  amount: "100.00",
  currency: "ILS",
  expiresAt: "2025-10-13T12:00:00.000Z",
  maxUses: 1,
  usedCount: 0,
  status: "active"
}
```

---

#### **3. Get Payment Status**

Get the status of a specific transaction.

```javascript
const transaction = await client.payments.getStatus('transaction-uuid');

console.log('Status:', transaction.status);
console.log('Decision:', transaction.decision);
console.log('Amount:', transaction.amount);
```

**Response:**
```javascript
{
  id: "uuid",
  referenceNumber: "ORD-12345",
  amount: "100.00",
  currency: "ILS",
  status: "completed", // 'pending', 'completed', 'declined', 'cancelled', 'error'
  decision: "ACCEPT",  // 'ACCEPT', 'DECLINE', 'ERROR', 'REVIEW', 'CANCEL'
  reasonCode: "100",
  message: "Transaction approved",
  customerEmail: "customer@example.com",
  createdAt: "2025-10-12T10:00:00.000Z",
  updatedAt: "2025-10-12T10:05:00.000Z"
}
```

---

#### **4. List Transactions**

List all transactions with optional filtering.

```javascript
const transactions = await client.payments.list({
  page: 1,
  limit: 20,
  
  // Optional filters
  status: 'completed', // 'pending', 'completed', 'declined', 'cancelled'
  startDate: '2025-10-01',
  endDate: '2025-10-31'
});

console.log('Total:', transactions.pagination.total);
console.log('Page:', transactions.pagination.page);
console.log('Transactions:', transactions.data.length);

transactions.data.forEach(tx => {
  console.log(`${tx.referenceNumber}: ${tx.amount} ${tx.currency} - ${tx.status}`);
});
```

**Response:**
```javascript
{
  data: [
    {
      id: "uuid",
      referenceNumber: "ORD-001",
      amount: "100.00",
      currency: "ILS",
      status: "completed",
      decision: "ACCEPT",
      createdAt: "2025-10-12T10:00:00.000Z"
    }
    // ... more transactions
  ],
  pagination: {
    page: 1,
    limit: 20,
    total: 150,
    pages: 8
  }
}
```

---

#### **5. Get Payment Link**

Get details of a specific payment link.

```javascript
const link = await client.payments.getLink('link-id');

console.log('Link URL:', link.paymentLink);
console.log('Status:', link.status);
console.log('Used:', link.usedCount, '/', link.maxUses);
```

---

#### **6. List Payment Links**

List all payment links.

```javascript
const links = await client.payments.listLinks({
  page: 1,
  limit: 20,
  status: 'active' // 'active', 'completed', 'expired', 'cancelled'
});

links.data.forEach(link => {
  console.log(`${link.linkId}: ${link.amount} ${link.currency} - ${link.status}`);
});
```

---

#### **7. Cancel Payment Link**

Cancel an active payment link.

```javascript
await client.payments.cancelLink('link-id');
console.log('Payment link cancelled');
```

---

#### **8. Refund Payment**

Request a refund for a completed payment.

```javascript
const refund = await client.payments.refund({
  transactionId: 'original-transaction-uuid',
  amount: 50.00, // Partial refund (optional, full refund if omitted)
  reason: 'Customer requested refund'
});

console.log('Refund ID:', refund.refundId);
console.log('Status:', refund.status);
```

---

### 🔐 **Tokenization API** (`client.tokens`)

#### **1. Create Tokenization Request**

Create a request for customer to save their card.

**JavaScript:**
```javascript
const tokenization = await client.tokens.create({
  billingInfo: {
    firstName: 'Jane',
    lastName: 'Smith',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  customerId: 'CUST-999',  // Your internal customer ID - links card to customer
  metadata: {
    source: 'mobile_app'
  }
});

console.log('Tokenization URL:', tokenization.tokenizationUrl);
console.log('HTML Form:', tokenization.htmlForm); // For WebView
// Send this URL to customer to enter card details
```

**TypeScript:** ✨
```typescript
import { TokenData, TokenCreationResponse } from '@portous/payment-sdk';

const tokenData: TokenData = {
  billingInfo: {
    firstName: 'Jane',
    lastName: 'Smith',
    email: 'customer@example.com',
    addressLine1: '123 Main St',
    city: 'Ramallah',
    postalCode: '12345'
  },
  customerId: 'CUST-999',
  metadata: {
    source: 'mobile_app'
  }
};

const tokenization: TokenCreationResponse = await client.tokens.create(tokenData);
console.log('Tokenization URL:', tokenization.tokenizationUrl);
```

**Response:**
```javascript
{
  success: true,
  tokenRequestId: "uuid-here",
  status: "pending",
  tokenizationUrl: "https://cybersource.com/tokenize/...",
  htmlForm: "<form>...</form>" // For WebView integration
}
```

**After customer saves card:**
- You receive webhook: `webhook:token.created`
- Token is saved and can be used for future charges

---

#### **2. List Saved Tokens**

Get all saved payment tokens.

**JavaScript:**
```javascript
const result = await client.tokens.list({
  page: 1,
  limit: 20,
  status: 'active', // 'active' or 'inactive'
  customerId: 'CUST-999' // Optional: filter by customer
});

console.log('Total tokens:', result.pagination.total);

result.tokens.forEach(token => {
  console.log(`Token: ${token.id}`);
  console.log(`  Customer: ${token.customerEmail}`);
  console.log(`  Card: ${token.cardType} ending in ${token.cardLastFour}`);
  console.log(`  Status: ${token.status}`);
  console.log(`  Created: ${new Date(token.createdAt).toLocaleDateString()}`);
});
```

**TypeScript:** ✨
```typescript
import { TokenListOptions, PaymentToken } from '@portous/payment-sdk';

const options: TokenListOptions = {
  page: 1,
  limit: 20,
  status: 'active',
  customerId: 'CUST-999'
};

const result = await client.tokens.list(options);

result.tokens.forEach((token: PaymentToken) => {
  console.log(`${token.cardType} **** ${token.cardLastFour}`);
});
```

---

#### **2a. Get Cards for Specific Customer**

Get all saved cards for a specific customer using their customer ID.

```javascript
const customerCards = await client.tokens.list({
  customerId: 'CUST-999',  // Your internal customer ID
  isActive: true,
  page: 1,
  limit: 10
});

console.log(`Customer CUST-999 has ${customerCards.data.length} saved card(s)`);

customerCards.data.forEach(card => {
  console.log(`Card: ${card.card_type} ending in ${card.card_last_four}`);
  console.log(`  Expiry: ${card.card_expiry}`);
  console.log(`  Token ID: ${card.id}`);
});
```

**Use case:** Show customer their saved cards, allow them to manage or delete cards.

**Response:**
```javascript
{
  data: [
    {
      id: "token-uuid",
      customer_email: "customer@example.com",
      card_type: "001", // Visa
      masked_card_number: "****1234",
      expiry_date: "12/2025",
      status: "active",
      created_at: "2025-10-01T10:00:00.000Z",
      last_used: "2025-10-12T08:30:00.000Z"
    }
    // ... more tokens
  ],
  pagination: {
    page: 1,
    limit: 20,
    total: 45,
    pages: 3
  }
}
```

---

#### **3. Get Token Details**

Get details of a specific token.

```javascript
const token = await client.tokens.get('token-uuid');

console.log('Card Type:', token.card_type);
console.log('Last 4 Digits:', token.masked_card_number);
console.log('Expiry:', token.expiry_date);
console.log('Status:', token.status);
```

---

#### **4. Charge Saved Card**

Charge a customer using their saved token (no card entry required!).

**JavaScript:**
```javascript
const payment = await client.tokens.pay({
  paymentToken: 'saved-token-uuid',
  amount: 99.99,
  currency: 'ILS',
  referenceNumber: 'SUB-RENEWAL-2025-10',
  metadata: {
    subscriptionId: 'SUB-123',
    billingCycle: 'monthly'
  }
});

console.log('Payment created:', payment.transactionUuid);
console.log('Status:', payment.status);
console.log('HTML Form:', payment.htmlForm); // For 3DS verification if needed
// Customer is charged automatically!
```

**TypeScript:** ✨
```typescript
import { TokenPaymentData, PaymentLinkResponse } from '@portous/payment-sdk';

const tokenPaymentData: TokenPaymentData = {
  paymentToken: 'saved-token-uuid',
  amount: 99.99,
  currency: 'ILS',
  referenceNumber: 'SUB-RENEWAL-2025-10',
  metadata: {
    subscriptionId: 'SUB-123',
    billingCycle: 'monthly'
  }
};

const payment: PaymentLinkResponse = await client.tokens.pay(tokenPaymentData);
console.log('Payment status:', payment.status);
```

**Response:**
```javascript
{
  transactionUuid: "uuid-here",
  referenceNumber: "SUB-RENEWAL-2025-10",
  amount: "99.99",
  currency: "ILS",
  status: "completed", // Usually instant!
  paymentToken: "saved-token-uuid"
}
```

---

#### **5. Deactivate Token**

Deactivate a saved card token.

```javascript
await client.tokens.deactivate('token-uuid');
console.log('Token deactivated');
```

---

#### **6. Get Token Statistics**

Get statistics about your tokens.

```javascript
const stats = await client.tokens.getStats();

console.log('Total tokens:', stats.total);
console.log('Active tokens:', stats.active);
console.log('Used tokens:', stats.used);
console.log('Expired tokens:', stats.expired);
```

---

#### **7. Get Token Transactions**

Get all transactions made with a specific saved card.

```javascript
const history = await client.tokens.getTransactions('token-uuid', {
  page: 1,
  limit: 20
});

console.log(`Total charges: ${history.pagination.total}`);

history.transactions.forEach(tx => {
  console.log(`${new Date(tx.created_at).toLocaleDateString()}: ${tx.amount} ${tx.currency} - ${tx.status}`);
  console.log(`  Reference: ${tx.reference_number}`);
});
```

**Use case:** Show customer their card usage history or track subscription payments.

---

### 🔔 **Webhook Events**

The SDK automatically handles webhooks and emits events for your application.

#### **Available Events**

| Event | Description | When It Fires |
|-------|-------------|---------------|
| `payment.completed` | Payment successful | Customer completes payment |
| `payment.declined` | Payment declined | Bank/Cybersource declines payment |
| `payment.cancelled` | Payment cancelled | Customer cancels payment |
| `payment.error` | Payment error | Technical error occurs |
| `payment.pending` | Payment pending | Payment needs review |
| `webhook:started` | Webhook server started | SDK starts webhook server |
| `webhook:stopped` | Webhook server stopped | SDK stops webhook server |
| `webhook:received` | Any webhook received | Any webhook arrives |

#### **Event Data Structure**

```javascript
client.on('payment.completed', (data) => {
  console.log(data);
  /*
  {
    transactionUuid: "uuid-here",
    referenceNumber: "ORD-12345",
    amount: "100.00",
    currency: "ILS",
    status: "completed",
    decision: "ACCEPT",
    reasonCode: "100",
    message: "Transaction approved",
    customerEmail: "customer@example.com",
    customerName: "John Doe",
    cardType: "001", // Visa
    maskedCardNumber: "****1234",
    processedAt: "2025-10-12T10:05:00.000Z",
    metadata: { ... } // Your custom metadata
  }
  */
});
```

#### **Complete Event Handling Example**

**JavaScript:**
```javascript
const { PaymentClient } = require('@portous/payment-sdk');

const client = new PaymentClient({
  apiKey: process.env.API_KEY,
  profileId: process.env.PROFILE_ID,
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
});

// Payment completed
client.on('webhook:payment.completed', async (data) => {
  console.log(`✅ Payment completed: ${data.amount} ${data.currency}`);
  
  // YOUR BUSINESS LOGIC
  await updateOrderStatus(data.referenceNumber, 'paid');
  await sendConfirmationEmail(data.customerEmail);
  await fulfillOrder(data.referenceNumber);
  await updateInventory(data.metadata.items);
});

// Payment failed
client.on('webhook:payment.failed', async (data) => {
  console.log(`❌ Payment failed: ${data.reasonCode}`);
  
  await updateOrderStatus(data.referenceNumber, 'payment_failed');
  await sendPaymentFailedEmail(data.customerEmail);
});

// Token created (card saved)
client.on('webhook:token.created', async (data) => {
  console.log(`💳 Card saved: **** ${data.cardLastFour}`);
  
  await linkCardToCustomer(data.metadata.customerId, data.id);
});

// Webhook errors
client.on('webhook:error', (error) => {
  console.error(`💥 Webhook error: ${error.message}`);
  await alertAdminTeam(error);
});

// Webhook lifecycle
client.on('webhook:started', (info) => {
  console.log(`🔔 Webhook server started on port ${info.port}`);
  console.log(`   Webhook URL: ${info.webhookUrl}`);
});

// Start webhook server (auto-registers with platform)
await client.startWebhook('https://your-backend.com');

console.log('🚀 Ready to receive payments!');
```

**TypeScript:** ✨
```typescript
import { PaymentClient, Transaction, ClientConfig } from '@portous/payment-sdk';

const config: ClientConfig = {
  apiKey: process.env.API_KEY!,
  profileId: process.env.PROFILE_ID!,
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
};

const client = new PaymentClient(config);

// ✅ Full type checking for webhook data
client.on('webhook:payment.completed', async (data: Transaction) => {
  console.log(`✅ Payment completed: ${data.amount} ${data.currency}`);
  console.log(`Transaction ID: ${data.transactionId}`);
  console.log(`Metadata:`, data.metadata);
  
  // YOUR BUSINESS LOGIC with type safety
  await updateOrderStatus(data.referenceNumber, 'paid');
  await sendConfirmationEmail(data.customerEmail);
});

client.on('webhook:payment.failed', async (data: Transaction) => {
  console.log(`❌ Payment failed: ${data.reasonCode}`);
  await handleFailedPayment(data);
});

client.on('webhook:token.created', async (data: Transaction) => {
  console.log(`💳 Card saved: ${data.cardType} **** ${data.cardLastFour}`);
  await linkCardToCustomer(data.metadata?.customerId, data.id);
});

await client.startWebhook('https://your-backend.com');
```

---

### 🛠️ **Webhook Management**

#### **Start Webhook Server**

```javascript
// Option 1: Production with auto-registration
await client.startWebhook('https://your-backend.com');
// SDK automatically registers: https://your-backend.com/webhooks/{profileId}

// Option 2: Development with ngrok
await client.startWebhook('https://abc123.ngrok.io');

// Option 3: Local only (manual dashboard setup)
await client.startWebhook();
```

**What it does:**
1. ✅ Fetches webhook secret from platform (via API key)
2. ✅ Creates Express server on port 3003
3. ✅ Registers webhook URL with platform (if public URL provided)
4. ✅ Verifies all incoming webhook signatures
5. ✅ Emits events for your application

#### **Stop Webhook Server**

```javascript
client.stopWebhook();
```

#### **Manual Webhook Registration**

```javascript
// Usually not needed - startWebhook() does this automatically
await client.registerWebhookUrl('https://your-backend.com/webhooks');
```

---

## 🎯 **Complete Usage Examples**

### **Example 1: E-commerce Store**

```javascript
const PaymentClient = require('@portous/payment-sdk');

const client = new PaymentClient({
  apiKey: process.env.API_KEY,
  profileId: process.env.PROFILE_ID,
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
});

// Create payment link for order
async function createOrderPayment(order) {
  const link = await client.payments.createLink({
    amount: order.totalAmount,
    currency: 'ILS',
    description: `Order #${order.id}`,
    customerEmail: order.customerEmail,
    customerName: order.customerName,
    referenceNumber: order.id,
    expiresIn: 86400, // 24 hours
    metadata: {
      orderId: order.id,
      items: order.items
    }
  });
  
  return link.paymentLink; // Send to customer via email/SMS
}

// Handle payment completion
client.on('payment.completed', async (data) => {
  const order = await getOrder(data.referenceNumber);
  
  // Mark order as paid
  order.status = 'paid';
  order.paymentId = data.transactionUuid;
  await order.save();
  
  // Send confirmation
  await sendOrderConfirmation(order);
  
  // Fulfill order
  await fulfillOrder(order);
});

await client.startWebhook('https://store.example.com');
```

---

### **Example 2: Subscription Service**

```javascript
const PaymentClient = require('@portous/payment-sdk');

const client = new PaymentClient({
  apiKey: process.env.API_KEY,
  profileId: process.env.PROFILE_ID,
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
});

// Step 1: Customer signs up - save their card
async function signUpCustomer(email, name) {
  const tokenization = await client.tokens.create({
    customerEmail: email,
    customerName: name,
    referenceNumber: `SIGNUP-${Date.now()}`,
    description: 'Save card for subscription'
  });
  
  return tokenization.tokenizationUrl; // Send to customer
}

// Step 2: Charge customer monthly (automatic!)
async function chargeMonthlySubscription(customer) {
  const payment = await client.tokens.pay({
    tokenId: customer.savedTokenId,
    amount: 29.99,
    currency: 'USD',
    referenceNumber: `SUB-${customer.id}-${Date.now()}`,
    description: 'Monthly subscription'
  });
  
  return payment.transactionUuid;
}

// Step 3: Handle successful charges
client.on('payment.completed', async (data) => {
  if (data.referenceNumber.startsWith('SUB-')) {
    const customerId = data.referenceNumber.split('-')[1];
    
    // Extend subscription
    await extendSubscription(customerId, 30); // 30 days
    
    // Send receipt
    await sendReceipt(data.customerEmail, data);
  }
});

// Handle failed charges
client.on('payment.declined', async (data) => {
  if (data.referenceNumber.startsWith('SUB-')) {
    const customerId = data.referenceNumber.split('-')[1];
    
    // Notify customer
    await sendPaymentFailedNotification(customerId);
    
    // Retry in 3 days
    await scheduleRetry(customerId, 3);
  }
});

await client.startWebhook('https://subscription-service.com');

// Charge all subscriptions (run daily via cron)
async function chargeAllSubscriptions() {
  const customers = await getActiveSubscribers();
  
  for (const customer of customers) {
    try {
      await chargeMonthlySubscription(customer);
    } catch (error) {
      console.error(`Failed to charge ${customer.email}:`, error.message);
    }
  }
}
```

---

### **Example 3: Invoice Payment System**

```javascript
const PaymentClient = require('@portous/payment-sdk');

const client = new PaymentClient({
  apiKey: process.env.API_KEY,
  profileId: process.env.PROFILE_ID,
  baseUrl: 'https://payment-platform-production.up.railway.app/api/v1'
});

// Create invoice with payment link
async function createInvoice(invoice) {
  const link = await client.payments.createLink({
    amount: invoice.totalAmount,
    currency: invoice.currency,
    description: `Invoice ${invoice.invoiceNumber}`,
    customerEmail: invoice.customerEmail,
    customerName: invoice.customerName,
    referenceNumber: invoice.invoiceNumber,
    expiresIn: 30 * 24 * 60 * 60, // 30 days
    metadata: {
      invoiceId: invoice.id,
      dueDate: invoice.dueDate
    }
  });
  
  // Save payment link to invoice
  invoice.paymentLink = link.paymentLink;
  invoice.paymentLinkId = link.linkId;
  await invoice.save();
  
  // Send invoice email with payment link
  await sendInvoiceEmail(invoice);
  
  return link;
}

// Handle payment
client.on('payment.completed', async (data) => {
  const invoice = await findInvoiceByNumber(data.referenceNumber);
  
  // Mark as paid
  invoice.status = 'paid';
  invoice.paidAt = new Date();
  invoice.paymentId = data.transactionUuid;
  await invoice.save();
  
  // Send receipt
  await sendPaymentReceipt(invoice);
  
  // Update accounting system
  await updateAccounting(invoice);
});

await client.startWebhook('https://invoice-system.com');
```

---

## 🐛 **Debug Mode**

Enable detailed debug logging to troubleshoot issues:

```javascript
const client = new PaymentClient({
  apiKey: 'your-api-key',
  profileId: 'your-profile-id',
  debug: true // Enable debug logging
});
```

**What Debug Mode Shows:**
- 🐛 SDK initialization details (profile ID, API key prefix)
- 🐛 Webhook secret retrieval process
- 🐛 Webhook registration attempts
- 🐛 Incoming webhook headers and body
- 🐛 Signature verification details
- 🐛 Event emission details
- 🐛 API request/response details

**Example Output:**
```
🚀 Portous Payment SDK v2.0.1 initialized
   Base URL: https://platform.com/api/v1
   Webhook enabled: true
   🐛 Debug mode: ENABLED
   Profile ID: abc-123-def
   API Key: 709d0345...
🐛 [DEBUG] Fetching webhook secret from platform...
🐛 [DEBUG] Webhook secret retrieved: e362754a...
🐛 [DEBUG] Registering webhook URL with platform: https://my-app.com/webhooks
🐛 [DEBUG] Webhook URL registered successfully
🐛 [DEBUG] Webhook received: { headers: {...}, body: {...} }
🐛 [DEBUG] Signature verified successfully
🐛 [DEBUG] Emitting event: payment.completed {...}
```

**⚠️ Warning:** Debug mode logs sensitive information (API keys, secrets). Only use in development!

---

## 🚀 **Production Deployment**

### **Environment Variables**

```bash
# Required
API_KEY=your-api-key
PROFILE_ID=your-profile-id

# Recommended
PUBLIC_URL=https://your-app.com  # For auto-registration
PLATFORM_URL=https://payment-platform-production.up.railway.app/api/v1

# Optional
WEBHOOK_PORT=3003
NODE_ENV=production
```

### **Heroku**

```bash
heroku config:set API_KEY=your-api-key
heroku config:set PROFILE_ID=your-profile-id
heroku config:set PUBLIC_URL=https://your-app.herokuapp.com
```

### **Railway**

```bash
railway variables set API_KEY=your-api-key
railway variables set PROFILE_ID=your-profile-id
railway variables set PUBLIC_URL=https://your-app.up.railway.app
```

### **Docker**

```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3003
ENV PUBLIC_URL=https://your-app.com
CMD ["node", "server.js"]
```

### **Using ngrok (Development)**

```bash
# Terminal 1: Start ngrok
ngrok http 3003

# Terminal 2: Start your app with ngrok URL
PUBLIC_URL=https://abc123.ngrok.io node server.js
```

---

## 🔒 **Security Features**

- ✅ **Automatic Signature Verification**: All webhooks verified with HMAC-SHA256
- ✅ **Secure Secret Management**: Secrets fetched securely via API key
- ✅ **Timing-Safe Comparison**: Prevents timing attacks
- ✅ **HTTPS Enforcement**: Production requires HTTPS
- ✅ **IP Validation**: No localhost/private IPs in production
- ✅ **Rate Limiting**: Built-in protection

---

## 🧪 **Testing**

### **Test Connection**

```javascript
const isHealthy = await client.healthCheck();
console.log('Platform healthy:', isHealthy);
```

### **Test Webhook**

```javascript
const result = await client.testWebhook();
console.log('Webhook test:', result);
// Emits test event
```

---

## 📘 **TypeScript Usage**

### **Full Type Definitions**

The SDK includes complete TypeScript definitions. Import types as needed:

```typescript
import {
  // Main Client
  PaymentClient,
  ClientConfig,
  
  // Payment Types
  PaymentData,
  PaymentLinkResponse,
  Transaction,
  TransactionType,
  TransactionStatus,
  
  // Token Types
  TokenData,
  TokenPaymentData,
  TokenCreationResponse,
  PaymentToken,
  TokenStatus,
  TokenListOptions,
  
  // Other Types
  BillingInfo,
  RefundData,
  ListOptions,
  HealthCheckResponse,
  
  // Error Types
  PaymentError
} from '@portous/payment-sdk';
```

### **TypeScript Configuration**

Ensure your `tsconfig.json` includes:

```json
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": true
  }
}
```

### **Example: NestJS Integration**

```typescript
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PaymentClient, Transaction, PaymentData } from '@portous/payment-sdk';

@Injectable()
export class PaymentService implements OnModuleInit {
  private client: PaymentClient;

  constructor(private configService: ConfigService) {
    this.client = new PaymentClient({
      apiKey: this.configService.get('PORTOUS_API_KEY')!,
      profileId: this.configService.get('PORTOUS_PROFILE_ID')!,
      baseUrl: this.configService.get('PORTOUS_BASE_URL')!,
      debug: true
    });
  }

  async onModuleInit() {
    // Setup webhooks
    this.client.on('webhook:payment.completed', (data: Transaction) => {
      this.handlePaymentCompleted(data);
    });

    await this.client.startWebhook(
      this.configService.get('PUBLIC_URL')!
    );
  }

  async createPayment(amount: number, customerId: string) {
    const paymentData: PaymentData = {
      amount,
      currency: 'ILS',
      transactionType: 'sale',
      billingInfo: {
        firstName: 'Customer',
        lastName: 'Name',
        email: 'customer@example.com',
        addressLine1: 'Address',
        city: 'Ramallah',
        postalCode: '12345'
      },
      customerId,
      metadata: {
        customerId,
        source: 'api'
      }
    };

    return await this.client.payments.createLink(paymentData);
  }

  private handlePaymentCompleted(data: Transaction) {
    // Full type safety
    console.log(`Payment ${data.transactionId} completed`);
    console.log(`Amount: ${data.amount} ${data.currency}`);
    console.log(`Customer: ${data.metadata?.customerId}`);
  }
}
```

---

## 🔧 **Troubleshooting**

### **Common Issues**

**1. Webhook not receiving events**
- Check if PUBLIC_URL is accessible from internet
- Verify firewall allows port 3003
- Check webhook registration in dashboard

**2. Signature verification failed**
- Ensure webhook secret is correct
- Check system time synchronization
- Enable debug mode to see signature details

**3. Connection timeout**
- Verify platform URL is correct
- Check network connectivity
- Increase timeout value

---

## 📝 **Changelog**

### v2.1.0 (Latest) ✨

- ✅ **Full TypeScript support** with complete `.d.ts` definitions
- ✅ **ES Modules support** - Use modern `import` syntax
- ✅ **Dual package** - Works with both ESM and CommonJS
- ✅ **Enhanced types** - All functions fully typed
- ✅ **Better autocomplete** - IntelliSense in VS Code
- ✅ **NestJS optimized** - Perfect for TypeScript projects
- ✅ **No breaking changes** - Fully backward compatible

### v2.0.5

- Payment creation and tokenization
- Webhook handling and auto-registration
- Event-driven architecture
- Customer ID linking
- Metadata support

---

## 📄 **License**

MIT License - see LICENSE file for details

---

## 🤝 **Support**

- **Documentation**: [Complete Integration Guide](./NESTJS_INTEGRATION_GUIDE.md)
- **Issues**: [GitHub Issues](https://github.com/portousz/payment-sdk/issues)
- **Email**: support@portous.com

---

**Made with ❤️ by the Portous Team**