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

xendit-fn

v1.0.7

Published

Modern TypeScript SDK for Xendit payment gateway with built-in type safety, error handling, and production-ready features

Downloads

101

Readme

Xendit SDK for TypeScript/JavaScript

npm version TypeScript License: MIT

A modern, production-ready TypeScript SDK for the Xendit payment gateway. Framework-agnostic and designed for any JavaScript/TypeScript project.

Features

Production-Ready

  • Built-in rate limiting and retry logic
  • Webhook signature verification
  • Comprehensive error handling
  • Pagination utilities

Developer Experience

  • Full TypeScript support with type safety
  • Runtime validation using Zod schemas
  • Tree-shakeable exports
  • Framework-agnostic design

Complete API Coverage

  • Customer Management
  • E-wallet Payments
  • Payment Methods
  • Invoice Management
  • Payment Request API (v3) - Unified payment processing
  • Refund API - Process refunds
  • Payout API - Disbursements and payouts
  • Balance & Transaction API - Account balance and transaction history
  • Card Operations - Tokenization, charges, and authorizations

Installation

# Using bun (recommended)
bun add xendit-fn

# Using npm
npm install xendit-fn

# Using yarn
yarn add xendit-fn

Quick Start

import { Xendit } from 'xendit-fn';

// Initialize with your secret key
const xendit = Xendit(process.env.XENDIT_SECRET_KEY!);

// Create a customer
const customer = await xendit.customer.create({
  reference_id: 'customer_001',
  type: 'INDIVIDUAL',
  individual_detail: {
    given_names: 'John',
    surname: 'Doe',
  },
  email: '[email protected]',
  mobile_number: '+639171234567',
});

// Create a payment request (recommended for new integrations)
const payment = await xendit.paymentRequest.create({
  reference_id: 'payment_001',
  type: 'PAY',
  country: 'PH',
  currency: 'PHP',
  request_amount: 10000, // 100.00 PHP
  payment_method: {
    type: 'EWALLET',
    ewallet: {
      channel_code: 'PH_GCASH',
      channel_properties: {
        success_redirect_url: 'https://yourapp.com/success',
        failure_redirect_url: 'https://yourapp.com/failure',
      },
    },
  },
  customer_id: customer.id,
});

API Reference

Payment Request API (v3) - Recommended

The Payment Request API is the unified way to process payments across all payment channels.

Create Payment Request

// E-wallet payment
const payment = await xendit.paymentRequest.create({
  reference_id: 'payment_001',
  type: 'PAY',
  country: 'PH',
  currency: 'PHP',
  request_amount: 10000,
  payment_method: {
    type: 'EWALLET',
    ewallet: {
      channel_code: 'PH_GCASH',
      channel_properties: {
        success_redirect_url: 'https://yourapp.com/success',
        failure_redirect_url: 'https://yourapp.com/failure',
      },
    },
  },
  description: 'Payment for order #123',
  customer_id: 'cust-12345',
});

// Card payment
const cardPayment = await xendit.paymentRequest.create({
  reference_id: 'payment_002',
  type: 'PAY',
  country: 'PH',
  currency: 'PHP',
  request_amount: 50000,
  payment_method: {
    type: 'CARD',
    card_information: {
      token_id: 'token-from-xendit-js',
    },
  },
  capture_method: 'AUTOMATIC',
});

// Direct debit payment
const directDebitPayment = await xendit.paymentRequest.create({
  reference_id: 'payment_003',
  type: 'PAY',
  country: 'ID',
  currency: 'IDR',
  request_amount: 100000,
  payment_method: {
    type: 'DIRECT_DEBIT',
    direct_debit: {
      channel_code: 'BCA_ONEKLIK',
      channel_properties: {
        account_mobile_number: '+6281234567890',
      },
    },
  },
});

// Virtual account payment
const vaPayment = await xendit.paymentRequest.create({
  reference_id: 'payment_004',
  type: 'PAY',
  country: 'ID',
  currency: 'IDR',
  request_amount: 200000,
  payment_method: {
    type: 'VIRTUAL_ACCOUNT',
    virtual_account: {
      channel_code: 'BCA',
      channel_properties: {
        customer_name: 'John Doe',
      },
    },
  },
});

Get Payment Request

