Catalog npm
Back to packageRELEASE DETAILS

1.0.2

npm

9japay-nestjs

A comprehensive NestJS SDK for integrating with 9jaPay Virtual Account APIs

9japayapinestjspaymentssdkvirtual-accounts
Published6 Sept 2025
Direct dependencies14
Transitive dependenciesNot calculated

README

Current package documentation

9jaPay NestJS SDK

A comprehensive NestJS SDK for integrating with 9jaPay Virtual Account APIs. This SDK provides a type-safe, easy-to-use interface for all 9jaPay API endpoints including virtual account management, transfers, and transaction handling.

Features

  • 🚀 Full API Coverage: Complete implementation of all 9jaPay API endpoints
  • 🛡️ Type Safety: Full TypeScript support with comprehensive type definitions
  • 🏗️ NestJS Integration: Native NestJS module with dependency injection support
  • 🌍 Multi-Environment: Support for both sandbox and production environments
  • 📚 Well Documented: Comprehensive documentation and examples
  • ✅ Tested: Unit tests included
  • 🔧 Configurable: Flexible configuration options

Installation

npm install 9japay-nestjs
# or
yarn add 9japay-nestjs

Quick Start

1. Module Registration

import { Module } from '@nestjs/common';
import { NineJaPayModule } from '9japay-nestjs';

@Module({
  imports: [
    NineJaPayModule.register({
      apiKey: 'your-api-key',
      secretKey: 'your-secret-key',
      environment: 'sandbox', // or 'production'
    }),
  ],
})
export class AppModule {}

2. Async Configuration

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { NineJaPayModule } from '9japay-nestjs';

