> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js SDK Integration

> Quick setup guide for Navio Node.js/TypeScript SDK

## Overview

The Navio Node.js SDK provides a modern, type-safe interface for integrating Navio payments into your Node.js and TypeScript applications. Built with TypeScript and async/await for the best developer experience.

<CardGroup cols={2}>
  <Card title="TypeScript Native" icon="shield-check" color="#0D9373">
    Full TypeScript support with complete type definitions
  </Card>

  <Card title="Promise-based" icon="clock" color="#0D9373">
    Native Promise support with async/await
  </Card>

  <Card title="Simple API" icon="code" color="#0D9373">
    Clean, intuitive interface
  </Card>

  <Card title="Error Handling" icon="circle-exclamation" color="#0D9373">
    Custom exceptions for different error types
  </Card>
</CardGroup>

## Requirements

* Node.js 16.0.0 or higher
* npm, yarn, or pnpm

## Installation

Install via npm:

```bash theme={null}
npm install @oneclickdz/ocpay-sdk
```

Or with yarn:

```bash theme={null}
yarn add @oneclickdz/ocpay-sdk
```

Or with pnpm:

```bash theme={null}
pnpm add @oneclickdz/ocpay-sdk
```

## Quick Start

### 1. Initialize SDK

```typescript theme={null}
import { OCPay } from '@oneclickdz/ocpay-sdk';

// Initialize with your API access token
const ocpay = new OCPay('your-api-access-token');
```

<Warning>
  Store your API key in environment variables, never in code
</Warning>

```bash theme={null}
# .env file
ONECLICK_API_KEY=your_api_key_here
```

```typescript theme={null}
// Load from environment
const ocpay = new OCPay(process.env.ONECLICK_API_KEY);
```

### 2. Create Payment Link

```typescript theme={null}
import { OCPay, FeeMode } from '@oneclickdz/ocpay-sdk';

const ocpay = new OCPay(process.env.ONECLICK_API_KEY);

// Create payment link request
const request = {
  productInfo: {
    title: 'Premium Subscription',
    amount: 5000, // Amount in DZD (500 - 500,000)
    description: 'Monthly access to premium features',
  },
  feeMode: FeeMode.NO_FEE, // Merchant pays fees
  successMessage: 'Thank you for your purchase!',
  redirectUrl: 'https://yourstore.com/success?orderId=12345',
};

// Create the payment link
try {
  const response = await ocpay.createLink(request);
  
  // Redirect customer to payment page
  console.log('Payment URL:', response.paymentUrl);
  
  // IMPORTANT: Save this reference!
  console.log('Payment Reference:', response.paymentRef);
  // await saveOrderPaymentRef(orderId, response.paymentRef);
  
} catch (error) {
  if (error instanceof ValidationException) {
    console.error('Validation error:', error.message);
  } else if (error instanceof UnauthorizedException) {
    console.error('Auth error:', error.message);
  } else if (error instanceof ApiException) {
    console.error('API error:', error.message);
  }
}
```

### 3. Check Payment Status

```typescript theme={null}
import { PaymentStatus } from '@oneclickdz/ocpay-sdk';

// Check payment status using the payment reference
try {
  const status = await ocpay.checkPayment('OCPL-A1B2C3-D4E5');
  
  if (status.status === PaymentStatus.CONFIRMED) {
    // Payment successful - fulfill the order
    console.log('Payment confirmed!');
    console.log('Amount:', status.transactionDetails?.amount, 'DZD');
    await fulfillOrder(orderId);
    
  } else if (status.status === PaymentStatus.FAILED) {
    // Payment failed or expired
    console.log('Payment failed:', status.message);
    await markOrderFailed(orderId);
    
  } else {
    // Still pending - check again later
    console.log('Payment pending...');
    await schedulePolling(orderId);
  }
  
} catch (error) {
  if (error instanceof NotFoundException) {
    console.error('Payment not found');
  } else if (error instanceof PaymentExpiredException) {
    console.error('Payment link expired');
  } else if (error instanceof ApiException) {
    console.error('API error:', error.message);
  }
}
```

