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

@rikology/adonisjs-midtrans

v0.1.0

Published

AdonisJS v7 package for Midtrans payment gateway integration (Snap, Core API, Iris)

Readme

@rikology/adonisjs-midtrans

npm version license: MIT node checks

AdonisJS v7 package for Midtrans payment gateway integration. Supports Snap checkout, Core API (credit card, bank transfer, e-wallet, c-store, BNPL), transaction management, Iris disbursement, and webhook verification.

Features

  • Snap – Redirect checkout with Midtrans payment page
  • Core API – Direct charge for credit card, bank transfer (BCA, BNI, BRI, Mandiri, Permata, CIMB), GoPay, ShopeePay, QRIS, convenience store (Indomaret / Alfamart), and BNPL (Akulaku / Kredivo)
  • Transaction management – Check status, cancel, refund, expire, and approve transactions
  • Iris disbursement – Payouts to bank accounts when irisKey is configured
  • Webhook helpers – Signature verification, typed notification parsing, and status predicates
  • Typed errors – Granular error classes for HTTP, API, validation, and signature failures
  • AdonisJS native – Provider registration, configure hook, and IoC container singleton

Table of contents

Requirements

  • Node.js >= 24
  • AdonisJS v7

Installation

npm install @rikology/adonisjs-midtrans
node ace configure @rikology/adonisjs-midtrans

The configure command interactively prompts for your keys, creates config/midtrans.ts, injects environment variables, and registers the provider in adonisrc.ts.

Configuration

Environment variables

Add these to your .env file:

MIDTRANS_SERVER_KEY=SB-Mid-server-xxx
MIDTRANS_CLIENT_KEY=SB-Mid-client-xxx
MIDTRANS_IRIS_KEY=your-iris-key          # optional, only for disbursement
MIDTRANS_SANDBOX=true                    # true for sandbox, false for production
MIDTRANS_TIMEOUT=30000                   # request timeout in ms (minimum 1000)
MIDTRANS_DEBUG=false                     # enable HTTP request logging

Update env.ts to validate them:

export default Env.create(new URL('.', import.meta.url), {
  MIDTRANS_SERVER_KEY: Env.schema.string(),
  MIDTRANS_CLIENT_KEY: Env.schema.string.optional(),
  MIDTRANS_IRIS_KEY: Env.schema.string.optional(),
  MIDTRANS_SANDBOX: Env.schema.boolean(),
  MIDTRANS_TIMEOUT: Env.schema.number.optional(),
  MIDTRANS_DEBUG: Env.schema.boolean.optional(),
})

Config file

The config lives in config/midtrans.ts. Use the defineConfig helper for type safety and validation:

import { defineConfig } from '@rikology/adonisjs-midtrans/define_config'
import env from '#start/env'

export default defineConfig({
  serverKey: env.get('MIDTRANS_SERVER_KEY'),
  clientKey: env.get('MIDTRANS_CLIENT_KEY'),
  irisKey: env.get('MIDTRANS_IRIS_KEY'),
  sandbox: env.get('MIDTRANS_SANDBOX'),
  timeout: env.get('MIDTRANS_TIMEOUT'),
  debug: env.get('MIDTRANS_DEBUG'),
})

defineConfig validates your input and applies defaults:

| Option | Required | Default | Description | | ----------- | -------- | --------- | ------------------------------------- | | serverKey | yes | - | Midtrans server key | | clientKey | no | undefined | Midtrans client key | | irisKey | no | undefined | Iris API key (enables disbursement) | | sandbox | no | false | Use sandbox environment | | timeout | no | 30000 | HTTP request timeout in ms (min 1000) | | debug | no | false | Log HTTP requests (keys redacted) |

Usage

Resolve the Midtrans manager from the IoC container:

import { MidtransManager } from '@rikology/adonisjs-midtrans'

const midtrans = await app.container.make(MidtransManager)

The manager exposes three clients: snap, core, and iris (optional).

Snap (redirect checkout)

Create a Snap transaction and redirect the user to the payment page:

const response = await midtrans.snap.createTransaction({
  transaction_details: {
    order_id: 'ORDER-123',
    gross_amount: 50000,
  },
  item_details: [{ id: 'item-1', price: 50000, quantity: 1, name: 'Coffee Beans' }],
  customer_details: {
    first_name: 'John',
    last_name: 'Doe',
    email: '[email protected]',
    phone: '+6281234567890',
  },
})

// response.token - pass to MidtransSnap.js on frontend
// response.redirect_url - redirect user here

You can also restrict payment methods with enabled_payments:

const response = await midtrans.snap.createTransaction({
  transaction_details: { order_id: 'ORDER-124', gross_amount: 100000 },
  enabled_payments: ['gopay', 'bca_va', 'indomaret'],
})

Core API

The Core API gives you full control over individual payment methods.

Credit card

const charge = await midtrans.core.charge(
  midtrans.core.createCreditCardCharge('ORDER-200', 100000, {
    token_id: 'token-from-midtrans-js',
    secure: true,
  })
)

Bank transfer (virtual account)

Supports BCA, BNI, BRI, Mandiri, Permata, and CIMB:

const charge = await midtrans.core.charge(
  midtrans.core.createBankTransferCharge('ORDER-201', 75000, 'bca')
)

// With a custom VA number:
const charge2 = await midtrans.core.charge(
  midtrans.core.createBankTransferCharge('ORDER-202', 75000, 'bca', '111222333444')
)

GoPay

const charge = await midtrans.core.charge(
  midtrans.core.createGoPayCharge('ORDER-203', 50000, 'https://myapp.com/gopay-callback')
)

ShopeePay

const charge = await midtrans.core.charge(
  midtrans.core.createShopeepayCharge('ORDER-204', 60000, 'https://myapp.com/shopeepay-callback')
)

QRIS

const charge = await midtrans.core.charge(midtrans.core.createQrisCharge('ORDER-205', 25000))

Convenience store (Indomaret / Alfamart)

const charge = await midtrans.core.charge(
  midtrans.core.createCStoreCharge('ORDER-206', 30000, 'indomaret', 'Payment for order 206')
)

BNPL (Akulaku / Kredivo)

const charge = await midtrans.core.charge(midtrans.core.createAkulakuCharge('ORDER-207', 200000))

const charge2 = await midtrans.core.charge(midtrans.core.createKredivoCharge('ORDER-208', 150000))

Transaction management

// Check status
const status = await midtrans.core.status('ORDER-123')

// Cancel a transaction
await midtrans.core.cancel('ORDER-123')

// Refund (full or partial)
await midtrans.core.refund('ORDER-123')
await midtrans.core.refund('ORDER-123', { amount: 50000, reason: 'Partial refund' })

// Expire a pending transaction
await midtrans.core.expire('ORDER-123')

// Approve a challenged transaction
await midtrans.core.approve('ORDER-123')

Iris disbursement

Iris is only available when irisKey is configured. The midtrans.iris property will be undefined otherwise.

if (midtrans.iris) {
  const disbursement = await midtrans.iris.createDisbursement({
    bank_account: {
      bank: 'bca',
      account: '1234567890',
      name: 'John Doe',
    },
    amount: 1000000,
    reference_no: 'DISB-001',
    notes: 'March payout',
  })

  // Check status
  const status = await midtrans.iris.getDisbursementStatus(disbursement.disbursement_id)

  // Approve with OTP
  await midtrans.iris.approveDisbursement({
    disbursement_id: disbursement.disbursement_id,
    otp: '123456',
  })
}

Webhook handling

Import helpers from the package to verify and parse incoming notifications:

import {
  validateSignature,
  parseNotification,
  isTransactionSuccess,
} from '@rikology/adonisjs-midtrans'

In your webhook route:

router.post('/midtrans/webhook', async ({ request, response, env }) => {
  const body = request.body() as Record<string, string>

  // Verify the signature first
  const isValid = validateSignature(body, env.get('MIDTRANS_SERVER_KEY'))
  if (!isValid) {
    return response.unauthorized('Invalid signature')
  }

  // Parse into typed notification
  const notification = parseNotification(body)

  // Handle based on transaction status
  if (isTransactionSuccess(notification)) {
    // Fulfill the order
    await Order.markPaid(notification.order_id)
  }
})

isTransactionSuccess returns true when transaction_status is "settlement" or "capture". These are the only statuses where you should fulfill an order.

Error handling

The package provides a typed error hierarchy. All errors extend MidtransError.

| Error class | When it occurs | | ------------------------- | --------------------------------------------- | | MidtransError | Base class for all Midtrans errors | | MidtransHTTPError | Network or server errors (5xx, timeouts) | | MidtransAPIError | Midtrans API rejections (4xx with validation) | | MidtransValidationError | Invalid config input in defineConfig | | MidtransSignatureError | Webhook signature verification failure |

Catch specific errors to handle different failure modes:

import {
  MidtransAPIError,
  MidtransHTTPError,
  MidtransValidationError,
} from '@rikology/adonisjs-midtrans'

try {
  const charge = await midtrans.core.charge(params)
} catch (error) {
  if (error instanceof MidtransAPIError) {
    // Midtrans rejected the request
    console.log(error.statusCode) // e.g. 400
    console.log(error.statusMessage) // e.g. "Invalid transaction details"
    console.log(error.errorMessages) // e.g. ["gross_amount is required"]
  } else if (error instanceof MidtransHTTPError) {
    // Network or server error
    console.log(error.statusCode) // e.g. 500
    console.log(error.requestUrl) // the URL that failed
    console.log(error.requestMethod) // "POST"
  } else if (error instanceof MidtransValidationError) {
    // Config validation failed
    console.log(error.field) // e.g. "serverKey"
  }
}

All error toJSON() methods exclude sensitive data like server keys.

Safe config access

Use safeConfig to expose configuration without leaking keys:

const config = midtrans.safeConfig
// { sandbox: true, timeout: 30000, debug: false }
// serverKey and irisKey are excluded

Documentation

Links

Contributing

Contributions are welcome. Before opening a pull request, please make sure the test suite passes:

# Install dependencies
npm install

# Run lint, typecheck, and tests
npm test

# Build
npm run build

All changes should include tests where applicable.

License

MIT. See LICENSE.md for details.