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

pay2s-node

v0.3.0

Published

Node.js SDK for the Pay2S payment gateway, callbacks, IPN, and webhooks

Readme

pay2s-node

SDK Node.js cho Pay2S Payment API, Payment Notification/IPN và raw webhook.

Cài đặt

npm install pay2s-node

Yêu cầu Node.js >=18.18.0.

Khởi tạo client

import { Pay2sClient } from 'pay2s-node'

const client = new Pay2sClient({
  environment: 'sandbox',
  accessKey: process.env.PAY2S_ACCESS_KEY,
  partnerCode: process.env.PAY2S_PARTNER_CODE,
  secretKey: process.env.PAY2S_SECRET_KEY,
  timeout: 10_000,
})

environment tự chọn endpoint chính thức:

  • Sandbox: https://sandbox-payment.pay2s.vn
  • Production: https://payment.pay2s.vn

Có thể dùng baseUrlfetch để test hoặc chạy qua HTTP adapter riêng.

Tạo payment

Với flow thanh toán một lần thông thường, có thể dùng helper ngắn hơn. SDK tự điền các giá trị mặc định requestId=orderId, orderType=pay2s, requestType=pay2sbankAccounts=[]:

const payment = await client.createOneTimePayment({
  orderId: 'ORDER10001',
  amount: 50000,
  orderInfo: 'ThanhToan10001',
  redirectUrl: 'https://merchant.example/payment/return',
  ipnUrl: 'https://merchant.example/payment/ipn',
})

const paymentUrl = client.checkout.getPaymentUrl(payment)
// redirect người mua tới paymentUrl

Nếu account trả về tên field khác cho URL, helper vẫn nhận các dạng phổ biến paymentUrl, payment_url, payUrlcheckoutUrl. Dùng createPayment() bên dưới khi cần truyền toàn bộ field Pay2S và kiểm soát requestId riêng.

const payment = await client.createPayment({
  partnerName: 'Demo Merchant',
  requestId: 'REQ1000001',
  amount: 50000,
  orderId: 'ORDER10001',
  orderInfo: 'ThanhToan10001',
  orderType: 'pay2s',
  redirectUrl: 'https://merchant.example/payment/return',
  ipnUrl: 'https://merchant.example/payment/ipn',
  requestType: 'pay2s',
  bankAccounts: [],
  extraData: '',
})

SDK tự tạo signature theo canonical field order của Pay2S và giữ nguyên bankAccounts=Array khi ký. Nếu truyền signature, SDK sẽ kiểm tra chữ ký trước khi gửi request. SDK hiện validate orderInfo là 10-32 ký tự ASCII letters/digits; hãy đối chiếu constraint này với contract của account trước khi dùng dữ liệu production.

Client payment và QR

const clientPayment = await client.createClientPayment({
  invoiceNumber: 'INV-100',
  invoiceId: 39,
  partnerCode: process.env.PAY2S_PARTNER_CODE,
  accessKey: process.env.PAY2S_ACCESS_KEY,
  orderId: 'ORDER10001',
  orderInfo: 'ThanhToan10001',
  amount: 50000,
  accountNumber: '123456789',
  ipnUrl: 'https://merchant.example/payment/ipn',
  redirectUrl: 'https://merchant.example/payment/return',
  requestId: 'REQ1000001',
  requestType: 'pay2s',
  signature: '<signature-from-pay2s-contract>',
})

const qr = await client.createQrCode({
  bankShortName: 'ACB',
  accountNumber: '123456789',
  accountName: 'DEMO MERCHANT',
  amount: 50000,
  memo: 'TEST10001',
})

Các method tương ứng với contract hiện có của Pay2S:

  • POST /v1/gateway/api/create
  • POST /api/create.php
  • POST /v1/gateway/create_qr

Bank Codes

const banks = await client.listBankCodes()

Method này gọi POST /v1/gateway/api/bankcodes. Nên cache có thời hạn và chọn bank code theo đúng environment/account.

OneQR

OneQR là API độc lập, dùng Basic Auth để lấy Bearer token rồi gọi các endpoint QR:

import { Pay2sOneQrClient } from 'pay2s-node'

const oneQr = new Pay2sOneQrClient({
  accessKey: process.env.PAY2S_ACCESS_KEY,
  secretKey: process.env.PAY2S_SECRET_KEY,
})

const qr = await oneQr.createQr('vcb', {
  orderId: 'ORDER10001',
  amount: 50000,
  merchantName: 'Demo Merchant',
  merchantId: 'MERCHANT_ID',
  terminalId: 'TERMINAL_ID',
  description: 'TEST PAYMENT',
})

Các method còn có listQr, getQrTransactioncancelQr. Host/path và quyền bank code phải đối chiếu contract account trước khi dùng Production.

Open Banking và Partner API

import { Pay2sOpenBankingClient, Pay2sPartnerClient } from 'pay2s-node'