## Complete E-commerce Example

Here's a complete flow for an e-commerce checkout:

```typescript theme={null}
import {
  OCPay,
  FeeMode,
  PaymentStatus,
  ValidationException,
  ApiException,
} from '@oneclickdz/ocpay-sdk';

// Initialize SDK
const ocpay = new OCPay(process.env.ONECLICK_API_KEY!);

// Step 1: Create order in your system
const orderId = await createOrder({
  customerId: 123,
  items: [
    { name: 'Product A', price: 5000 },
    { name: 'Product B', price: 3000 },
  ],
  total: 8000,
});

// Step 2: Create payment link
try {
  const response = await ocpay.createLink({
    productInfo: {
      title: `Order #${orderId}`,
      amount: 8000,
      description: `Payment for order #${orderId}`,
    },
    feeMode: FeeMode.NO_FEE,
    successMessage: `Thank you! Your order #${orderId} is being processed.`,
    redirectUrl: `https://yourstore.com/orders/${orderId}/success`,
  });

  // Step 3: Save payment reference to order
  await updateOrder(orderId, {
    paymentRef: response.paymentRef,
    paymentUrl: response.paymentUrl,
    status: 'pending_payment',
  });

  // Step 4: Redirect customer to payment page
  // res.redirect(response.paymentUrl);
  console.log('Redirect to:', response.paymentUrl);
  
} catch (error) {
  console.error('Payment link creation failed:', error.message);
  // showErrorPage('Failed to create payment link. Please try again.');
}

// Step 5: Poll payment status (in background job)
async function checkOrderPayment(orderId: string): Promise<void> {
  const order = await getOrder(orderId);

  if (!order || !order.paymentRef) {
    return;
  }

  try {
    const status = await ocpay.checkPayment(order.paymentRef);

    if (status.status === PaymentStatus.CONFIRMED) {
      // Mark order as paid and fulfill
      await updateOrder(orderId, {
        status: 'paid',
        paidAt: new Date(),
      });
      await fulfillOrder(orderId);
      
    } else if (status.status === PaymentStatus.FAILED) {
      // Mark order as failed
      await updateOrder(orderId, {
        status: 'payment_failed',
      });
    }
    // If pending, do nothing and check again later
    
  } catch (error) {
    console.error('Payment status check failed:', error.message);
  }
}
```

## Framework Integration

### Express.js

```typescript theme={null}
import express from 'express';
import { OCPay, FeeMode, PaymentStatus } from '@oneclickdz/ocpay-sdk';

const app = express();
const ocpay = new OCPay(process.env.ONECLICK_API_KEY!);

app.use(express.json());

