Skip to content

Joselay/aba-payway

Repository files navigation

aba-payway

npm version CI License: MIT npm downloads Zero Dependencies

Type-safe TypeScript SDK for ABA PayWay — Cambodia's #1 payment gateway.

Unofficial community SDK. Not affiliated with ABA Bank.

Why aba-payway?

ABA PayWay's official SDK is a raw REST API with no official Node.js/TypeScript client. That means you're left dealing with manual HMAC hashing, snake_case field ordering, base64 encoding, and zero type safety. This SDK handles all of that for you.

aba-payway Rolling your own
Type safety Full TypeScript with strict types None — guess the field names
Hash computation Automatic, correct field ordering Manual HMAC-SHA512, easy to get wrong
Base64 encoding Automatic for items, URLs, payout Do it yourself, hope you didn't miss one
Dependencies Zero — only Node.js built-ins Probably axios + crypto-js + glue code
API coverage 15+ methods Build each one from scratch
Runtime support Node.js, Bun, Deno, Cloudflare Workers Whatever you tested

Features

  • Zero runtime dependencies — uses Node.js built-in crypto and native fetch
  • Full TypeScript support with strict types and autocomplete
  • Dual ESM + CJS output — works everywhere
  • 15+ API methods — checkout, QR payments, refunds, pre-auth, payouts, and more
  • Runs anywhere — Node.js, Bun, Deno, Next.js, Express, Hono, Cloudflare Workers
  • Tested against ABA's sandbox — not just unit tests, real API integration tests

Installation

# bun
bun add aba-payway

# npm
npm install aba-payway

# pnpm
pnpm add aba-payway

Quick Start

import { PayWay } from 'aba-payway'

const payway = new PayWay({
  merchantId: 'your_merchant_id',
  apiKey: 'your_api_key',
})

// Generate checkout params (synchronous — no API call)
const params = payway.createTransaction({
  transactionId: 'order-001',
  amount: 10.00,
  items: 'Product A',
  returnUrl: 'https://yoursite.com/callback',
})

// Send `params` to your frontend, populate ABA's hidden form,
// and call AbaPayway.checkout() to open the payment dialog.
// See examples/ for more snippets and framework integrations.

API Reference

new PayWay(config)

Parameter Type Required Default Description
merchantId string Yes Your ABA PayWay merchant ID
apiKey string Yes Your ABA PayWay API key
environment 'sandbox' | 'production' No 'sandbox' Target environment
baseUrl string No Override the base URL directly (takes priority over environment)

payway.createTransaction(options)

Generate checkout parameters for a payment. Synchronous — computes the HMAC hash and returns form params without making any API calls.

Returns CheckoutParams — snake_case form parameters to submit via ABA's checkout JS SDK.