const openBanking = new Pay2sOpenBankingClient({
  pay2sToken: process.env.PAY2S_TOKEN,
})
const recipient = await openBanking.getRecipientName({ accountNumber: '123456789', bankCode: '970436' })

const partner = new Pay2sPartnerClient({
  accessKey: process.env.PAY2S_ACCESS_KEY,
  secretKey: process.env.PAY2S_SECRET_KEY,
  analyticsToken: process.env.PAY2S_ANALYTICS_TOKEN,
})
const linkedBanks = await partner.listBanks()

Open Banking dùng header pay2s-token; Partner API tự lấy và cache Bearer token trong memory. Các operation quản lý bank, webhook và history/resend được expose trên Pay2sPartnerClient. Metrics yêu cầu truyền analyticsToken riêng vì tài liệu hiện chưa công bố ổn định flow cấp token Analytics.

Payment Notification và IPN

const notification = client.parsePaymentNotification(request.url)
client.verifyPaymentNotification(notification)

const ipn = client.parseIpn(request.body)
client.verifyIpn(ipn)

Luôn verify chữ ký trước khi cập nhật trạng thái đơn hàng. Việc chống xử lý callback trùng lặp thuộc application layer; nên dùng khóa idempotency như partnerCode:orderId:requestId:transId.

Raw webhook

Phải giữ nguyên raw request body trước khi JSON parse. verifyWebhook là HMAC helper generic; chỉ dùng khi contract Webhook của account xác nhận đúng header và secret:

import { parseWebhookEvent, verifyWebhook } from 'pay2s-node'

const signature = request.headers['x-signature']
if (typeof signature !== 'string') throw new Error('Missing webhook signature')

verifyWebhook(rawBodyBuffer, {
  secret: process.env.PAY2S_WEBHOOK_SECRET,
  signatureHeader: signature,
})

const event = parseWebhookEvent(rawBodyBuffer)

verifyWebhook hỗ trợ chữ ký hex HMAC-SHA256 dạng trực tiếp hoặc header dạng sha256=<hex>, so sánh constant-time và từ chối payload/chữ ký không hợp lệ. Header authentication không được mặc định là x-signature hoặc Authorization: Bearer; hãy đối chiếu contract account trước khi bật Production.

Với Technical/Partner Webhook dùng Bearer token của Pay2S:

import { parseTransactionWebhook, verifyWebhookBearerToken } from 'pay2s-node'

verifyWebhookBearerToken({
  authorizationHeader: request.headers.authorization,
  token: process.env.PAY2S_WEBHOOK_TOKEN,
})
const event = parseTransactionWebhook(rawBodyBuffer)

parseTransactionWebhook yêu cầu body có wrapper transactions; việc kiểm tra amount, account, checksum và idempotency vẫn thuộc application layer.

Typed responses

Các response export typed vẫn cho phép field mở rộng để tương thích contract theo account:

import type {
  CreateClientPaymentResponse,
  CreateQrCodeResponse,
  PaymentResponse,
} from 'pay2s-node'

function getPaymentUrl(response: CreateClientPaymentResponse) {
  return response.paymentUrl ?? response.payment_url
}

PaymentResponse, CreateClientPaymentResponseCreateQrCodeResponse expose các field phổ biến như requestId, orderId, resultCode, payment_urlqrUrl; field production phải đối chiếu API Reference.

Errors

Các error class được export gồm ValidationError, AuthenticationError, NetworkError, ApiError, ResponseError, SignatureVerificationError, Pay2sWebhookVerificationErrorPay2sWebhookParseError. Error giữ code, HTTP status nếu có, requestId nếu Pay2S trả về và cause gốc khi phù hợp.

| Error | Cách xử lý | | --- | --- | | ValidationError | Sửa input; không retry. | | AuthenticationError | Kiểm tra environment/key/token; không retry mù. | | SignatureVerificationError | Từ chối callback/request và điều tra contract/secret. | | NetworkError | Retry hữu hạn chỉ khi operation an toàn và application đã deduplicate. | | ApiError / ResponseError | Lưu status, code, requestId; xử lý theo business contract. |

SDK không tự retry payment request vì retry mù có thể tạo giao dịch trùng. Dùng requestId ổn định cho mỗi business order, lưu correlation fields (requestId, orderId, transId) và deduplicate callback ở application layer. defaultHeaders có thể dùng cho header idempotency nếu contract account cung cấp header đó; SDK không tự đặt một header chưa được Pay2S xác nhận.

SDK hiện không thêm status lookup, cancel hoặc refund vì tài liệu Pay2S công khai hiện không cung cấp contract ổn định cho các endpoint này.

Kiểm tra

npm run typecheck
npm test
npm run sandbox:smoke

Mặc định Sandbox smoke test được bỏ qua. Chỉ bật rõ ràng bằng PAY2S_RUN_SANDBOX=true và cung cấp credential cùng URL callback HTTPS trong environment.