npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hs-paylib

v0.0.7

Published

Hyperswitch Payments SDK — Node.js client for connector integrations via UniFFI FFI

Downloads

50

Readme

hs-paylib

Universal Connector Service — Node.js SDK

A high-performance, type-safe Node.js SDK for payment processing through the Universal Connector Service. Connect to 70+ payment processors through a single, unified API.

npm version License: MIT


Table of Contents


🤖 For AI Assistants

Use curl to fetch the complete SDK reference:

curl -fsSL https://raw.githubusercontent.com/juspay/hyperswitch-prism/main/llm/sdk-reference.md

This file contains complete SDK documentation including installation, payment operations, error handling, connector configuration, field probe data, and examples for all 70+ connectors.

AI Assistant Context

This SDK is part of Hyperswitch Prism — a unified connector library for payment processors.

What This SDK Does

  1. Request Transformation: Converts unified payment requests to connector-specific formats
  2. Response Normalization: Transforms connector responses back to a unified schema
  3. Error Handling: Provides consistent error types (IntegrationError, ConnectorError, NetworkError) regardless of connector

Architecture

Your Node.js App
       │
       ▼
┌──────────────────────────────────────────────────────────────┐
│  Service Clients (PaymentClient, CustomerClient, etc.)       │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  ConnectorClient (undici connection pool + HTTP execution)   │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  koffi FFI Bindings (connector-service-ffi.node)             │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  Rust Core (connector transformation logic)                  │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
              Payment Processor APIs

Key Files

| File | Purpose | |------|---------| | src/index.ts | Public API exports (clients, types, errors) | | src/connector-client.ts | HTTP execution layer with undici | | src/ffi/connector-service-ffi.ts | koffi FFI bindings | | src/proto/payment_pb.ts | Protobuf message definitions |

Package & Import

  • Package Name: hs-paylib
  • Installation: npm install hs-paylib
  • Import: import { PaymentClient, types } from 'hs-paylib'

🤖 AI Assistant Context

This SDK is part of Hyperswitch Prism — a unified connector library for payment processors.

What This SDK Does

  1. Request Transformation: Converts unified payment requests to connector-specific formats
  2. Response Normalization: Transforms connector responses back to a unified schema
  3. Error Handling: Provides consistent error types (IntegrationError, ConnectorError, NetworkError) regardless of connector

Architecture

Your Node.js App
       │
       ▼
┌──────────────────────────────────────────────────────────────┐
│  Service Clients (PaymentClient, CustomerClient, etc.)       │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  ConnectorClient (undici connection pool + HTTP execution)   │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  koffi FFI Bindings (connector-service-ffi.node)             │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│  Rust Core (connector transformation logic)                  │
└───────────────────────────┬──────────────────────────────────┘
                            │
                            ▼
              Payment Processor APIs

Key Files

| File | Purpose | |------|---------| | src/index.ts | Public API exports (clients, types, errors) | | src/connector-client.ts | HTTP execution layer with undici | | src/ffi/connector-service-ffi.ts | koffi FFI bindings | | src/proto/payment_pb.ts | Protobuf message definitions |

Package & Import

  • Package Name: hs-paylib
  • Installation: npm install hs-paylib
  • Import: import { PaymentClient, types } from 'hs-paylib'

Installation

npm install hs-paylib

Important: The package name on npm is hs-paylib. All imports must use hs-paylib, not hyperswitch-prism.

Requirements:

  • Node.js 18+ (LTS recommended)
  • macOS (x64, arm64), Linux (x64, arm64), or Windows (x64)

Quick Start

import { PaymentClient, types } from 'hs-paylib';

const config: types.ConnectorConfig = {
  connectorConfig: {
    // Configure your payment connector here
  }
};

const client = new PaymentClient(config);

