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

doku-nodejs-library

v1.0.52

Published

doku nodejs library

Readme

DOKU NODE JS SDK Documentation

Introduction

Welcome to the DOKU NODE JS SDK! This SDK simplifies access to the DOKU API for your server-side NODE JS applications, enabling seamless integration with payment and virtual account services.

If your looking for another language PHP, Go, Python, Java

Table of Contents

1. Getting Started

Requirements

  • NODE JS version 18 or higher

Installation

To install the Doku Snap SDK, use Composer:

npm i doku-nodejs-library

Configuration

Before using the Doku Snap SDK, you need to initialize it with your credentials:

  1. Client ID, Secret Key and DOKU Public Key: Retrieve these from the Integration menu in your Doku Dashboard
  2. Private Key and Public Key : Generate your Private Key and Public Key

How to generate Merchant privateKey and publicKey :

  1. generate private key RSA : openssl genrsa -out private.key 2048
  2. set passphrase your private key RSA : openssl pkcs8 -topk8 -inform PEM -outform PEM -in private.key -out pkcs8.key -v1 PBE-SHA1-3DES
  3. generate public key RSA : openssl rsa -in private.key -outform PEM -pubout -out public.pem

The encryption model applied to messages involves both asymmetric and symmetric encryption, utilizing a combination of Private Key and Public Key, adhering to the following standards:

  1. Standard Asymmetric Encryption Signature: SHA256withRSA dengan Private Key ( Kpriv ) dan Public Key ( Kpub ) (256 bits)
  2. Standard Symmetric Encryption Signature HMAC_SHA512 (512 bits)
  3. Standard Symmetric Encryption AES-256 dengan client secret sebagai encryption key.

| Parameter | Description | Required | |-----------------|----------------------------------------------------|--------------| | privateKey | The private key for the partner service. | ✅ | | publicKey | The public key for the partner service. | ✅ | | dokuPublicKey | Key that merchants use to verify DOKU request | ✅ | | clientId | The client ID associated with the service. | ✅ | | secretKey | The secret key for the partner service. | ✅ | | isProduction | Set to true for production environment | ✅ | | issuer | Optional issuer for advanced configurations. | ❌ | | authCode | Optional authorization code for advanced use. | ❌ |

const doku = require('doku-nodejs-library');

let privateKey = `-----BEGIN PRIVATE KEY-----
your privatekey
-----END PRIVATE KEY-----`;
let issuer = "your issuer";
let clientID = "your client id";
let publicKey = `-----BEGIN PUBLIC KEY-----
your public key
-----END PUBLIC KEY-----`;
let dokuPublicKey = `-----BEGIN PUBLIC KEY-----
doku public key
-----END PUBLIC KEY-----`;
let secretKey = 'SK-VknOxwR4xZSEPnG7fpJo';
let snap = new doku.Snap({
    isProduction : false,
    privateKey : privateKey,
    clientID : clientID,
    publicKey :publicKey,
    dokuPublicKey:dokuPublicKey,
    issuer:issuer,
    secretKey:secretKey
});

2. Usage

Initialization Always start by initializing the Snap object.

let snap = new doku.Snap({
    isProduction : false,
    privateKey : privateKey,
    clientID : clientID,
    publicKey :publicKey,
    dokuPublicKey:dokuPublicKey,
    issuer:issuer,
    secretKey:secretKey
});

Virtual Account

I. Virtual Account (DGPC & MGPC)

DGPC
  • Description: A pre-generated virtual account provided by DOKU.
  • Use Case: Recommended for one-time transactions.
MGPC
  • Description: Merchant generated virtual account.
  • Use Case: Recommended for top up business model.

