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

duitku-ts

v1.0.0

Published

Duitku TypeScript SDK for Node.js and Bun - Payment Gateway Integration

Readme

Duitku TypeScript SDK

Welcome to the Duitku TypeScript SDK — the Community TypeScript library for integrating Duitku payment gateway into your Node.js or Bun applications.

flow_duitku_payment


Features

  • ✅ Full compatibility with Node.js >= 18 and Bun
  • Zero runtime dependencies — uses only built-in APIs (fetch, node:crypto, node:fs)
  • Dual package output — CommonJS and ESM
  • Full TypeScript support with type definitions
  • ✅ Support for both Duitku-Pop and Duitku-API
  • ✅ Request parameter sanitization (optional)
  • Logging to file (optional)
  • ✅ Comprehensive test suite

Links


Requirements

  • Node.js >= 18.0.0
  • Bun >= 1.0.0 (optional)

Installation

Using npm

npm install duitku-ts

Using Bun

bun add duitku-ts

Using yarn

yarn add duitku-ts

Configuration Settings

import { Config } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');

// false for production mode (default: true = sandbox)
config.setSandboxMode(false);

// Enable/disable request parameter sanitization (default: true)
config.setSanitizedMode(false);

// Enable/disable logging to file (default: true)
config.setDuitkuLogs(false);

Config Constructor

| Parameter | Type | Default | Description | | ----------------- | --------- | ------- | ------------------------------------------ | | apiKey | string | — | Your merchant's API key | | merchantCode | string | — | Your merchant's merchant code | | isSandboxMode | boolean | true | true for sandbox, false for production | | isSanitizedMode | boolean | true | Enable request parameter sanitization | | duitkuLogs | boolean | true | Enable logging to file |


Duitku POP

Create Invoice (Duitku-Pop)

Parameter paymentMethod is optional. You can set it to direct customers to a specific payment method.

import { Config, Pop } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');
config.setSandboxMode(true);

const params = {
  paymentAmount: 10000,
  merchantOrderId: `order-${Date.now()}`, // unique
  productDetails: 'Test Payment',
  additionalParam: '', // optional
  merchantUserInfo: '', // optional
  customerVaName: 'John Doe',
  email: '[email protected]',
  phoneNumber: '081234567890',
  callbackUrl: 'http://YOUR_SERVER/callback',
  returnUrl: 'http://YOUR_SERVER/return',
  expiryPeriod: 60, // expired in minutes
  itemDetails: [
    {
      name: 'Test Payment',
      price: 10000,
      quantity: 1,
    },
  ],
  customerDetail: {
    firstName: 'John',
    lastName: 'Doe',
    email: '[email protected]',
    phoneNumber: '081234567890',
    billingAddress: {
      firstName: 'John',
      lastName: 'Doe',
      address: 'Jl. Kembangan Raya',
      city: 'Jakarta',
      postalCode: '11530',
      phone: '081234567890',
      countryCode: 'ID',
    },
    shippingAddress: {
      firstName: 'John',
      lastName: 'Doe',
      address: 'Jl. Kembangan Raya',
      city: 'Jakarta',
      postalCode: '11530',
      phone: '081234567890',
      countryCode: 'ID',
    },
  },
};

try {
  const response = await Pop.createInvoice(params, config);
  console.log(response.statusCode); // '00' = success
  console.log(response.paymentUrl); // payment URL
  console.log(response.reference); // reference for checkout.process()
} catch (error) {
  console.error(error.message);
}

Check Transaction Status (Duitku-Pop)

import { Config, Pop } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');

try {
  const merchantOrderId = 'YOUR_MERCHANT_ORDER_ID';
  const status = await Pop.transactionStatus(merchantOrderId, config);

  if (status.statusCode === '00') {
    // Action Success
  } else if (status.statusCode === '01') {
    // Action Pending
  } else {
    // Action Failed Or Expired
  }
} catch (error) {
  console.error(error.message);
}

Callback (Duitku-Pop)

Duitku sends callbacks via HTTP POST with application/x-www-form-urlencoded content type.

Note: Unlike the PHP SDK which reads $_POST, the TypeScript SDK requires you to pass the request body as a parameter.

import { Config, Pop } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');