const payment = await xendit.paymentRequest.get({
  id: 'pr-12345',
});

List Payment Requests

const payments = await xendit.paymentRequest.list({
  status: ['SUCCEEDED', 'PENDING'],
  limit: 50,
  created_after: '2024-01-01T00:00:00Z',
});

Refund API

Process refunds for successful payment requests.

Create Refund

// Full refund
const refund = await xendit.refund.create({
  payment_request_id: 'pr-12345',
  reason: 'REQUESTED_BY_CUSTOMER',
  metadata: {
    order_id: 'order_123',
  },
});

// Partial refund
const partialRefund = await xendit.refund.create({
  payment_request_id: 'pr-12345',
  amount: 5000, // Partial amount
  reason: 'CANCELLATION',
});

Get Refund

const refund = await xendit.refund.get({
  id: 'refund-12345',
});

List Refunds

const refunds = await xendit.refund.list({
  payment_request_id: 'pr-12345',
  limit: 20,
});

Payout API

Create and manage payouts/disbursements.

Create Payout

// Bank payout
const payout = await xendit.payout.create({
  reference_id: 'payout_001',
  channel_code: 'BANK',
  channel_properties: {
    channel_code: 'BANK',
    bank_account: {
      account_holder_name: 'John Doe',
      account_number: '1234567890',
      bank_code: 'BCA',
      account_type: 'CHECKING',
    },
  },
  amount: 100000,
  currency: 'IDR',
  description: 'Payout for order #123',
});

// E-wallet payout
const ewalletPayout = await xendit.payout.create({
  reference_id: 'payout_002',
  channel_code: 'EWALLET',
  channel_properties: {
    channel_code: 'EWALLET',
    ewallet: {
      account_holder_name: 'Jane Doe',
      account_number: '+6281234567890',
      ewallet_type: 'OVO',
    },
  },
  amount: 50000,
  currency: 'IDR',
});

Get Payout

const payout = await xendit.payout.get({
  id: 'payout-12345',
});

List Payouts

const payouts = await xendit.payout.list({
  status: ['COMPLETED', 'PENDING'],
  channel_code: ['BANK'],
  limit: 50,
});

Cancel Payout

const cancelledPayout = await xendit.payout.cancel({
  id: 'payout-12345',
});

Balance & Transaction API

Get Balance

const balance = await xendit.balance.get();
// Returns: { balance: 1000000, currency: 'IDR' }

List Transactions

const transactions = await xendit.balance.listTransactions({
  types: ['PAYMENT', 'PAYOUT'],
  statuses: ['SUCCEEDED'],
  limit: 100,
  created_after: '2024-01-01T00:00:00Z',
});

Card Operations

Create Token

const token = await xendit.card.createToken({
  mid_label: 'merchant_label',
  card_data: {
    account_number: '4111111111111111',
    exp_month: '12',
    exp_year: '2025',
    card_holder_first_name: 'John',
    card_holder_last_name: 'Doe',
    card_holder_email: '[email protected]',
    card_holder_phone_number: '+639171234567',
  },
  is_multiple_use: true,
  currency: 'PHP',
});

Get Token

const token = await xendit.card.getToken({
  credit_card_token_id: 'token-12345',
});

Authenticate Token

const auth = await xendit.card.authenticateToken({
  token_id: 'token-12345',
  amount: '10000',
  currency: 'PHP',
  external_id: 'auth_001',
});

Authorize Token

const charge = await xendit.card.authorizeToken({
  token_id: 'token-12345',
  amount: '10000',
  external_id: 'charge_001',
  capture: true,
});

Create Charge

const charge = await xendit.card.createCharge({
  token_id: 'token-12345',
  external_id: 'charge_001',
  amount: 10000,
  currency: 'PHP',
  capture: true,
  authentication_id: 'auth-12345',
});

Get Charge

const charge = await xendit.card.getCharge({
  id: 'charge-12345',
});

Customer Management

Create Customer

const customer = await xendit.customer.create({
  reference_id: 'unique_customer_id',
  type: 'INDIVIDUAL', // or 'BUSINESS'
  individual_detail: {
    given_names: 'John',
    surname: 'Doe',
    nationality: 'PH',
    date_of_birth: '1990-01-01',
  },
  email: '[email protected]',
  mobile_number: '+639171234567',
  addresses: [{
    country: 'PH',
    street_line1: '123 Main St',
    city: 'Manila',
    postal_code: '1000',
    is_primary: true,
  }],
});