Parameters for createVA and updateVA

  1. Create Virtual Account

    • Function: createVa
    const CreateVARequestDto = require('doku-nodejs-library/_models/createVaRequestDto');
    const VirtualAccountConfig = require('doku-nodejs-library/_models/virtualAccountConfig');
    const TotalAmount = require('doku-nodejs-library/_models/totalAmount');
    const AdditionalInfo = require('doku-nodejs-library/_models/additionalInfo');
       
    app.post('/create-va', async (req,res) => {
      let createVaRequestDto = new CreateVARequestDto();
        createVaRequestDto.partnerServiceId = req.body.partnerServiceId;
        createVaRequestDto.customerNo =req.body.customerNo;
        createVaRequestDto.virtualAccountNo = req.body.partnerServiceId+req.body.customerNo;
        createVaRequestDto.virtualAccountName = req.body.virtualAccountName;
        createVaRequestDto.virtualAccountEmail = req.body.virtualAccountEmail;
        createVaRequestDto.virtualAccountPhone = req.body.virtualAccountPhone;
        createVaRequestDto.trxId =  req.body.trxId;
       
        let totalAmount = new TotalAmount();
        totalAmount.value = req.body.totalAmount.value;
        totalAmount.currency = req.body.totalAmount.currency;
       
        createVaRequestDto.totalAmount = totalAmount;
       
        let virtualAccountConfig = new VirtualAccountConfig();
        virtualAccountConfig.reusableStatus = req.body.additionalInfo.virtualAccountConfig.reusableStatus;
        let additionalInfo = new AdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB", virtualAccountConfig);
        additionalInfo.channel = req.body.additionalInfo.channel;
        additionalInfo.virtualAccountConfig = virtualAccountConfig;
        createVaRequestDto.additionalInfo = additionalInfo;
        createVaRequestDto.virtualAccountTrxType =req.body.virtualAccountTrxType;
        createVaRequestDto.expiredDate = req.body.expiredDate;
      await snap.createVa(createVaRequestDto).then(va=>{
        res.status(200).send(va);
      }).catch(err=>{
          if(err.response){
              res.status(400).send(err.response.data)
          }else{
            res.status(400).send({
              responseCode:"400",
              responseMessage:err.message
            })
          }
           
      })
    })
  2. Update Virtual Account

    • Function: updateVa
    const UpdateVaVirtualAccountConfigDto = require('doku-nodejs-library/_models/updateVaVirtualAccountConfigDTO');
    const VirtualAccountConfig = require('doku-nodejs-library/_models/virtualAccountConfig');
    const TotalAmount = require('doku-nodejs-library/_models/totalAmount');
    const UpdateVaAdditionalInfoDto = require('doku-nodejs-library/_models/updateVaAdditionalInfoDTO');
       
      app.post('/update-va', async (req,res) => {
        let updateVaRequestDto = new UpdateVaDto()
        updateVaRequestDto.partnerServiceId = req.body.partnerServiceId; 
        updateVaRequestDto.customerNo = req.body.customerNo;
        updateVaRequestDto.virtualAccountNo =     updateVaRequestDto.partnerServiceId+updateVaRequestDto.customerNo;
        updateVaRequestDto.virtualAccountName = req.body.virtualAccountName;
        updateVaRequestDto.virtualAccountEmail = req.body.virtualAccountEmail;
        updateVaRequestDto.trxId = req.body.trxId
       
        let totalAmount = new TotalAmount();
        totalAmount.value = req.body.totalAmount.value;
        totalAmount.currency = req.body.totalAmount.currency;
       
        updateVaRequestDto.totalAmount = totalAmount;
        let virtualAccountConfig = new UpdateVaVirtualAccountConfigDto();
        virtualAccountConfig.status = "INACTIVE";
    
        let additionalInfo = new UpdateVaAdditionalInfoDto(req.body.additionalInfo.channel, virtualAccountConfig);
        additionalInfo.channel = req.body.additionalInfo.channel;
        additionalInfo.virtualAccountConfig = virtualAccountConfig;
        updateVaRequestDto.additionalInfo = additionalInfo;
        updateVaRequestDto.virtualAccountTrxType = "C";
        updateVaRequestDto.expiredDate = req.body.expiredDate;
        console.log(updateVaRequestDto)
        await snap.updateVa(updateVaRequestDto).then(va=>{
          res.status(200).send(va);
        }).catch((err)=>{
          if(err.response){
            res.status(400).send(err.response.data)
          }else{
            res.status(400).send({
              responseCode:"400",
              responseMessage:err.message
            })
          }
        })
    })
  3. Delete Virtual Account

    | Parameter | Description | Data Type | Required | |-----------------------|----------------------------------------------------------------------------|---------------------|--------------| | partnerServiceId | The unique identifier for the partner service. | String(8) | ✅ | | customerNo | The customer's identification number. | String(20) | ✅ | | virtualAccountNo | The virtual account number associated with the customer. | String(20) | ✅ | | trxId | Invoice number in Merchant's system. | String(64) | ✅ | | additionalInfo | channel: Channel applied for this VA.Example: VIRTUAL_ACCOUNT_BANK_CIMB | String(30) | ✅ |

  • Function: deletePaymentCode

    const DeleteVaRequestDto = require('doku-nodejs-library/_models/deleteVaRequestDTO');
    const DeleteVaRequestAdditionalInfo = require('doku-nodejs-library/_models/deleteVaRequestAdditionalInfoDTO');
        
    app.post('/delete-va', async (req,res) => {
      let deleteVaRequestDto = new DeleteVaRequestDto()
      deleteVaRequestDto.partnerServiceId =  req.body.partnerServiceId; 
      deleteVaRequestDto.customerNo =  req.body.customerNo;
      deleteVaRequestDto.virtualAccountNo = req.body.virtualAccountNo
         
      deleteVaRequestDto.trxId = req.body.trxId
      let additionalInfo = new DeleteVaRequestAdditionalInfo(req.body.additionalInfo.channel);
      deleteVaRequestDto.additionalInfo = additionalInfo;
      await snap.deletePaymentCode(deleteVaRequestDto).then(response=>{
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response){
          res.status(400).send(err.response.data)
        }else{
          res.status(400).send({
            responseCode:"400",
            responseMessage:err.message
          })
        }
      })
    })