Parameter Type Required Description
transactionId string Yes Unique transaction ID (max 20 chars)
amount number Yes Purchase amount
currency 'USD' | 'KHR' No Default: 'USD'
paymentOption PaymentOption No cards, abapay_khqr, abapay_khqr_deeplink, alipay, wechat, google_pay
firstName string No Buyer's first name
lastName string No Buyer's last name
email string No Buyer's email
phone string No Buyer's phone
items string | ItemEntry[] No Item description — string or { name, quantity, price }[]
returnUrl string No Callback URL for payment completion
cancelUrl string No Redirect URL when user closes payment
continueSuccessUrl string No Redirect URL after success
type 'purchase' | 'pre-auth' No Default: 'purchase'
shipping number No Shipping fee
viewType string No 'hosted_view' or 'popup'
lifetime number No Payment lifetime in minutes (3–43200)
skipSuccessPage number No 0 (don't skip) or 1 (skip)
payout string No Payout details (JSON string)
returnDeeplink string No Mobile app deeplink
googlePayToken string No Required if paymentOption is 'google_pay'

items, returnUrl, returnDeeplink, and payout are automatically base64-encoded by the SDK.

payway.checkTransaction(transactionId)

Check the status of a transaction.

const result = await payway.checkTransaction('order-001')
console.log(result.status.code)          // '00' = success
console.log(result.data?.payment_status) // 'APPROVED' | 'DECLINED' | 'PENDING' | ...

payway.listTransactions(options?)

List transactions with optional filters. Max 3-day date range.

const list = await payway.listTransactions({
  fromDate: '2026-03-01 00:00:00',
  toDate: '2026-03-03 23:59:59',
  status: 'APPROVED',
  page: 1,
  pagination: 20,
})
Parameter Type Description
fromDate string Start date: 'YYYY-MM-DD HH:mm:ss'
toDate string End date: 'YYYY-MM-DD HH:mm:ss'
fromAmount number Minimum amount filter
toAmount number Maximum amount filter
status string Comma-separated: APPROVED, DECLINED, PENDING, PRE-AUTH, CANCELLED, REFUNDED
page number Page number (default: 1)
pagination number Records per page (default: 40, max: 1000)

payway.getTransactionDetails(transactionId)

Get detailed information about a transaction, including its operation history.

const details = await payway.getTransactionDetails('order-001')
console.log(details.data?.payment_status)            // 'APPROVED'
console.log(details.data?.transaction_operations)     // [{ status, amount, ... }]

payway.closeTransaction(transactionId)

Close (cancel) a pending transaction. The payment status becomes CANCELLED.

const result = await payway.closeTransaction('order-001')
console.log(result.status.code) // '00' = success

payway.getExchangeRate()

Fetch the latest exchange rates from ABA Bank for 12 currencies.

const rates = await payway.getExchangeRate()
console.log(rates.exchange_rates.eur) // { sell: '...', buy: '...' }

payway.generateQR(options)

Generate a dynamic QR code for payment via ABA KHQR, WeChat Pay, or Alipay.

const qr = await payway.generateQR({
  transactionId: 'qr-001',
  amount: 10.00,
  paymentOption: 'abapay_khqr',
  qrImageTemplate: 'template1',
  lifetime: 30,
})
console.log(qr.qrString)         // QR content string
console.log(qr.abapay_deeplink)  // ABA Mobile deep link
Parameter Type Required Description
transactionId string Yes Unique transaction ID (max 20 chars)
amount number Yes Payment amount (min: 100 KHR or 0.01 USD)
paymentOption QRPaymentOption Yes abapay_khqr, wechat (USD only), alipay (USD only)
qrImageTemplate string Yes QR image template name
currency 'USD' | 'KHR' No Default: 'USD'
lifetime number No Lifetime in minutes (3–43200)
firstName string No Payer's first name
lastName string No Payer's last name
email string No Payer's email
phone string No Payer's phone
purchaseType 'purchase' | 'pre-auth' No Default: 'purchase'
items string No Item description (auto base64-encoded)
callbackUrl string No Payment callback URL (auto base64-encoded)
returnDeeplink string No Mobile deeplink (auto base64-encoded)
payout string No Payout JSON string (auto base64-encoded)

payway.getTransactionsByRef(merchantRef)

Get transactions by merchant reference. Returns up to the last 50 transactions.

const txns = await payway.getTransactionsByRef('REF-001')
for (const txn of txns.data) {
  console.log(txn.transaction_id, txn.payment_status)
}

## Error Handling

```typescript
import { PayWay, PayWayAPIError, PayWayConfigError } from 'aba-payway'
Error Class When Thrown
PayWayConfigError Missing or invalid constructor config
PayWayAPIError ABA API returns non-2xx response (has statusCode and responseBody properties)
PayWayError Base error class
PayWayHashError Hash generation failure

Framework Examples

Next.js (App Router)

// app/api/pay/route.ts
import { PayWay } from 'aba-payway'

const payway = new PayWay({
  merchantId: process.env.PAYWAY_MERCHANT_ID!,
  apiKey: process.env.PAYWAY_API_KEY!,
  environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox',
})

export async function POST(request: Request) {
  const { orderId, amount } = await request.json()

  const params = payway.createTransaction({
    transactionId: orderId,
    amount,
    items: 'Order payment',
    returnUrl: `${process.env.NEXT_PUBLIC_URL}/api/pay/callback`,
  })

  return Response.json(params)
}

Express

import express from 'express'
import { PayWay } from 'aba-payway'

const app = express()
app.use(express.json())

const payway = new PayWay({
  merchantId: process.env.PAYWAY_MERCHANT_ID!,
  apiKey: process.env.PAYWAY_API_KEY!,
})

app.post('/pay', (req, res) => {
  const params = payway.createTransaction({
    transactionId: req.body.orderId,
    amount: req.body.amount,
    items: 'Order payment',
    returnUrl: 'https://yoursite.com/callback',
  })
  res.json(params)
})

Sandbox Test Cards

Card Number Expiry CVV Result
Mastercard 5156 8399 3770 6777 01/30 993 Approved
Visa 4286 0900 0000 0206 04/30 777 Approved
Mastercard 5156 8302 7256 1029 04/30 777 Declined
Visa 4156 8399 3770 6777 01/30 993 Declined

Documentation

For the full ABA PayWay API documentation, see aba-payway-docs.

Contributing

Found a bug or have a feature request? Open an issue — all feedback is welcome.

Pull requests are also welcome. Please make sure tests pass before submitting:

bun run test
bun run typecheck
bun run lint

License

MIT

About

TypeScript SDK for ABA PayWay — Cambodia's payment gateway. Zero dependencies, full TypeScript support, ESM/CJS.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors