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

bjb-qrismpm-sdk-node

v1.0.7

Published

BJB QRIS MPM SDK for Node.js — SNAP BI standard integration via IBM API Connect

Downloads

74

Readme

BJB QRIS MPM SDK — Node.js

Backend SDK for integrating with Bank BJB Open API (SNAP BI standard) for QRIS Merchant Presented Mode (MPM) payments via IBM API Connect.

Installation

npm install bjb-qrismpm-sdk-node

Quick Start

const { QrisMpmService, CallbackVerifier, parseCallback } = require('bjb-qrismpm-sdk-node');
const fs = require('fs');

const qrisService = new QrisMpmService({
  baseUrl: process.env.BJB_BASE_URL,
  clientId: process.env.BJB_CLIENT_ID,
  clientSecret: process.env.BJB_CLIENT_SECRET,
  channelId: process.env.BJB_CHANNEL_ID,
  privateKey: fs.readFileSync('./keys/private-key.pem', 'utf8'),
  logger: console.log, // optional
});

Generate QR Code

const result = await qrisService.generateQr({
  partnerReferenceNo: 'ORDER-001',
  amount: { value: '12000', currency: 'IDR' },
  feeAmount: { value: '0.00', currency: 'IDR' },
  merchantId: '825670157598976',
  subMerchantId: '-',
  storeId: '-',
  terminalId: '825670157598976',
  validityPeriod: '2026-12-31T23:59:59+07:00',
  additionalInfo: {
    paymentId: 1,
    merchantCode: '6282120596296',
    backendUrl: 'https://your-domain.com/api/v1/callback/qris-mpm',
    channelId: '3',
    transactionPurpose: '3rd party merchant payment',
  },
});

console.log(result.qrContent);        // QR string
console.log(result.referenceNo);       // BJB reference (use for check status)
console.log(result.partnerReferenceNo); // your reference

Response

{
  "responseCode": "2004700",
  "responseMessage": "Success",
  "referenceNo": "523925829312",
  "partnerReferenceNo": "ORDER-001",
  "qrContent": "00020101021226690017ID.CO.BANKBJB.WWW...",
  "merchantName": "SAMBARA PROV JABAR",
  "terminalId": "825670157598976"
}

Check Transaction Status

const status = await qrisService.checkStatus({
  originalReferenceNo: '523925829312',          // from generateQr response
  originalPartnerReferenceNo: 'ORDER-001',
  serviceCode: '50',
  merchantId: '825670157598976',
  additionalInfo: {
    PaymentId: 1,
    MerchantCode: '6282120596296',
    Currency: 'IDR',
  },
});

console.log(status.latestTransactionStatus); // "00" = paid
console.log(status.paidTime);

Transaction Status Codes

| Status | Description | |--------|-------------| | 00 | Success / Paid | | 01 | Initiated | | 03 | Pending | | 05 | Cancelled | | 06 | Failed |


Callback Verification

BJB sends a POST to your server when payment is completed. Use CallbackVerifier to verify the signature.

const { CallbackVerifier, parseCallback } = require('bjb-qrismpm-sdk-node');

const verifier = new CallbackVerifier({
  clientSecret: process.env.BJB_CLIENT_SECRET,
});

app.post('/api/v1/callback/qris-mpm', (req, res) => {
  // 1. Verify signature
  const isValid = verifier.verify({
    method: 'POST',
    path: '/api/v1/callback/qris-mpm',
    accessToken: (req.headers['authorization'] || '').replace('Bearer ', ''),
    body: JSON.stringify(req.body),
    timestamp: req.headers['x-timestamp'],
    signature: req.headers['x-signature'],
  });

  if (!isValid) {
    return res.status(401).json({
      ResponseCode: '4015200',
      ResponseMessage: 'Unauthorized',
    });
  }

  // 2. Parse payment data
  const payment = parseCallback(req.body);
  console.log(payment.originalPartnerReferenceNo); // your order reference
  console.log(payment.latestTransactionStatus);     // "00" = paid
  console.log(payment.amount);                      // { value, currency }
  console.log(payment.additionalInfo.Rrn);          // bank reference

  // 3. Your business logic (update DB, notify user, etc.)

  // 4. Return success to BJB
  res.json({
    ResponseCode: '2005200',
    ResponseMessage: 'Request has been processed successfully',
  });
});

Callback Flow

