npm package: @flixora/airxpay
Description: AirXPay Initialization Data activities API__for Node & Express etc.
Author: Tafseel Khan
Latest version: 0.0.5
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

<p align="center">
  <a href="#-nodejs">
    <img src="https://img.shields.io/badge/Node.js-18.0+-339933?style=for-the-badge&logo=node.js" alt="Node.js" />
  </a>
  <a href="#-typescript">
    <img src="https://img.shields.io/badge/TypeScript-5.0+-3178C6?style=for-the-badge&logo=typescript" alt="TypeScript" />
  </a>
  <a href="#-express">
    <img src="https://img.shields.io/badge/Express-4.18+-000000?style=for-the-badge&logo=express" alt="Express" />
  </a>
  <a href="#-javascript">
    <img src="https://img.shields.io/badge/JavaScript-ES6+-F7DF1E?style=for-the-badge&logo=javascript" alt="JavaScript" />
  </a>
  <a href="#-nestjs">
    <img src="https://img.shields.io/badge/NestJS-10.0+-E0234E?style=for-the-badge&logo=nestjs" alt="NestJS" />
  </a>
  <a href="#-mit-license">
    <img src="https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge&logo=open-source-initiative" alt="MIT License" />
  </a>
</p>

# @flixora/airxpay 🚀