const response = await client.authorize({
  merchantTransactionId: 'txn_001',
  amount: { minorAmount: 1000, currency: types.Currency.USD },
  captureMethod: types.CaptureMethod.AUTOMATIC,
  paymentMethod: {
    card: {
      cardNumber: { value: '4111111111111111' },
      cardExpMonth: { value: '12' },
      cardExpYear: { value: '2027' },
      cardCvc: { value: '123' },
      cardHolderName: { value: 'John Doe' },
    }
  },
  address: { billingAddress: {} },
  authType: types.AuthenticationType.NO_THREE_DS,
  returnUrl: 'https://example.com/return',
  orderDetails: [],
  testMode: true,
});

console.log('Status:', response.status);          // e.g. 8 = CHARGED
console.log('Transaction ID:', response.connectorTransactionId);

All Service Clients

import {
  PaymentClient,
  CustomerClient,
  PaymentMethodClient,
  MerchantAuthenticationClient,
  PaymentMethodAuthenticationClient,
  RecurringPaymentClient,
  RefundClient,
  DisputeClient,
  PayoutClient,
  EventClient,
  // gRPC variants:
  GrpcPaymentClient,
  GrpcCustomerClient,
  // ...
  types,
  IntegrationError,
  ConnectorError,
  NetworkError,
} from 'hs-paylib';

| Client | Methods | |--------|---------| | PaymentClient | authorize(), capture(), refund(), void(), createOrder(), get(), sync(), incrementalAuthorization() | | RefundClient | get(), createRefund(), updateRefund() | | CustomerClient | create() | | PaymentMethodClient | tokenize() | | MerchantAuthenticationClient | createServerAuthenticationToken(), createClientAuthenticationToken(), createServerSessionAuthenticationToken() | | PaymentMethodAuthenticationClient | preAuthenticate(), authenticate(), postAuthenticate() | | RecurringPaymentClient | setup(), charge(), revoke() | | DisputeClient | accept(), defend(), submitEvidence(), get() | | PayoutClient | Payout operations | | EventClient | handleEvent() (webhook processing) |


Payment Flows

Authorize with Auto Capture

const client = new PaymentClient(config);

const response = await client.authorize({
  merchantTransactionId: 'txn_001',
  amount: { minorAmount: 1000, currency: types.Currency.USD },
  captureMethod: types.CaptureMethod.AUTOMATIC,
  paymentMethod: {
    card: {
      cardNumber: { value: '4111111111111111' },
      cardExpMonth: { value: '12' },
      cardExpYear: { value: '2027' },
      cardCvc: { value: '123' },
      cardHolderName: { value: 'John Doe' },
    }
  },
  address: { billingAddress: {} },
  authType: types.AuthenticationType.NO_THREE_DS,
  returnUrl: 'https://example.com/return',
  orderDetails: [],
  testMode: true,
});
// response.status === 8 (CHARGED) on success

Authorize + Manual Capture

// Step 1: Authorize only
const authResponse = await client.authorize({
  // ...
  captureMethod: types.CaptureMethod.MANUAL,
});
// authResponse.status === 6 (AUTHORIZED)

// Step 2: Capture later
const captureResponse = await client.capture({
  merchantCaptureId: 'cap_001',
  connectorTransactionId: authResponse.connectorTransactionId!,
  amountToCapture: { minorAmount: 1000, currency: types.Currency.USD },
  testMode: true,
});
// captureResponse.status === 8 (CHARGED) or 20 (PENDING) — both are success

Refund

const refundResponse = await client.refund({
  merchantRefundId: 'ref_001',
  connectorTransactionId: authResponse.connectorTransactionId!,
  refundAmount: { minorAmount: 500, currency: types.Currency.USD },
  paymentAmount: 1000,
  reason: 'RETURN',  // Use enum values for cross-connector safety
  testMode: true,
});
// refundResponse.status === 4 (REFUND_SUCCESS) or 3 (REFUND_PENDING) — both are success

Void (Cancel Authorization)