Get Customer

// Get by ID
const customer = await xendit.customer.getById({
  id: 'cust-12345'
});

// Get by reference ID
const customers = await xendit.customer.getByRefId({
  reference_id: 'customer_001'
});

Update Customer

const updatedCustomer = await xendit.customer.update({
  id: 'cust-12345',
  payload: {
    email: '[email protected]',
    phone_number: '+639181234567',
  },
});

E-Wallet Payments

Create Charge

// One-time payment
const charge = await xendit.ewallet.charge({
  reference_id: 'charge_001',
  currency: 'PHP',
  amount: 50000, // 500.00 PHP
  checkout_method: 'ONE_TIME_PAYMENT',
  channel_code: 'PH_GCASH',
  channel_properties: {
    success_redirect_url: 'https://yourapp.com/success',
    failure_redirect_url: 'https://yourapp.com/failure',
  },
  customer_id: 'cust-12345', // optional
  basket: [ // optional
    {
      reference_id: 'item_001',
      name: 'Product Name',
      category: 'Electronics',
      currency: 'PHP',
      price: 50000,
      quantity: 1,
      type: 'PRODUCT',
    },
  ],
});

// Tokenized payment
const tokenizedCharge = await xendit.ewallet.charge({
  reference_id: 'charge_002',
  currency: 'PHP',
  amount: 25000,
  checkout_method: 'TOKENIZED_PAYMENT',
  payment_method_id: 'pm-12345',
  channel_properties: {
    success_redirect_url: 'https://yourapp.com/success',
  },
});

Get Charge

const charge = await xendit.ewallet.get({
  id: 'ewc-12345'
});

Payment Methods

Create Payment Method

const paymentMethod = await xendit.paymentMethod.create({
  type: 'CARD',
  country: 'PH',
  reusability: 'MULTIPLE_USE',
  card: {
    currency: 'PHP',
    channel_properties: {
      success_return_url: 'https://yourapp.com/success',
      failure_return_url: 'https://yourapp.com/failure',
    },
  },
});

Get Payment Method

const paymentMethod = await xendit.paymentMethod.get({
  id: 'pm-12345',
});

List Payment Methods

const paymentMethods = await xendit.paymentMethod.list({
  customer_id: 'cust-12345',
  type: ['CARD', 'EWALLET'],
  status: ['ACTIVE'],
  limit: 50,
});

Update Payment Method

const updated = await xendit.paymentMethod.update({
  id: 'pm-12345',
  payload: {
    status: 'INACTIVE',
    description: 'Card expired',
  },
});

Invoice Management

Create Invoice

const invoice = await xendit.invoice.create({
  external_id: 'invoice-001',
  payer_email: '[email protected]',
  amount: 100000,
  description: 'Payment for services',
  invoice_duration: 3600,
  customer: {
    customer_name: 'John Doe',
    customer_email: '[email protected]',
    customer_phone: '+639171234567',
  },
  success_redirect_url: 'https://yoursite.com/success',
  failure_redirect_url: 'https://yoursite.com/failure',
});

Get Invoice

const invoice = await xendit.invoice.get({
  invoice_id: 'invoice-12345',
});

List Invoices

const invoices = await xendit.invoice.list({
  statuses: ['PAID', 'PENDING'],
  limit: 50,
  created_after: '2024-01-01T00:00:00Z',
});

Update Invoice

const updated = await xendit.invoice.update({
  invoice_id: 'invoice-12345',
  payload: {
    customer_email: '[email protected]',
    items: [
      {
        name: 'Updated Item',
        quantity: 2,
        price: 50000,
      },
    ],
  },
});

Expire Invoice

const expired = await xendit.invoice.expire({
  invoice_id: 'invoice-12345',
});

Supported Countries and Currencies

  • Philippines (PH): PHP
  • Indonesia (ID): IDR
  • Malaysia (MY): MYR
  • Thailand (TH): THB
  • Vietnam (VN): VND

Supported Payment Channels