![npm version](https://img.shields.io/npm/v/@flixora/airxpay)
![license](https://img.shields.io/npm/l/@flixora/airxpay)
![downloads](https://img.shields.io/npm/dm/@flixora/airxpay)

Official AirXPay SDK for Node.js - Easily integrate merchant onboarding and payment services into your application.

## 📦 Installation

```bash
npm install @flixora/airxpay
# or
yarn add @flixora/airxpay
```

## 🔑 Environment Setup

Create a `.env` file in your project root:

```env
AIRXPAY_SECRET_KEY=your_secret_key_here
AIRXPAY_CLIENT_KEY=your_client_key_here
```

## 📝 Complete Express.js Controller Example

Here's a production-ready controller showing how to integrate the SDK in your Express.js application:

```typescript
// controllers/sellerController.ts
import { Request, Response } from "express";
import { AirXPay } from "@flixora/airxpay";

// 🔒 Backend keys from .env
const AIRXPAY_SECRET_KEY = process.env.AIRXPAY_SECRET_KEY || "";
const AIRXPAY_CLIENT_KEY = process.env.AIRXPAY_CLIENT_KEY || "";

if (!AIRXPAY_SECRET_KEY)
  throw new Error("AIRXPAY_SECRET_KEY is not defined in .env");
if (!AIRXPAY_CLIENT_KEY)
  throw new Error("AIRXPAY_CLIENT_KEY is not defined in .env");

/**
 * ✅ CREATE SELLER (CREATE MERCHANT)
 * frontend sends publicKey as 'publicKey' in body
 */
export const createSeller = async (req: Request, res: Response) => {
  console.log("📥 [CREATE SELLER] Request received:", new Date().toISOString());

  try {
    const { seller, publicKey } = req.body;
    console.log("📦 [CREATE SELLER] Body keys:", Object.keys(req.body));

    // 🔹 Validate required fields
    if (!seller?.merchantName || !seller?.merchantEmail) {
      return res.status(400).json({
        success: false,
        message: "merchantName and merchantEmail are required",
      });
    }
    if (!publicKey) {
      return res.status(400).json({
        success: false,
        message: "frontend public key is required",
      });
    }

    // 🔹 Prepare merchant data
    const merchantData = {
      merchantName: seller.merchantName,
      merchantEmail: seller.merchantEmail,
      merchantPhone: seller.merchantPhone,
      businessName: seller.businessName,
      businessType: seller.businessType || "individual",
      businessCategory: seller.businessCategory,
      country: seller.country || "India",
      nationality: seller.nationality || "Indian",
      dob: seller.dob,
      mode: seller.mode || "test",
      metadata: seller.metadata || {},
      kycDetails: seller.kycDetails,
      bankDetails: seller.bankDetails,
      publicKey,
    };

    console.log("🔑 [CREATE SELLER] Prepared merchant data:", {
      merchantName: merchantData.merchantName,
      merchantEmail: merchantData.merchantEmail,
      hasPublicKey: !!merchantData.publicKey,
    });

    // 🔹 Call SDK → which calls company backend → returns token + merchant
    console.log("📡 [CREATE SELLER] Calling AirXPay.flixora.createMerchant...");
    const result = await AirXPay.flixora.createMerchant(publicKey, {
      ...merchantData,
      clientKey: AIRXPAY_CLIENT_KEY,
      secretKey: AIRXPAY_SECRET_KEY,
    });

    console.log("✅ [CREATE SELLER] Merchant created successfully:", {
      merchantId: result.merchant.merchantId,
      airxpayMerchantId: result.merchant.airxpayMerchantId,
      status: result.merchant.status,
    });

    // 🔹 Return final response to frontend
    return res.status(200).json({
      success: true,
      message: "Merchant created successfully",
      merchantId: result.merchant.merchantId,
      airxpayMerchantId: result.merchant.airxpayMerchantId,
      walletId: result.merchant.walletId,
      status: result.merchant.status,
      kycStatus: result.merchant.kycStatus,
      isKycCompleted: result.merchant.isKycCompleted,
      isBankDetailsCompleted: result.merchant.isBankDetailsCompleted,
      mode: result.merchant.mode,
      token: result.token,
    });
  } catch (error: any) {
    console.error("❌ [CREATE SELLER] Error:", error);

    return res.status(error.statusCode || 500).json({
      success: false,
      message: error.message || "Failed to create merchant",
      error: error.data || null,
    });
  }
};
```

## 🔍 Controller Explanation (Step by Step)

Let me break down what's happening in the controller:

### 1. **Environment Variables Setup**
```typescript
const AIRXPAY_SECRET_KEY = process.env.AIRXPAY_SECRET_KEY || "";
const AIRXPAY_CLIENT_KEY = process.env.AIRXPAY_CLIENT_KEY || "";
```
- `AIRXPAY_SECRET_KEY`: Your secret key for authentication (never exposed to frontend)
- `AIRXPAY_CLIENT_KEY`: Your client key for identification
- Both keys are loaded from `.env` file for security

### 2. **Request Validation**
```typescript
if (!seller?.merchantName || !seller?.merchantEmail) {
  return res.status(400).json({ success: false, message: "..." });
}
if (!publicKey) {
  return res.status(400).json({ success: false, message: "..." });
}
```
- Validates that frontend sent required fields
- Checks for `merchantName`, `merchantEmail`, and `publicKey`
- Returns 400 error if any required field is missing

### 3. **Data Preparation**
```typescript
const merchantData = {
  merchantName: seller.merchantName,
  merchantEmail: seller.merchantEmail,
  merchantPhone: seller.merchantPhone,
  businessName: seller.businessName,
  businessType: seller.businessType || "individual", // Default value
  country: seller.country || "India", // Default value
  nationality: seller.nationality || "Indian", // Default value
  mode: seller.mode || "test", // Default to test mode
  kycDetails: seller.kycDetails, // Optional KYC documents
  bankDetails: seller.bankDetails, // Optional bank details
  publicKey, // Frontend public key
};
```
- Maps frontend data to SDK expected format
- Sets default values for optional fields
- Includes KYC and bank details if provided

### 4. **SDK Call**
```typescript
const result = await AirXPay.flixora.createMerchant(publicKey, {
  ...merchantData,
  clientKey: AIRXPAY_CLIENT_KEY,
  secretKey: AIRXPAY_SECRET_KEY,
});
```
- Calls the SDK's `createMerchant` method
- Passes frontend public key and merchant data
- Adds backend keys (`clientKey`, `secretKey`) for authentication
- SDK internally calls company backend API

### 5. **Response Handling**
```typescript
return res.status(200).json({
  success: true,
  message: "Merchant created successfully",
  merchantId: result.merchant.merchantId,
  airxpayMerchantId: result.merchant.airxpayMerchantId,
  walletId: result.merchant.walletId,
  status: result.merchant.status,
  kycStatus: result.merchant.kycStatus,
  isKycCompleted: result.merchant.isKycCompleted,
  isBankDetailsCompleted: result.merchant.isBankDetailsCompleted,
  mode: result.merchant.mode,
  token: result.token,
});
```
- Returns success response to frontend
- Includes all important merchant data:
  - `merchantId`: Your internal merchant ID
  - `airxpayMerchantId`: AirXPay's system ID
  - `walletId`: Merchant's wallet ID
  - `status`: Current merchant status
  - `kycStatus`: KYC verification status
  - `token`: Auth token for future API calls

### 6. **Error Handling**
```typescript
catch (error: any) {
  return res.status(error.statusCode || 500).json({
    success: false,
    message: error.message || "Failed to create merchant",
    error: error.data || null,
  });
}
```
- Catches any errors from SDK or backend
- Returns appropriate HTTP status code
- Sends error details to frontend

## 🎯 Alternative Usage Patterns

### **Pattern 1: Minimal Implementation**
```typescript
// If you only need basic merchant creation
export const quickCreateSeller = async (req: Request, res: Response) => {
  try {
    const { email, name, publicKey } = req.body;
    
    const result = await AirXPay.flixora.createMerchant(publicKey, {
      merchantName: name,
      merchantEmail: email,
      clientKey: process.env.AIRXPAY_CLIENT_KEY!,
      secretKey: process.env.AIRXPAY_SECRET_KEY!,
    });

    res.json({ success: true, token: result.token });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
};
```

### **Pattern 2: With KYC Documents**
```typescript
// When frontend sends KYC documents
export const createSellerWithKYC = async (req: Request, res: Response) => {
  try {
    const { seller, publicKey, kycDocs } = req.body;
    
    const result = await AirXPay.flixora.createMerchant(publicKey, {
      merchantName: seller.name,
      merchantEmail: seller.email,
      merchantPhone: seller.phone,
      kycDetails: {
        panCardUrl: kycDocs.panCard,
        aadhaarUrl: kycDocs.aadhaar,
        selfieUrl: kycDocs.selfie,
      },
      clientKey: process.env.AIRXPAY_CLIENT_KEY!,
      secretKey: process.env.AIRXPAY_SECRET_KEY!,
    });

    res.json({ success: true, data: result });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
};
```

### **Pattern 3: With Bank Details**
```typescript
// When frontend provides bank information
export const createSellerWithBank = async (req: Request, res: Response) => {
  try {
    const { seller, publicKey, bank } = req.body;
    
    const result = await AirXPay.flixora.createMerchant(publicKey, {
      merchantName: seller.name,
      merchantEmail: seller.email,
      bankDetails: {
        accountHolderName: bank.holderName,
        accountNumber: bank.accountNumber,
        ifscCode: bank.ifsc,
        upiId: bank.upi,
      },
      clientKey: process.env.AIRXPAY_CLIENT_KEY!,
      secretKey: process.env.AIRXPAY_SECRET_KEY!,
    });

    res.json({ success: true, data: result });
  } catch (error) {
    res.status(500).json({ success: false, error: error.message });
  }
};
```

### **Pattern 4: NestJS Controller**
```typescript
// sellers.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { AirXPay } from '@flixora/airxpay';

@Controller('sellers')
export class SellersController {
  @Post('create')
  async createSeller(@Body() body: any) {
    try {
      const { seller, publicKey } = body;
      
      const result = await AirXPay.flixora.createMerchant(publicKey, {
        merchantName: seller.name,
        merchantEmail: seller.email,
        clientKey: process.env.AIRXPAY_CLIENT_KEY!,
        secretKey: process.env.AIRXPAY_SECRET_KEY!,
      });

      return { success: true, data: result };
    } catch (error) {
      throw new Error(`Failed to create seller: ${error.message}`);
    }
  }
}
```

### **Pattern 5: Koa.js Middleware**
```typescript
// middleware/airxpay.ts
import { Context, Next } from 'koa';
import { AirXPay } from '@flixora/airxpay';

export const createSellerMiddleware = async (ctx: Context, next: Next) => {
  try {
    const { seller, publicKey } = ctx.request.body;
    
    const result = await AirXPay.flixora.createMerchant(publicKey, {
      merchantName: seller.name,
      merchantEmail: seller.email,
      clientKey: process.env.AIRXPAY_CLIENT_KEY!,
      secretKey: process.env.AIRXPAY_SECRET_KEY!,
    });

    ctx.body = { success: true, data: result };
  } catch (error) {
    ctx.status = 500;
    ctx.body = { success: false, error: error.message };
  }
};
```

## 📚 API Reference

### `AirXPay.flixora.createMerchant(publicKey, merchantData)`

Creates a new merchant in the AirXPay system.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `publicKey` | `string` | ✅ | Frontend public key for authentication |
| `merchantData` | `MerchantData` | ✅ | Merchant details object |

**MerchantData Object:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantName` | `string` | ✅ | Full name of the merchant |
| `merchantEmail` | `string` | ✅ | Email address |
| `merchantPhone` | `string` | ❌ | Phone number (10-15 digits) |
| `businessName` | `string` | ❌ | Business/Store name |
| `businessType` | `'individual' \| 'company'` | ❌ | Type of business |
| `mode` | `'test' \| 'live'` | ❌ | Environment mode |
| `kycDetails` | `KycDocuments` | ❌ | KYC document URLs/info |
| `bankDetails` | `BankDetails` | ❌ | Bank account details |
| `clientKey` | `string` | ✅ | Your client key from env |
| `secretKey` | `string` | ✅ | Your secret key from env |

**Returns:** `Promise<MerchantResponse>`

### `AirXPay.flixora.getMerchantStatus(token)`

Fetches the current status of a merchant.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `token` | `string` | ✅ | Token received from createMerchant |

**Returns:** `Promise<MerchantData>` - Clean merchant data object

## 🎯 Features

- ✅ **Full TypeScript Support** - Complete type definitions
- 🔐 **Secure** - Automatic token management and refresh
- 📡 **Event Driven** - Subscribe to SDK events
- ⚡ **Performance Monitoring** - Built-in execution time measurement
- 🛡️ **Validation** - Input validation for all operations
- 🔌 **Plugin System** - Extend functionality with custom plugins
- 🚀 **Framework Agnostic** - Works with Express, NestJS, Koa, Fastify

## 📡 Events

Subscribe to SDK events for real-time updates:

```typescript
import { AirXPay } from '@flixora/airxpay';

// Listen for merchant creation
AirXPay.events.on('merchantCreated', (data) => {
  console.log('New merchant created:', data);
});

// Listen for status fetches
AirXPay.events.on('merchantStatusFetched', (data) => {
  console.log('Status fetched:', data);
});
```

## ⚙️ Configuration

The SDK comes with default configuration:

```typescript
{
  baseURL: 'http://172.20.10.12:7000', // API base URL
  autoRefreshToken: true // Auto-refresh auth tokens
}
```

## 🛠️ Advanced Usage

### With Performance Tracking

```typescript
import { measureExecutionTime } from '@flixora/airxpay/performance';

const result = await measureExecutionTime(() => 
  AirXPay.flixora.createMerchant(publicKey, merchantData)
);
// Output: "Execution time: 234 ms"
```

### Custom Validation

```typescript
import { validateMerchantPhone } from '@flixora/airxpay/rules';

if (!validateMerchantPhone('9876543210')) {
  throw new Error('Invalid phone number');
}
```

## 📋 Types

```typescript
import type { 
  MerchantData,
  MerchantResponse,
  KycStatus,
  BankDetails 
} from '@flixora/airxpay';

// Use types in your code
const merchant: MerchantData = {
  merchantName: 'John Doe',
  merchantEmail: 'john@example.com',
  // ...
};
```

## 🔧 Error Handling

```typescript
import { AirXPayError } from '@flixora/airxpay/errors';

try {
  await AirXPay.flixora.createMerchant(publicKey, merchantData);
} catch (error) {
  if (error instanceof AirXPayError) {
    console.error(`SDK Error [${error.code}]:`, error.message);
  } else {
    console.error('Unexpected error:', error);
  }
}
```

## 📝 License

MIT © Flixora

## 🤝 Support

- 📧 Email: support@flixora.com
- 📚 Documentation: [docs.flixora.com](https://docs.flixora.com)
- 🐛 Issues: [GitHub Issues](https://github.com/tafseelkhan/airxpay-sdk-init-server/issues)

## 🚦 Status

![Last Commit](https://github.com/tafseelkhan/airxpay-sdk-init-server)

---

**Made with ❤️ by Flixora Team**