II. Virtual Account (DIPC)

  • Description: The VA number is registered on merchant side and DOKU will forward Acquirer inquiry request to merchant side when the customer make payment at the acquirer channel

  • Function: directInquiryVa

    const InquiryResponseVirtualAccountDataDTO = require('doku-nodejs-library/_models/InquiryResponseVirtualAccountDataDTO');
    const InquiryResponseBodyDTO = require('doku-nodejs-library/_models/inquiryResponseBodyDTO');
    const TotalAmount = require('doku-nodejs-library/_models/totalAmount');
    const InquiryResponseAdditionalInfoDTO = require('doku-nodejs-library/_models/inquiryResponseAdditionalInfoDTO');
    const VirtualAccountConfig = require('doku-nodejs-library/_models/virtualAccountConfig');
    const InquiryReasonDto = require('doku-nodejs-library/_models/inquiryReasonDTO');
      app.post("/v1.1/transfer-va/inquiry",(req,res)=>{
        let data = new InquiryRequestDTO();
        data.partnerServiceId = req.body.partnerServiceId;
        data.customerNo = req.body.customerNo;
        data.virtualAccountNo = req.body.virtualAccountNo;
        data.trxDateInit = req.body.trxDateInit;
        data.inquiryRequestId = req.body.inquiryRequestId;
        data.additionalInfo = req.body.additionalInfo;
        let isvalid = snap.validateTokenB2B(req.headers['authorization']);
        if(isvalid){
            <!--validate yout virtualAccountNo in your database-->
            let bodyData = new InquiryResponseBodyDTO()
                  bodyData.responseCode = "2002400";
                  bodyData.responseMessage = "Successful"
                  let vaData = new InquiryResponseVirtualAccountDataDTO()
                  vaData.partnerServiceId = req.body.partnerServiceId;
                  vaData.customerNo = req.body.customerNo;
                  vaData.virtualAccountNo = req.body.virtualAccountNo;
                  vaData.virtualAccountName = "Nama "+Date.now();
                  vaData.virtualAccountEmail ="email."+Date.now()+"@gmail.com";
                  vaData.virtualAccountPhone = `${Date.now()}`;
                  let totalAmount = new TotalAmount()
                  totalAmount.currency = "IDR";
                  totalAmount.value = "25000.00"
                  vaData.totalAmount = totalAmount;
                  vaData.virtualAccountTrxType = "C"
                  let additionalInfo = new InquiryResponseAdditionalInfoDTO()
                  additionalInfo.channel = req.body.additionalInfo.channel;
                  additionalInfo.trxId = "INV_MERCHANT_"+Date.now();
                  let virtualAccountConfig = new VirtualAccountConfig()
                  virtualAccountConfig.reusableStatus = true;
                  virtualAccountConfig.maxAmount = "100000.00";
                  virtualAccountConfig.minAmount = "10000.00"
                  additionalInfo.virtualAccountConfig = virtualAccountConfig;
                  vaData.additionalInfo = additionalInfo;
                  vaData.inquiryStatus ="00";
                  let inquiryReason = new InquiryReasonDto()
                  inquiryReason.english = "Success";
                  inquiryReason.indonesia = "Sukses";
                  vaData.inquiryReason = inquiryReason;
                  vaData.inquiryRequestId = req.body.inquiryRequestId;
                  vaData.freeText = [
                          {
                            "english": "Free text",
                            "indonesia": "Tulisan Bebas"
                          }
                  ]
                  bodyData.virtualAccountData = vaData;
        }else{
          let body ={
            "responseCode": "4010000",
            "responseMessage": "Unauthorized",
          }
           res.status(401).send(body);
        }})