const voidResponse = await client.void({
  merchantVoidId: 'void_001',
  connectorTransactionId: authResponse.connectorTransactionId!,
  cancellationReason: 'Customer cancelled',
  testMode: true,
});
// voidResponse.status === 11 (VOIDED)

Status Codes Reference

PaymentStatus

The response.status field is always a number, not a string. String comparisons silently fail:

// ❌ Always false — response.status is a number, never a string
if (response.status === 'CHARGED') { ... }

// ✅ Correct — compare against the numeric enum constant
if (response.status === types.PaymentStatus.CHARGED) { ... }  // === 8
if (response.status === 8) { ... }                            // equivalent

Important: a FAILURE status is returned in the response body — it does NOT throw an exception. Always check response.status explicitly.

PaymentStatus and RefundStatus are two separate enums with overlapping integer values. Use types.PaymentStatus for authorize/capture/void responses and types.RefundStatus for refund responses. Using the wrong enum gives actively misleading results:

| Integer | types.PaymentStatus | types.RefundStatus | |---------|----------------------|---------------------| | 3 | ROUTER_DECLINED ❌ | REFUND_PENDING ✅ | | 4 | AUTHENTICATION_PENDING ❌ | REFUND_SUCCESS ✅ |

Example: a successful refund returns status 4. Checking it against types.PaymentStatus gives AUTHENTICATION_PENDING — which looks like a failure. Always use types.RefundStatus for refund responses.

| Name | Value | Meaning | |------|-------|---------| | PAYMENT_STATUS_UNSPECIFIED | 0 | Unknown | | STARTED | 1 | Payment initiated | | AUTHENTICATION_PENDING | 4 | Awaiting 3DS redirect | | AUTHENTICATION_SUCCESSFUL | 5 | 3DS passed | | AUTHENTICATION_FAILED | 2 | 3DS failed | | AUTHORIZED | 6 | Auth succeeded, not yet captured | | AUTHORIZATION_FAILED | 7 | Auth declined | | CHARGED | 8 | Captured / auto-captured successfully | | PARTIAL_CHARGED | 17 | Partially captured | | CAPTURE_INITIATED | 13 | Async capture in progress | | CAPTURE_FAILED | 14 | Capture failed | | VOIDED | 11 | Authorization voided/cancelled | | VOID_INITIATED | 12 | Async void in progress | | VOID_FAILED | 15 | Void failed | | PENDING | 20 | Processing / async (common for async connectors) | | FAILURE | 21 | Soft decline — check response.error | | ROUTER_DECLINED | 3 | Declined by routing layer | | EXPIRED | 26 | Payment expired | | PARTIALLY_AUTHORIZED | 25 | Partial authorization | | UNRESOLVED | 19 | Requires manual review |

Checking status safely:

import { types } from 'hs-paylib';

const response = await client.authorize(request);

// Soft declines arrive as status, NOT exceptions
if (response.status === types.PaymentStatus.FAILURE) {
  console.error('Declined:', response.error?.message, response.error?.code);
} else if (response.status === types.PaymentStatus.CHARGED ||
           response.status === types.PaymentStatus.AUTHORIZED) {
  console.log('Success:', response.connectorTransactionId);
} else if (response.status === types.PaymentStatus.AUTHENTICATION_PENDING) {
  // Redirect user for 3DS
  console.log('Redirect to:', response.redirectionData);
}

RefundStatus

| Name | Value | Meaning | |------|-------|---------| | REFUND_STATUS_UNSPECIFIED | 0 | Unknown | | REFUND_FAILURE | 1 | Refund failed | | REFUND_MANUAL_REVIEW | 2 | Pending manual review | | REFUND_PENDING | 3 | Processing (normal for async connectors) | | REFUND_SUCCESS | 4 | Completed | | REFUND_TRANSACTION_FAILURE | 5 | Transaction-level failure |