@Module({
  imports: [
    ConfigModule.forRoot(),
    NineJaPayModule.registerAsync({
      useFactory: (configService: ConfigService) => ({
        apiKey: configService.get('NINE_JA_PAY_API_KEY'),
        secretKey: configService.get('NINE_JA_PAY_SECRET_KEY'),
        environment: configService.get('NINE_JA_PAY_ENVIRONMENT'),
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

3. Using the Service

import { Injectable } from '@nestjs/common';
import { NineJaPayService } from '9japay-nestjs';

@Injectable()
export class PaymentService {
  constructor(private readonly nineJaPayService: NineJaPayService) {}

  async createVirtualAccount(accountName: string) {
    const response = await this.nineJaPayService.createPermanentVirtualAccount({
      requestReference: `ref-${Date.now()}`,
      accountName,
      autoPayoutEnabled: true,
    });

    return response;
  }

  async makeTransfer(transferData: any) {
    // First, validate the recipient account
    const nameEnquiry = await this.nineJaPayService.nameEnquiry({
      bankCode: transferData.bankCode,
      accountNumber: transferData.accountNumber,
    });

    if (nameEnquiry.status === 'SUCCESS') {
      // Proceed with transfer
      const transfer = await this.nineJaPayService.transfer({
        paymentReference: `pay-${Date.now()}`,
        senderAccountNumber: transferData.senderAccountNumber,
        senderAccountName: transferData.senderAccountName,
        recipientAccountNumber: transferData.accountNumber,
        recipientAccountName: nameEnquiry.data.accountName,
        recipientBankCode: transferData.bankCode,
        amount: transferData.amount.toString(),
        nameEnquiryReference: nameEnquiry.data.nameEnquiryReference,
        narration: transferData.narration,
      });

      return transfer;
    }
  }
}

API Reference

Virtual Account Management

Permanent Virtual Accounts

// Create permanent virtual account
await nineJaPayService.createPermanentVirtualAccount({
  requestReference: 'unique-ref-123',
  accountName: 'John Doe Account',
  autoPayoutEnabled: true,
});

// Update permanent virtual account
await nineJaPayService.updatePermanentVirtualAccount('9000001234', {
  accountName: 'Updated Account Name',
  blockStatus: false,
  autoPayoutEnabled: false,
});

// Get single permanent virtual account
await nineJaPayService.getPermanentVirtualAccount('9000001234');

// Get all permanent virtual accounts
await nineJaPayService.getAllPermanentVirtualAccounts({
  pageSize: 10,
  pageNumber: 1,
});

// Close permanent virtual account
await nineJaPayService.closePermanentVirtualAccount({
  requestReference: 'close-ref-123',
  accountNumber: '9000001234',
  reasonForClosure: 'Account no longer needed',
});

Transient Virtual Accounts

// Create transient virtual account
await nineJaPayService.createTransientVirtualAccount({
  requestReference: 'temp-ref-123',
  timeToLive: '3600', // 1 hour in seconds
  amount: 100000, // Amount in kobo (optional)
  isSinglePayment: true,
});

// Update transient virtual account
await nineJaPayService.updateTransientVirtualAccount('9000001234', {
  blockStatus: false,
});

// Get single transient virtual account
await nineJaPayService.getTransientVirtualAccount('9000001234');

// Get all transient virtual accounts
await nineJaPayService.getAllTransientVirtualAccounts({
  pageSize: 10,
  pageNumber: 1,
});

General Virtual Account Operations

// Get all virtual accounts (both permanent and transient)
await nineJaPayService.getAllVirtualAccounts({
  pageSize: 20,
  pageNumber: 1,
});

// Get single virtual account (regardless of type)
await nineJaPayService.getVirtualAccount('9000001234');

// Get account balance
await nineJaPayService.getAccountBalance('9000001234');

// Get total balance summary
await nineJaPayService.getTotalBalanceSummary();

Transfers

// Get list of banks
const banks = await nineJaPayService.getBankList();

// Perform name enquiry
const nameEnquiry = await nineJaPayService.nameEnquiry({
  bankCode: '057',
  accountNumber: '1234567890',
});

// Transfer from regular account
await nineJaPayService.transfer({
  paymentReference: 'pay-ref-123',
  senderAccountNumber: '3000001234',
  senderAccountName: 'Sender Name',
  recipientAccountNumber: '1234567890',
  recipientAccountName: 'Recipient Name',
  recipientBankCode: '057',
  amount: '100000', // Amount in kobo
  nameEnquiryReference: nameEnquiry.data.nameEnquiryReference,
  narration: 'Payment for services',
});

// Transfer from virtual account
await nineJaPayService.transferFromVirtualAccount({
  // Same parameters as above
});

// Check transaction status
await nineJaPayService.getTransactionStatus('pay-ref-123');

Transactions

// Get transactions with filters
await nineJaPayService.getTransactions({
  pageSize: 10,
  pageNumber: 1,
  accountNumber: '9000001234', // optional
  startDate: '2024-01-01', // optional
  endDate: '2024-12-31', // optional
});

// Get single transaction by ID
await nineJaPayService.getTransactionById('transaction-id-123');

// Resend failed notification for a transaction
await nineJaPayService.resendNotification({
  transactionId: 'transaction-id-123',
});

// Resend all failed notifications for an account
await nineJaPayService.resendNotificationsForAccount({
  accountNumber: '9000001234',
});

// Resend all failed notifications
await nineJaPayService.resendAllNotifications();

// Simulate deposit (sandbox only)
await nineJaPayService.simulateDeposit({
  recipientAccountNumber: '9000001234',
  amount: '100000',
  authKey: 'test-auth-key',
});

Configuration Options

interface _9JaPayConfig {
  apiKey: string;           // Your 9jaPay API key
  secretKey: string;        // Your 9jaPay secret key
  environment: 'sandbox' | 'production'; // Environment
  baseUrl?: string;         // Optional custom base URL
  rejectUnauthorized?: boolean; // Optional: Set to false for local testing to ignore SSL cert errors (default: true)
}

Local Testing Configuration

For local testing environments where you might encounter SSL certificate issues, you can disable SSL verification:

NineJaPayModule.register({
  apiKey: 'your-api-key',
  secretKey: 'your-secret-key',
  environment: 'sandbox',
  rejectUnauthorized: false, // Disable SSL verification for local testing
})

⚠️ Security Warning: Only use rejectUnauthorized: false in development/testing environments. Never use this in production!

Environment URLs

  • Sandbox: https://test.developer.9japay.com/v1/api
  • Production: https://developer.9japay.com/v1/api

Error Handling

The SDK provides comprehensive error handling with two types of exceptions:

For 9jaPay API errors, the SDK throws NineJaPayException which properly maps 9jaPay status codes to HTTP status codes:

import { NineJaPayException } from '9japay-nestjs';

try {
  const result = await nineJaPayService.createPermanentVirtualAccount({
    requestReference: 'duplicate-ref',
    accountName: 'Test Account',
    autoPayoutEnabled: true,
  });
} catch (error) {
  if (error instanceof NineJaPayException) {
    console.log('9jaPay Status Code:', error.nineJaPayStatusCode); // "26"
    console.log('HTTP Status Code:', error.getStatus()); // 409
    console.log('Message:', error.message); // "Duplicate record found."
    console.log('Full Response:', error.nineJaPayResponse);
    
    // Handle specific 9jaPay errors
    switch (error.nineJaPayStatusCode) {
      case '26':
        // Handle duplicate record
        console.log('Duplicate record detected');
        break;
      case '25':
        // Handle no record found
        console.log('Record not found');
        break;
      case '09':
        // Handle validation error
        console.log('Validation failed');
        break;
      default:
        console.log('Other 9jaPay error');
    }
  }
}

2. Standard _9JaPayError

For network errors or other issues:

try {
  const result = await nineJaPayService.createPermanentVirtualAccount({
    requestReference: 'ref-123',
    accountName: 'Test Account',
    autoPayoutEnabled: true,
  });
} catch (error) {
  console.error('Error:', error.message);
  console.error('9jaPay Status Code:', error.nineJaPayStatusCode);
  console.error('HTTP Status Code:', error.httpStatusCode);
  console.error('Response:', error.response);
}

Error Response Structure

When using NineJaPayException, the error response structure is:

{
  statusCode: 409,              // HTTP status code (for proper REST API responses)
  message: "Duplicate record found.",
  nineJaPayStatusCode: "26",    // 9jaPay's business logic status code
  nineJaPayResponse: {          // Full 9jaPay response
    status: "FAILED",
    message: "Duplicate record found.",
    statusCode: "26"
  }
}

Response Codes

The SDK maps 9jaPay status codes to appropriate HTTP status codes:

9jaPay CodeDescriptionHTTP StatusHTTP Code
00SuccessOK200
01ProcessingAccepted202
06General errorInternal Server Error500
09Validation errorBad Request400
25No record foundNot Found404
26Duplicate recordConflict409

Status Code Usage

  • 9jaPay Code: Used for business logic and specific error handling
  • HTTP Status: Used for REST API responses and proper HTTP semantics
  • Both codes are available in the NineJaPayException for comprehensive error handling

Development

Building the Package

npm run build

Running Tests

npm test
npm run test:watch
npm run test:coverage

Linting

npm run lint
npm run lint:fix

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Run the test suite
  6. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For support and questions:

Changelog

v1.0.2

  • Enhanced Error Handling: Added NineJaPayException class with proper HTTP status code mapping
  • Fixed Status Code Conflict: Separated 9jaPay status codes from HTTP status codes to prevent ERR_HTTP_INVALID_STATUS_CODE
  • Improved Error Structure: Better error response format with both business logic and HTTP codes
  • Status Code Mapping: Automatic mapping of 9jaPay codes (e.g., "26") to appropriate HTTP codes (e.g., 409)

v1.0.1

  • Global Module: Made module global to resolve dependency injection issues
  • Fix: Service now available throughout application without additional imports

v1.0.0

  • Initial release
  • Complete API coverage
  • TypeScript support
  • NestJS integration
  • Unit tests
  • Comprehensive documentation

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 17

Native requirements
14 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
axios
Environment
{
  "local_name": "axios",
  "alias": false,
  "peer_metadata": null
}
^1.6.0runtime
jest
Environment
{
  "local_name": "jest",
  "alias": false,
  "peer_metadata": null
}
^29.0.0development
rxjs
Environment
{
  "local_name": "rxjs",
  "alias": false,
  "peer_metadata": null
}
^7.0.0development
eslint
Environment
{
  "local_name": "eslint",
  "alias": false,
  "peer_metadata": null
}
^8.0.0development
ts-jest
Environment
{
  "local_name": "ts-jest",
  "alias": false,
  "peer_metadata": null
}
^29.0.0development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^5.0.0development
@types/jest
Environment
{
  "local_name": "@types/jest",
  "alias": false,
  "peer_metadata": null
}
^29.0.0development
@types/node
Environment
{
  "local_name": "@types/node",
  "alias": false,
  "peer_metadata": null
}
^20.0.0development
@nestjs/core
Environment
{
  "local_name": "@nestjs/core",
  "alias": false,
  "peer_metadata": null
}
^10.0.0development
@nestjs/common
Environment
{
  "local_name": "@nestjs/common",
  "alias": false,
  "peer_metadata": null
}
^10.0.0development
@nestjs/testing
Environment
{
  "local_name": "@nestjs/testing",
  "alias": false,
  "peer_metadata": null
}
^10.0.0development
reflect-metadata
Environment
{
  "local_name": "reflect-metadata",
  "alias": false,
  "peer_metadata": null
}
^0.1.13development
@typescript-eslint/parser
Environment
{
  "local_name": "@typescript-eslint/parser",
  "alias": false,
  "peer_metadata": null
}
^6.0.0development
@typescript-eslint/eslint-plugin
Environment
{
  "local_name": "@typescript-eslint/eslint-plugin",
  "alias": false,
  "peer_metadata": null
}
^6.0.0development
rxjs
Environment
{
  "local_name": "rxjs",
  "alias": false,
  "peer_metadata": null
}
^7.0.0peer
@nestjs/core
Environment
{
  "local_name": "@nestjs/core",
  "alias": false,
  "peer_metadata": null
}
^10.0.0peer
@nestjs/common
Environment
{
  "local_name": "@nestjs/common",
  "alias": false,
  "peer_metadata": null
}
^10.0.0peer

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "0f7fba4023a584fab2cb4a711df28ba94d1ec2e8",
  "tarball": "https://registry.npmjs.org/9japay-nestjs/-/9japay-nestjs-1.0.2.tgz",
  "fileCount": 26,
  "integrity": "sha512-BwHe/C2n8D90LNsNzQK6WXv5O30Q5vRhOYkVkAhU1hI3+Z9Tws5FQYZkMV8vp0v1HwJn3tZPssp9NWKtasi7pA==",
  "signatures": [
    {
      "sig": "MEQCIDiArk5GPnfTnWBc0/NslgLVe9atn6Ivd/zsQqgS+D+SAiBsxDnGOpUsGU9HXXdAYfb5bJtAoJlWj3SALBeN/t0HzA==",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 66749
}

Repository

PENDING
evidenze/9japay-nestjs

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:38 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:73aab1f8a6c680164c67f9fabf1afefdc4078bd7cee6039b5e00a6d2b31e2577

Other collected versions

1.1.026 Nov1.0.526 Nov1.0.46 Sept1.0.36 Sept1.0.16 Sept1.0.06 SeptView all collected versions →