III. Check Virtual Account Status

| Parameter | Description | Data Type | Required | |-----------------------|----------------------------------------------------------------------------|---------------------|--------------| | partnerServiceId | The unique identifier for the partner service. | String(8) | ✅ | | customerNo | The customer's identification number. | String(20) | ✅ | | virtualAccountNo | The virtual account number associated with the customer. | String(20) | ✅ | | inquiryRequestId | The customer's identification number. | String(128) | ❌ | | paymentRequestId | The virtual account number associated with the customer. | String(128) | ❌ | | additionalInfo | The virtual account number associated with the customer. | String | ❌ |

  • Function: checkStatusVa
    const CheckStatusVARequestDto = require('doku-nodejs-library/_models/checkStatusVARequestDTO');
        
    app.post('/check-status', async (req,res) => {
      let checkVaRequestDto = new CheckStatusVARequestDto()
      checkVaRequestDto.partnerServiceId = req.body.partnerServiceId; 
      checkVaRequestDto.customerNo =  req.body.customerNo;
      checkVaRequestDto.virtualAccountNo = checkVaRequestDto.partnerServiceId+checkVaRequestDto.customerNo;
      await snap.checkStatusVa(checkVaRequestDto).then(response=>{
           res.status(200).send(response);
      }).catch((err)=>{
      if(err.response){
          res.status(400).send(err.response.data)
      }else{
          res.status(400).send({
            responseCode:"400",
            responseMessage:err.message
          })
      }
     })
    })

B. Binding / Registration Operations

The card registration/account binding process must be completed before payment can be processed. The merchant will send the card registration request from the customer to DOKU.

Each card/account can only registered/bind to one customer on one merchant. Customer needs to verify OTP and input PIN.

| Services | Binding Type | Details | |-------------------|-----------------------|-----------------------------------| | Direct Debit | Account Binding | Supports Allo Bank and CIMB | | Direct Debit | Card Registration | Supports BRI | | E-Wallet | Account Binding | Supports OVO |

I. Account Binding

  1. Binding
  • Function: doAccountBinding

    const AccountBindingRequestDto = require('doku-nodejs-library/_models/accountBindingRequestDTO');
        
    app.post("/account-binding", async (req,res)=>{
      let request = new AccountBindingRequestDto()
      request.phoneNo = req.body.phoneNo
      request.additionalInfo = req.body.additionalInfo;
      let ipAddress = req.headers['x-ip-address'];
      let deviceId = req.headers['x-device-id'];
      await snap.doAccountBinding(request,ipAddress,deviceId).then((response)=>{
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(parseInt(err.response.data.responseCode.substring(0, 3))).send(err.response.data);
        }else{
          res.status(500).send({"message":err.message});
        }
           
      })
          
    })
  1. Unbinding
    • Function: getTokenB2B2C
    app.post('/token-b2b2c', async (req,res) => {
        <!--YOUR_AUTH_CODE_FROM_ACCOUNT_BINDING-->
      let authCode = req.body['authCode'];
      await snap.getTokenB2B2c(authCode).then((response)=>{
       
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          res.status(500).send({"message":err.message});
        }
      })
     })
    • Function: doAccountUnbinding
    const {AccountUnbindingRequestDto,AccountUnbindingAdditionalInfo} = require('doku-nodejs-library/_models/accountUnbindingRequestDTO');
       
    app.post("/account-unbinding", async (req,res)=>{
      let request = new AccountUnbindingRequestDto()
      let additionalInfo = new AccountUnbindingAdditionalInfo(req.body.additionalInfo.channel)
      request.tokenId = req.body.tokenId;
      request.additionalInfo = additionalInfo;
      let ipAddress = req.headers['x-ip-address'];
      await snap.doAccountUnbinding(request,ipAddress).then((response)=>{
       
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          res.status(500).send({"message":err.message});
        }
      })
    })

II. Card Registration

  1. Registration

    • Function: doCardRegistration
    const CardRegistrationRequestDTO = require('doku-nodejs-library/_models/cardRegistrationRequestDTO');
       
    app.post("/card-registration", async (req,res)=>{
      let request = new CardRegistrationRequestDTO()
      request.cardData = req.body.cardData;
      request.custIdMerchant = req.body.custIdMerchant;
      request.phoneNo = req.body.phoneNo;
      request.additionalInfo = req.body.additionalInfo;
      console.log(request)
      await snap.doRegistrationCardBind(request).then((response)=>{
        res.status(200).send(response.data);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          console.log(err)
          res.status(500).send({"message":err.message});
        }
          
      })
    })
  2. UnRegistration

    • Function: getTokenB2B2C
    app.post('/token-b2b2c', async (req,res) => {
        <!--YOUR_AUTH_CODE_FROM_ACCOUNT_BINDING-->
      let authCode = req.body['authCode'];
      await snap.getTokenB2B2c(authCode).then((response)=>{
       
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          res.status(500).send({"message":err.message});
        }
      })
     })
    • Function: doCardUnbinding
    const CardUnRegistUnbindRequestDTO= require('doku-nodejs-library/_models/cardUnregistUnbindRequestDTO');
         
    app.post("/card-unbinding", async (req,res)=>{
      let request = new CardUnRegistUnbindRequestDTO(req.body.tokenId,
        req.body.additionalInfo
      )
         
      await snap.doUnRegistCardUnBind(request).then((response)=>{
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          console.log(err)
          res.status(500).send({"message":err.message});
        }
          
      })
    })

C. Direct Debit and E-Wallet

I. Request Payment

Once a customer’s account or card is successfully register/bind, the merchant can send a payment request. This section describes how to send a unified request that works for both Direct Debit and E-Wallet channels.