REFUND_PENDING is a normal success state for many async connectors. Treat both REFUND_PENDING and REFUND_SUCCESS as successful outcomes.


Error Handling

The SDK raises exceptions only for hard failures (network errors, invalid configuration, serialization errors). Soft payment declines come back as an in-band status: FAILURE in the response body.

import { IntegrationError, ConnectorError, NetworkError, types } from 'hs-paylib';

try {
  const response = await client.authorize(request);

  // Always check status — soft declines do NOT throw
  if (response.status === types.PaymentStatus.FAILURE) {
    console.error('Payment declined:', response.error?.message);
    return;
  }

} catch (error) {
  if (error instanceof IntegrationError) {
    // Request-phase error: bad config, missing required field, serialization failure
    // e.g. "MISSING_REQUIRED_FIELD: browser_info" for connectors that require browserInfo
    console.error('Integration error:', error.errorCode, error.message);

  } else if (error instanceof ConnectorError) {
    // Response-phase error: connector returned unexpected format, transform failed
    // e.g. invalid refund reason enum
    console.error('Connector error:', error.errorCode, error.message);

  } else if (error instanceof NetworkError) {
    // Network-level: timeout, connection refused, DNS failure
    console.error('Network error:', error.message);
  }
}

response.error is a Protobuf Object — Not JSON-Serializable

response.error is a protobuf message, not a plain JS object. Passing it directly to JSON.stringify, a logger, or a web framework response will either throw or produce {}.

// ❌ Throws or produces empty object
res.json({ error: response.error });
JSON.stringify(response.error);

// ✅ Extract the primitive fields you need
res.json({
  error: {
    message: response.error?.message,
    code: response.error?.code,
    reason: response.error?.reason,
  }
});

Common Error Codes

| Code | Type | Cause | Fix | |------|------|-------|-----| | MISSING_REQUIRED_FIELD: browser_info | IntegrationError | Connector requires browserInfo | Add browserInfo to request | | INVALID_CONFIGURATION | IntegrationError | Wrong credentials or missing required config field | Check connector config fields | | CLIENT_INITIALIZATION | IntegrationError | SDK failed to initialize native library | Check platform compatibility | | CONNECT_TIMEOUT | NetworkError | Could not reach connector | Check network / proxy config | | RESPONSE_TIMEOUT | NetworkError | Connector took too long | Increase totalTimeoutMs | | TOTAL_TIMEOUT | NetworkError | Request exceeded total timeout | Increase totalTimeoutMs |


Advanced Configuration

Timeouts

const client = new PaymentClient(config, {
  http: {
    totalTimeoutMs: 30000,      // Total request timeout
    connectTimeoutMs: 10000,    // TCP connect timeout
    responseTimeoutMs: 25000,   // Time waiting for response headers
    keepAliveTimeoutMs: 60000,  // Keep-alive connection lifetime
  }
});

Proxy

const client = new PaymentClient(config, {
  http: {
    proxy: {
      httpsUrl: 'https://proxy.company.com:8443',
      bypassUrls: ['http://localhost']
    }
  }
});

Per-Request Overrides

const response = await client.authorize(request, {
  http: { totalTimeoutMs: 60000 }  // Override for this request only
});

Connection Pooling

Create the client once and reuse it — each instance manages its own connection pool:

// Good: create once, reuse
const client = new PaymentClient(config);
for (const payment of payments) {
  await client.authorize(payment);
}

// Bad: creating a new client per request destroys connection pool benefits

CA Certificate Pinning

const client = new PaymentClient(config, {
  http: {
    caCert: fs.readFileSync('ca.pem', 'utf8')  // PEM or DER format
  }
});

Building from Source

# Clone the repository
git clone https://github.com/juspay/hyperswitch-prism.git
cd hyperswitch-prism/sdk/javascript

# Build native library, generate bindings, and pack
make pack

# Run tests
make test-pack

# With live API credentials
CONNECTOR_API_KEY=your_api_key make test-pack