// Create payment endpoint
app.post('/api/orders/:orderId/payment', async (req, res) => {
  const { orderId } = req.params;
  const order = await getOrder(orderId);

  try {
    const response = await ocpay.createLink({
      productInfo: {
        title: `Order #${orderId}`,
        amount: order.total,
      },
      feeMode: FeeMode.NO_FEE,
      redirectUrl: `${req.protocol}://${req.get('host')}/orders/${orderId}/success`,
    });

    await updateOrder(orderId, { paymentRef: response.paymentRef });
    res.json({ paymentUrl: response.paymentUrl });
    
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Check payment status endpoint
app.get('/api/payments/:paymentRef/status', async (req, res) => {
  try {
    const status = await ocpay.checkPayment(req.params.paymentRef);
    res.json(status);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});
```

### NestJS

```typescript theme={null}
import { Injectable } from '@nestjs/common';
import { OCPay, CreateLinkRequest, FeeMode } from '@oneclickdz/ocpay-sdk';

@Injectable()
export class PaymentService {
  private readonly ocpay: OCPay;

  constructor() {
    this.ocpay = new OCPay(process.env.ONECLICK_API_KEY!);
  }

  async createPaymentLink(orderId: string, amount: number): Promise<string> {
    const response = await this.ocpay.createLink({
      productInfo: {
        title: `Order #${orderId}`,
        amount,
      },
      feeMode: FeeMode.NO_FEE,
      redirectUrl: `https://yourstore.com/orders/${orderId}/success`,
    });

    return response.paymentUrl;
  }

  async checkPaymentStatus(paymentRef: string) {
    return await this.ocpay.checkPayment(paymentRef);
  }
}
```

### Next.js (App Router)

```typescript theme={null}
// app/api/orders/[orderId]/payment/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { OCPay, FeeMode } from '@oneclickdz/ocpay-sdk';

const ocpay = new OCPay(process.env.ONECLICK_API_KEY!);

export async function POST(
  request: NextRequest,
  { params }: { params: { orderId: string } }
) {
  try {
    const order = await getOrder(params.orderId);
    
    const response = await ocpay.createLink({
      productInfo: {
        title: `Order #${params.orderId}`,
        amount: order.total,
      },
      feeMode: FeeMode.NO_FEE,
      redirectUrl: `${process.env.NEXT_PUBLIC_URL}/orders/${params.orderId}/success`,
    });

    await updateOrder(params.orderId, { paymentRef: response.paymentRef });
    
    return NextResponse.json({ paymentUrl: response.paymentUrl });
  } catch (error) {
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
```

## API Reference

### OCPay Class

Main SDK entry point.

#### Constructor

```typescript theme={null}
constructor(accessToken: string, options?: ClientOptions)
```

**Parameters:**

* `accessToken` (string) - Your API access token
* `options` (ClientOptions) - Optional client configuration:
  * `timeout` (number) - Request timeout in milliseconds (default: 30000)
  * `baseURL` (string) - Custom base URL (mainly for testing)
  * `headers` (object) - Additional headers

**Example:**

```typescript theme={null}
const ocpay = new OCPay('your-api-key', {
  timeout: 60000, // 60 seconds
});
```

#### Methods

`createLink(request: CreateLinkRequest): Promise<CreateLinkResponse>`

Creates a payment link.

`checkPayment(paymentRef: string): Promise<CheckPaymentResponse>`

Checks payment status.

### Types & Interfaces

#### ProductInfo

```typescript theme={null}
interface ProductInfo {
  title: string;        // Product name (1-200 chars)
  amount: number;       // Amount in DZD (500 - 500,000)
  description?: string; // Optional (max 1000 chars)
}
```

#### CreateLinkRequest

```typescript theme={null}
interface CreateLinkRequest {
  productInfo: ProductInfo;
  feeMode?: FeeMode;        // NO_FEE (default), SPLIT_FEE, CUSTOMER_FEE
  successMessage?: string;  // Optional success message
  redirectUrl?: string;     // Optional redirect URL
}
```

**FeeMode Enum:**

```typescript theme={null}
enum FeeMode {
  NO_FEE = 'NO_FEE',           // Merchant pays (default)
  SPLIT_FEE = 'SPLIT_FEE',     // 50/50 split
  CUSTOMER_FEE = 'CUSTOMER_FEE' // Customer pays
}
```

#### CreateLinkResponse

```typescript theme={null}
interface CreateLinkResponse {
  paymentLink: PaymentLink;  // Full payment link details
  paymentUrl: string;        // URL to redirect customer
  paymentRef: string;        // Payment reference (SAVE THIS!)
}
```

#### CheckPaymentResponse

```typescript theme={null}
interface CheckPaymentResponse {
  status: PaymentStatus;            // Payment status enum
  message: string;                  // Status message
  paymentRef: string;               // Payment reference
  transactionDetails?: TransactionDetails; // Details (if available)
}
```

**PaymentStatus Enum:**

```typescript theme={null}
enum PaymentStatus {
  PENDING = 'PENDING',     // Payment in progress
  CONFIRMED = 'CONFIRMED', // Payment successful
  FAILED = 'FAILED',       // Payment declined/expired
}
```

### Exception Handling

All exceptions extend `OCPayException`:

| Exception                 | HTTP Code | When Thrown            |
| ------------------------- | --------- | ---------------------- |
| `ValidationException`     | 400       | Invalid request data   |
| `UnauthorizedException`   | 403       | Invalid API key        |
| `NotFoundException`       | 404       | Payment not found      |
| `PaymentExpiredException` | 410       | Link expired (>20 min) |
| `ApiException`            | Various   | Other API errors       |

All exceptions provide:

```typescript theme={null}
try {
  const response = await ocpay.createLink(request);
} catch (error) {
  if (error instanceof ApiException) {
    console.log(error.message);         // Error message
    console.log(error.getStatusCode()); // HTTP status code
    console.log(error.getRequestId());  // Request ID for support
    console.log(error.getErrorData());  // Full error data
  }
}
```

## Important Notes

### Merchant Validation Required

<Warning>
  Complete merchant validation at [app.oneclickdz.com](https://app.oneclickdz.com/profile) before using the API
</Warning>

### Amount Limits

* **Minimum**: 500 DZD
* **Maximum**: 500,000 DZD
* Must be whole numbers (integers)

### Fee Structure

<Info>
  **Low Fees**: 0% on balance, only 1% withdrawal fee
</Info>

### Payment Link Expiration

Links expire **20 minutes** after creation if payment not initiated.

### Payment Status Flow

1. **PENDING** - Payment in progress → Poll again later
2. **CONFIRMED** - Payment successful → Fulfill order
3. **FAILED** - Payment declined/expired → Mark order failed

## TypeScript Support

This SDK is written in TypeScript and includes complete type definitions. No need to install `@types` packages!

```typescript theme={null}
import { OCPay, CreateLinkRequest, PaymentStatus } from '@oneclickdz/ocpay-sdk';

// Full IntelliSense and type checking
const request: CreateLinkRequest = {
  productInfo: {
    title: 'Product',
    amount: 5000,
  },
};
```

## JavaScript Usage

The SDK works perfectly with plain JavaScript too:

```javascript theme={null}
const { OCPay, FeeMode } = require('@oneclickdz/ocpay-sdk');

const ocpay = new OCPay(process.env.ONECLICK_API_KEY);

async function createPayment() {
  const response = await ocpay.createLink({
    productInfo: {
      title: 'Premium Subscription',
      amount: 5000,
    },
    feeMode: FeeMode.NO_FEE,
  });
  
  console.log('Payment URL:', response.paymentUrl);
}
```

## Testing

### Using Sandbox

The API automatically uses sandbox mode for test accounts:

```typescript theme={null}
const response = await ocpay.createLink(request);

if (response.paymentLink.isSandbox) {
  console.log('This is a test payment');
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Always Save Payment Reference" icon="database">
    Store `paymentRef` immediately after creating the link. You need it to check payment status.
  </Accordion>

  <Accordion title="Poll Payment Status" icon="clock">
    Set up a background job to check payment status every 20 minutes for pending orders.
  </Accordion>

  <Accordion title="Handle All Exceptions" icon="shield-halved">
    Catch and handle all exception types appropriately. Log errors for debugging.
  </Accordion>

  <Accordion title="Secure Your API Key" icon="key">
    Store API keys in environment variables, never commit them to version control.
  </Accordion>

  <Accordion title="Use HTTPS Only" icon="lock">
    Always use HTTPS for redirect URLs and your application endpoints.
  </Accordion>
</AccordionGroup>

## Support & Resources

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/oneclickdz/ocpay-nodejs-sdk">
    Source code, examples, and issues
  </Card>

  <Card title="API Documentation" icon="book" href="/en/api-reference/ocpay/create-link">
    Detailed API reference
  </Card>

  <Card title="npm Package" icon="npm" href="https://www.npmjs.com/package/@oneclickdz/ocpay-sdk">
    View on npm registry
  </Card>

  <Card title="Contact Support" icon="headset" href="/en/contact">
    Get help from our team
  </Card>
</CardGroup>

## Next Steps

<Card title="Navio Best Practices" icon="star" href="/en/ocpay-guides/4-best-practices">
  Learn production-ready tips and security best practices
</Card>