| Acquirer | Channel Name | |-------------------|--------------------------| | Allo Bank | DIRECT_DEBIT_ALLO_SNAP | | BRI | DIRECT_DEBIT_BRI_SNAP | | CIMB | DIRECT_DEBIT_CIMB_SNAP | | OVO | EMONEY_OVO_SNAP |

Common parameter
Allo Bank Specific Parameters

| Parameter | Description | Required | |--------------------------------------|---------------------------------------------------------------|--------------| | additionalInfo.remarks | Remarks from the partner | ✅ | | additionalInfo.lineItems.name | Item name (String) | ✅ | | additionalInfo.lineItems.price | Item price (ISO 4217) | ✅ | | additionalInfo.lineItems.quantity | Item quantity (Integer) | ✅ | | payOptionDetails.payMethod | Balance type (options: BALANCE/POINT/PAYLATER) | ✅ | | payOptionDetails.transAmount.value | Transaction amount | ✅ | | payOptionDetails.transAmount.currency | Currency (ISO 4217, e.g., "IDR") | ✅ |

CIMB Specific Parameters

| Parameter | Description | Required | |--------------------------------------|---------------------------------------------------------------|--------------| | additionalInfo.remarks | Remarks from the partner | ✅ |

OVO Specific Parameters

| Parameter | Description | Required | |------------------------------------------|---------------------------------------------------------------|--------------| | feeType | Fee type from partner (values: OUR, BEN, SHA) | ❌ | | payOptionDetails.payMethod | Payment method format: CASH, POINTS | ✅ | | payOptionDetails.transAmount.value | Transaction amount (ISO 4217) | ✅ | | payOptionDetails.transAmount.currency | Currency (ISO 4217, e.g., "IDR") | ✅ | | payOptionDetails.feeAmount.value | Fee amount (if applicable) | ✅ | | payOptionDetails.feeAmount.currency | Currency for the fee | ✅ | | additionalInfo.paymentType | Transaction type (values: SALE, RECURRING) | ✅ |

Here’s how you can use the doPayment function for both payment types:

  • Function: doPayment

    const { PaymentRequestDto } = require('doku-nodejs-library/_models/paymentRequestDirectDebitDTO');
        
     app.post("/debit-payment", async (req,res)=>{
          let request = new PaymentRequestDto()
          request.payOptionDetails = req.body.payOptionDetails;
          request.partnerReferenceNo = req.body.partnerReferenceNo;
          request.amount = req.body.amount;
          request.additionalInfo = req.body.additionalInfo;
          let ipAddress = req.headers['x-ip-address'];
          let authCode = req.body['authCode'];
          await snap.doPayment(request,authCode,ipAddress).then((response)=>{
            res.status(200).send(response);
          }).catch((err)=>{
            if(err.response?.data){
              res.status(err.response.status).send(err.response.data);
            }else{
              res.status(500).send({"message":err.message});
            }
               
          })
        })

II. Request Payment Jump APP

| Acquirer | Channel Name | |-------------------|--------------------------| | DANA | EMONEY_DANA_SNAP | | ShopeePay | EMONEY_SHOPEE_PAY_SNAP |

The following fields are common across DANA and ShopeePay requests:

DANA

DANA spesific parameters

  • Function: doPaymentJumpApp
    const PaymentJumpAppRequestDto = require('doku-nodejs-library/_models/paymentJumpAppRequestDTO');
    
    app.post("/payment-jump-app", async (req,res)=>{
      let request = new PaymentJumpAppRequestDto()
      request.partnerReferenceNo = req.body.partnerReferenceNo;
      request.pointOfInitiation = req.body.pointOfInitiation;
      request.urlParam = req.body.urlParam;
      request.amount = req.body.amount;
      request.additionalInfo = req.body.additionalInfo;
      request.validUpto = req.body.validUpto;
      let ipAddress = req.headers['x-ip-address'];
      let deviceId = req.headers['x-device-id'];
      await snap.doPaymentJumpApp(request,ipAddress,deviceId).then((response)=>{
        res.status(200).send(response);
      }).catch((err)=>{
        if(err.response?.data){
          res.status(err.response.status).send(err.response.data);
        }else{
          res.status(500).send({"message":err.message});
        }
       
      })
    })