Customer pays → BJB processes → BJB POSTs to your backendUrl
                                │
                                ├─ Authorization: Bearer {bjb_token}
                                ├─ X-TIMESTAMP: {timestamp}
                                ├─ X-SIGNATURE: {HMAC-SHA512, signed with YOUR clientSecret}
                                └─ Body: { payment data }
                                │
                        Your server:
                                ├─ Rebuild signature with same clientSecret
                                ├─ Compare (timing-safe)
                                ├─ If match → process payment
                                └─ Return 2005200

Parsed Callback Fields

| Field | Description | |-------|-------------| | originalPartnerReferenceNo | Your order reference | | originalReferenceNo | BJB reference | | merchantId | Merchant identifier | | amount | { value, currency } | | latestTransactionStatus | "00" = success | | additionalInfo.Rrn | Bank reference number | | additionalInfo.PaidTime | Payment timestamp |


Full Payment Flow

1. Generate QR     →  qrisService.generateQr(payload)
                       Returns: qrContent, referenceNo

2. Display QR      →  Show QR to customer (use qrContent with any QR library)

3. Customer pays   →  Customer scans QR with banking app

4. BJB callback    →  BJB POSTs to your backendUrl
                       You verify signature + process payment

5. Check status    →  qrisService.checkStatus(payload)  (optional polling)
                       Returns: latestTransactionStatus

Constructor Parameters

new QrisMpmService({
  baseUrl,        // string — BJB API Connect URL (required)
  clientId,       // string — API Connect client key (required)
  clientSecret,   // string — HMAC signing key (required)
  channelId,      // string — Channel identifier (required)
  privateKey,     // string — RSA private key PEM (required)
  logger,         // function — e.g. console.log (optional)
});

API Reference

| Export | Description | |--------|-------------| | QrisMpmService | Main service — generateQr(), checkStatus() | | CallbackVerifier | Verify incoming BJB callback signatures | | parseCallback | Extract key fields from callback payload | | SnapHttpClient | Low-level SNAP API HTTP client | | getAccessToken | Request B2B access token directly | | createAsymmetricSignature | SHA256withRSA signing → lowercase hex | | createSymmetricSignature | HMAC-SHA512 signing → lowercase hex | | SnapError | Error class with responseCode / responseMessage |


Error Handling

const { SnapError } = require('bjb-qrismpm-sdk-node');

try {
  const result = await qrisService.generateQr(payload);
} catch (err) {
  if (err instanceof SnapError) {
    console.log(err.responseCode);    // "4014700"
    console.log(err.responseMessage); // "Unauthorized. Signature mismatch"
    console.log(err.toJSON());        // { responseCode, responseMessage }
  }
}

Error Codes

| Code | Description | |------|-------------| | 2007300 | Access token granted | | 2004700 | QR generated successfully | | 2005100 | Status check successful | | 2005200 | Callback processed | | 4004700 | Bad request | | 4014700 | Unauthorized / Signature mismatch | | 4044700 | Transaction not found | | 4044708 | Invalid merchant | | 5004700 | General error |


Logging

Pass a logger function to see full request/response details:

const qrisService = new QrisMpmService({
  ...config,
  logger: console.log,
});

Output:

[a1b2c3d4] service=QRIS_MPM action=GENERATE_QR
[a1b2c3d4] service=TOKEN action=REQUEST url=https://devapi.bankbjb.co.id/api/v1/access-token/b2b
[a1b2c3d4] service=TOKEN action=REQUEST_HEADERS {"Content-Type":"application/json","X-CLIENT-KEY":"..."}
[a1b2c3d4] service=TOKEN action=REQUEST_BODY {"grantType":"client_credentials"}
[a1b2c3d4] service=TOKEN action=RESPONSE responseCode=2007300
[a1b2c3d4] service=TOKEN action=RESPONSE_BODY {"accessToken":"AAIg...","expiresIn":3600}
[a1b2c3d4] service=SNAP_API action=REQUEST url=https://devapi.bankbjb.co.id/v1.0/qr/qr-mpm-generate
[a1b2c3d4] service=SNAP_API action=REQUEST_HEADERS {"Authorization":"Bearer AAIg...","X-SIGNATURE":"..."}
[a1b2c3d4] service=SNAP_API action=REQUEST_BODY {"partnerReferenceNo":"ORDER-001",...}
[a1b2c3d4] service=SNAP_API action=RESPONSE status=200 responseCode=2004700
[a1b2c3d4] service=SNAP_API action=RESPONSE_BODY {"qrContent":"0002010102..."}

Environments

| Environment | Base URL | |-------------|----------| | Development | https://devapi.bankbjb.co.id |

Dev environment uses a self-signed certificate — the SDK automatically skips SSL verification when the base URL contains devapi.


License

ISC