E-Wallets

  • Indonesia: OVO, DANA, LinkAja, ShopeePay, AstraPay, JENIUSPAY, SakuKu
  • Philippines: PayMaya, GCash, GrabPay, ShopeePay
  • Vietnam: Appota, MoMo, ShopeePay, VNPTWallet, ViettelPay, ZaloPay
  • Thailand: WeChat Pay, LINE Pay, TrueMoney, ShopeePay
  • Malaysia: Touch 'n Go, ShopeePay, GrabPay

Cards

  • Visa, Mastercard, JCB, AMEX

Direct Debit

  • BCA OneKlik, Mandiri ClickPay, BRI AutoDebit

Virtual Accounts

  • BCA, BNI, Mandiri, Permata, and more

Error Handling

The SDK provides comprehensive error handling with custom error types:

import { XenditApiError, ValidationError } from 'xendit-fn';

try {
  const payment = await xendit.paymentRequest.create(invalidData);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Validation failed:', error.validationErrors);
  } else if (error instanceof XenditApiError) {
    console.error('API Error:', {
      code: error.code,
      message: error.message,
      statusCode: error.statusCode,
      details: error.details,
    });
  } else {
    console.error('Unexpected error:', error);
  }
}

TypeScript Support

The SDK is built with TypeScript and provides full type definitions:

import type {
  CreatePaymentRequest,
  PaymentRequestResource,
  CreateRefund,
  RefundResource,
  CreatePayout,
  PayoutResource,
} from 'xendit-fn';

// All parameters and responses are fully typed
const createPayment = async (
  data: CreatePaymentRequest
): Promise<PaymentRequestResource> => {
  return await xendit.paymentRequest.create(data);
};

Production-Ready Features

Rate Limiting

The SDK includes built-in rate limiting to respect API limits:

import { Xendit } from 'xendit-fn';

const xendit = Xendit('your-api-key', {
  rateLimit: {
    maxRequests: 100,      // Max requests per window
    windowMs: 60000,       // Time window (1 minute)
    maxRetries: 3,         // Retry attempts
    baseRetryDelayMs: 1000 // Base delay for retries
  }
});

Webhook Handling

Secure webhook processing with signature verification:

import {
  createWebhookProcessor,
  WebhookHandlers,
} from 'xendit-fn';

// Create webhook processor
const webhookProcessor = createWebhookProcessor({
  callbackToken: 'your-webhook-token',
  // OR use HMAC verification
  // hmacSecret: 'your-hmac-secret'
});

// Define event handlers
const handlers: WebhookHandlers = {
  'payment_request.succeeded': async (event) => {
    console.log('Payment succeeded:', event.data);
    // Process payment success
  },
  'payment_request.failed': async (event) => {
    console.log('Payment failed:', event.data);
    // Handle payment failure
  },
  'refund.succeeded': async (event) => {
    console.log('Refund processed:', event.data);
    // Handle refund
  },
};

// Process webhook in your endpoint
app.post('/webhook', async (req, res) => {
  const result = await webhookProcessor.processWebhook(
    req.body,
    req.headers,
    handlers
  );

  if (result.success) {
    res.status(200).send('OK');
  } else {
    res.status(400).send(result.error);
  }
});

Pagination Utilities

For endpoints that return paginated data:

import { fetchAllPages, iterateItems } from 'xendit-fn';

// Get all invoices across all pages
const allInvoices = await fetchAllPages(
  axiosInstance,
  '/invoices',
  InvoiceSchema,
  { limit: 100, maxItems: 1000 }
);

// Stream through items
for await (const invoice of iterateItems(
  axiosInstance,
  '/invoices',
  InvoiceSchema
)) {
  console.log('Processing invoice:', invoice.id);
}

Development

Setup

# Install dependencies
bun install

# Run type checking
bun run typecheck

# Run linting
bun run lint

# Run tests
bun run test

Building

# Build the package
bun run build

# Start development mode
bun run dev

Environment Variables

For testing, create a .env file:

XENDIT_SK=your_xendit_secret_key_here

Contributing

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

License

MIT License - see LICENSE file for details.

Related Projects

Environment Configuration

The SDK automatically detects test mode:

// Test mode (automatically detected)
const xendit = Xendit('xnd_development_...');

// Production mode
const xendit = Xendit('xnd_production_...');

Note: This is an unofficial SDK. For official support, please refer to Xendit's official documentation.