3. Other Operation

A. Check Transaction Status

const CheckStatusDirectDebitDTO = require('doku-nodejs-library/_models/checkStatusDirectDebitRequestDTO');

 app.post('/debit-status', async (req,res) => {
    let request = new CheckStatusDirectDebitDTO()
    request.originalExternalId = req.body.originalExternalId
    request.originalPartnerReferenceNo= req.body.originalPartnerReferenceNo
    request.originalReferenceNo = req.body.originalReferenceNo
    request.serviceCode = req.body.serviceCode
    request.transactionDate= req.body.transactionDate
    request.amount = req.body.amount
    request.merchantId = req.body.merchantId
    request.subMerchantId = req.body.subMerchantId
    request.externalStoreId= req.body.externalStoreId
    request.additionalInfo= req.body.additionalInfo
    await snap.doCheckStatus(request).then(response=>{
      res.status(200).send(response);
    }).catch((err)=>{
      if(err.response){
        res.status(400).send(err.response.data)
      }else{
        res.status(400).send({
          responseCode:"400",
          responseMessage:err.message
        })
      }
    })
})

B. Refund

const RefundRequestDto = require('doku-nodejs-library/_models/refundRequestDTO');

app.post("/refund", async (req,res)=>{
    let request = new RefundRequestDto();
    request.originalPartnerReferenceNo = req.body.originalPartnerReferenceNo;
    request.refundAmount = req.body.refundAmount;
    request.partnerRefundNo = req.body.partnerRefundNo;
    request.originalExternalId = req.body.originalExternalId;
    request.reason = req.body.reason;
    request.additionalInfo = req.body.additionalInfo;
    let ipAddress = req.headers['x-ip-address'];
    let authCode = req.body['authCode'];
    let deviceId = req.headers['deviceId'];
    await snap.doRefund(request,authCode,ipAddress,deviceId).then((response)=>{
      res.status(200).send(response);
    }).catch((err)=>{
      if(err.response?.data){
        res.status(err.response.status).send(err.response.data);
      }else{
        res.status(500).send({"message":err.message});
      }
     
    })
})

C. Balance Inquiry

const BalanceInquiryRequestDto = require('doku-nodejs-library/_models/balanceInquiryRequestDTO');

app.post("/balance-inquiry", async (req,res)=>{
    let request = new BalanceInquiryRequestDto();
    request.additionalInfo = req.body.additionalInfo
    let ipAddress = req.headers['x-ip-address'];
    let authCode = req.body['authCode'];
    await snap.doBalanceInquiry(request,authCode,ipAddress).then((response)=>{
      res.status(200).send(response);
    }).catch((err)=>{
      if(err.response?.data){
        res.status(err.response.status).send(err.response.data);
      }else{
        res.status(500).send({"message":err.message});
      }
     
    })
})

4. Error Handling and Troubleshooting

The SDK throws exceptions for various error conditions. Always wrap your API calls in try-catch blocks:

 await snap.createVa(createVaRequestDto).then(va=>{
   res.status(200).send(va);
 }).catch(err=>{
     if(err.response){
         res.status(400).send(err.response.data)
     }else{
       res.status(400).send({
         responseCode:"400",
         responseMessage:err.message
       })
     }
   
 })

This section provides common errors and solutions:

| Error Code | Description | Solution | |------------|---------------------------------------|----------------------------------------------| | 4010000 | Unauthorized | Check if Client ID and Secret Key are valid. | | 4012400 | Virtual Account Not Found | Verify the virtual account number provided. | | 2002400 | Successful | Transaction completed successfully. |