// Express.js example
app.post('/callback', express.urlencoded({ extended: true }), (req, res) => {
  try {
    const notification = Pop.callback(req.body, config);

    if (notification.resultCode === '00') {
      // Action Success
    } else if (notification.resultCode === '01') {
      // Action Failed
    }

    res.json(notification);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

Get Payment Method (Duitku-Pop)

import { Config, Pop } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');

try {
  const methods = await Pop.getPaymentMethod('10000', config);
  console.log(methods.paymentFee);
  // [{ name: 'Permata Bank Virtual Account', code: 'BT', fee: 4000 }, ...]
} catch (error) {
  console.error(error.message);
}

Frontend Integration (Duitku-Pop)

<!-- Add Duitku JS Bundle -->
<script src="https://app-sandbox.duitku.com/lib/js/duitku.js"></script>
<!-- For production: https://app-prod.duitku.com/lib/js/duitku.js -->

<script>
  $.ajax({
    type: 'POST',
    data: {
      paymentAmount: amount,
      productDetail: productDetail,
      email: email,
      phoneNumber: phoneNumber,
    },
    url: 'http://YOUR_SERVER/create-invoice',
    dataType: 'json',
    success: function (result) {
      checkout.process(result.reference, {
        successEvent: function (result) {
          console.log('Payment Success', result);
        },
        pendingEvent: function (result) {
          console.log('Payment Pending', result);
        },
        errorEvent: function (result) {
          console.log('Payment Error', result);
        },
        closeEvent: function (result) {
          console.log('Customer closed popup without finishing payment', result);
        },
      });
    },
  });
</script>

Duitku API

Create Invoice (Duitku-API)

Important: paymentMethod is required for Duitku-API.

import { Config, Api } from 'duitku-ts';

const config = new Config('YOUR_MERCHANT_KEY', 'YOUR_MERCHANT_CODE');

const params = {
  paymentAmount: 10000,
  paymentMethod: 'BT', // REQUIRED - Permata Bank Virtual Account
  merchantOrderId: `order-${Date.now()}`,
  productDetails: 'Test Payment',
  email: '[email protected]',
  phoneNumber: '081234567890',
  customerVaName: 'John Doe',
  callbackUrl: 'http://YOUR_SERVER/callback',
  returnUrl: 'http://YOUR_SERVER/return',
  expiryPeriod: 60,
};

try {
  const response = await Api.createInvoice(params, config);
  console.log(response.paymentUrl);
} catch (error) {
  console.error(error.message);
}

Check Transaction Status (Duitku-API)

import { Config, Api } from 'duitku-ts';

try {
  const status = await Api.transactionStatus('YOUR_MERCHANT_ORDER_ID', config);

  if (status.statusCode === '00') {
    // Action Success
  } else if (status.statusCode === '01') {
    // Action Pending
  } else {
    // Action Failed Or Expired
  }
} catch (error) {
  console.error(error.message);
}

Callback (Duitku-API)

import { Config, Api } from 'duitku-ts';

// Express.js example
app.post('/callback/api', express.urlencoded({ extended: true }), (req, res) => {
  try {
    const notification = Api.callback(req.body, config);

    if (notification.resultCode === '00') {
      // Action Success
    } else if (notification.resultCode === '01') {
      // Action Failed
    }

    res.json(notification);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

Get Payment Method (Duitku-API)

import { Config, Api } from 'duitku-ts';

try {
  const methods = await Api.getPaymentMethod('10000', config);
  console.log(methods.paymentFee);
} catch (error) {
  console.error(error.message);
}

Error Handling

All SDK errors are wrapped in DuitkuError:

import { DuitkuError } from 'duitku-ts';

try {
  await Pop.createInvoice(params, config);
} catch (error) {
  if (error instanceof DuitkuError) {
    console.error('Message:', error.message);
    console.error('HTTP Status:', error.statusCode);
    console.error('Response:', error.responseBody);
  }
}

Migration from PHP SDK

If you're migrating from the PHP SDK (duitkupg/duitku-php), here are the key differences:

| PHP SDK | TypeScript SDK | | ---------------------------------- | ----------------------------------------------- | | Synchronous calls | All HTTP methods are async (use await) | | Returns JSON string | Returns typed objects | | callback($config) reads $_POST | callback(body, config) — pass body explicitly | | \Duitku\Pop::createInvoice(...) | Pop.createInvoice(...) | | \Duitku\Api::callback(...) | Api.callback(body, ...) | | json_decode($response) | Not needed — already parsed |


Running Tests

# Unit tests
npm test

# Unit tests with Bun
npm run test:bun

# With coverage
npm run test:coverage

License

MIT — see LICENSE for details.


Support

For issues, questions, or feature requests, please visit: