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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@carllee1983/newebpay

v1.5.0

Published

藍新金流 SDK - NewebPay Payment Gateway SDK for Node.js

Readme

藍新金流 Node.js SDK

npm version Node.js Version Bun Version TypeScript License CI

📖 English Version

藍新金流(NewebPay)Node.js SDK,提供簡潔易用的 API 整合藍新金流支付服務。

功能特色

  • ✅ 支援全部支付方式:信用卡、ATM 轉帳、超商代碼/條碼繳費、LINE Pay、台灣 Pay 等
  • ✅ 完整的 AES-256-CBC 加解密實作(使用 Node.js 原生 crypto)
  • ✅ 支援交易查詢、退款、取消授權
  • ✅ 完整的 TypeScript 型別定義
  • ✅ ESM 和 CommonJS 雙重支援
  • ✅ Node.js 18/20/22 LTS 支援
  • ✅ Bun 原生支援(使用 Bun 原生 fetch 和 crypto API)
  • ✅ Express、Fastify、Koa 框架整合

系統需求

  • Node.js 18.0.0 或更高版本(支援 18.x、20.x、22.x LTS)
  • 或 Bun 1.0.0 或更高版本(完全相容,使用 Bun 原生 API)

安裝

npm install @carllee1983/newebpay

或使用 yarn / pnpm / bun:

yarn add @carllee1983/newebpay
# 或
pnpm add @carllee1983/newebpay
# 或
bun add @carllee1983/newebpay

快速開始

基本使用

import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

// 建立信用卡付款
const payment = new CreditPayment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true) // 測試環境
  .setMerchantOrderNo('ORDER' + Date.now()) // 訂單編號
  .setAmt(1000) // 金額
  .setItemDesc('測試商品') // 商品描述
  .setEmail('[email protected]') // 買家 Email
  .setReturnURL('https://your-site.com/return') // 付款完成返回網址
  .setNotifyURL('https://your-site.com/notify') // 付款結果通知網址

// 產生 HTML 表單(自動送出)
const form = FormBuilder.create(payment).build()
console.log(form)

// 或取得表單資料供前端使用
const formData = FormBuilder.create(payment).getFormData()
// { action: 'https://...', fields: { MerchantID: '...', TradeInfo: '...', ... } }

Express 整合

import express from 'express'
import {
  createNewebPayRouter,
  loadConfigFromEnv,
  NewebPayService,
} from '@carllee1983/newebpay/express'

const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

// 從環境變數載入設定
const config = loadConfigFromEnv()

// 方式一:使用內建路由
app.use('/newebpay', createNewebPayRouter(config))

// 方式二:使用 NewebPayService
app.post('/api/payment/create', (req, res) => {
  const { orderId, amount, itemDesc, email } = req.body
  const newebpay = new NewebPayService(config)

  const params = newebpay
    .payment(orderId, amount, itemDesc, email)
    .creditCard()
    .setReturnUrl('https://your-site.com/return')
    .setNotifyUrl('https://your-site.com/notify')
    .getParams()

  res.json({ success: true, data: params })
})

app.listen(3000)

環境變數設定:

# .env
NEWEBPAY_MERCHANT_ID=MS12345678
NEWEBPAY_HASH_KEY=your_hash_key_32_chars
NEWEBPAY_HASH_IV=your_hash_iv_16_chars
NEWEBPAY_RETURN_URL=https://your-site.com/return
NEWEBPAY_NOTIFY_URL=https://your-site.com/notify
NEWEBPAY_TEST_MODE=true

前端自訂表單

當你需要在前端框架(React、Vue 等)中自訂表單 UI 時,可以使用 FormBuilder 提供的資料取得方法,無需使用 HTML 表單。

取得表單資料

FormBuilder 提供以下方法來取得表單資料:

  • getFormData()getData(): 取得完整的表單資料(包含 actionmethodfields
  • getFields(): 只取得表單欄位資料
import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

const payment = new CreditPayment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true)
  .setMerchantOrderNo('ORDER' + Date.now())
  .setAmt(1000)
  .setItemDesc('測試商品')
  .setEmail('[email protected]')
  .setReturnURL('https://your-site.com/return')
  .setNotifyURL('https://your-site.com/notify')

const builder = FormBuilder.create(payment)

// 取得完整表單資料
const { action, method, fields } = builder.getFormData()
// 或使用別名
const { action, method, fields } = builder.getData()

// 只取得欄位資料
const fields = builder.getFields()

// 返回的資料結構:
// {
//   action: 'https://ccore.newebpay.com/MPG/mpg_gateway',
//   method: 'POST',
//   fields: {
//     MerchantID: 'MS12345678',
//     TradeInfo: '...',
//     TradeSha: '...',
//     Version: '2.0'
//   }
// }

React 整合範例

使用 React Hook Form

import { useState, useEffect } from 'react'
import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

function PaymentForm() {
  const [formData, setFormData] = useState<{
    action: string
    method: string
    fields: Record<string, string>
  } | null>(null)

  useEffect(() => {
    // 從後端 API 取得表單資料
    fetch('/api/payment/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        orderId: 'ORDER' + Date.now(),
        amount: 1000,
        itemDesc: '測試商品',
        email: '[email protected]',
      }),
    })
      .then((res) => res.json())
      .then((data) => setFormData(data.formData))
  }, [])

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    if (!formData) return

    // 建立動態表單並提交
    const form = document.createElement('form')
    form.method = formData.method
    form.action = formData.action

    Object.entries(formData.fields).forEach(([name, value]) => {
      const input = document.createElement('input')
      input.type = 'hidden'
      input.name = name
      input.value = value
      form.appendChild(input)
    })

    document.body.appendChild(form)
    form.submit()
  }

  if (!formData) return <div>載入中...</div>

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">前往付款</button>
    </form>
  )
}

使用 Fetch API 直接提交

import { useState } from 'react'

function PaymentForm() {
  const [loading, setLoading] = useState(false)

  const handlePayment = async () => {
    setLoading(true)
    try {
      // 從後端取得表單資料
      const response = await fetch('/api/payment/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          orderId: 'ORDER' + Date.now(),
          amount: 1000,
          itemDesc: '測試商品',
          email: '[email protected]',
        }),
      })

      const { formData } = await response.json()

      // 建立 FormData 並提交到藍新金流
      const formDataToSubmit = new FormData()
      Object.entries(formData.fields).forEach(([key, value]) => {
        formDataToSubmit.append(key, value)
      })

      // 使用 fetch 提交(注意:藍新金流需要 POST 到指定 URL)
      const form = document.createElement('form')
      form.method = formData.method
      form.action = formData.action

      Object.entries(formData.fields).forEach(([name, value]) => {
        const input = document.createElement('input')
        input.type = 'hidden'
        input.name = name
        input.value = value
        form.appendChild(input)
      })

      document.body.appendChild(form)
      form.submit()
    } catch (error) {
      console.error('付款失敗:', error)
    } finally {
      setLoading(false)
    }
  }

  return (
    <button onClick={handlePayment} disabled={loading}>
      {loading ? '處理中...' : '前往付款'}
    </button>
  )
}

Vue 整合範例

使用 Vue 3 Composition API

<template>
  <div>
    <button @click="handlePayment" :disabled="loading">
      {{ loading ? '處理中...' : '前往付款' }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const loading = ref(false)

const handlePayment = async () => {
  loading.value = true
  try {
    // 從後端 API 取得表單資料
    const response = await fetch('/api/payment/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        orderId: 'ORDER' + Date.now(),
        amount: 1000,
        itemDesc: '測試商品',
        email: '[email protected]',
      }),
    })

    const { formData } = await response.json()

    // 建立動態表單並提交
    const form = document.createElement('form')
    form.method = formData.method
    form.action = formData.action

    Object.entries(formData.fields).forEach(([name, value]) => {
      const input = document.createElement('input')
      input.type = 'hidden'
      input.name = name
      input.value = value as string
      form.appendChild(input)
    })

    document.body.appendChild(form)
    form.submit()
  } catch (error) {
    console.error('付款失敗:', error)
  } finally {
    loading.value = false
  }
}
</script>

使用響應式表單資料

<template>
  <form @submit.prevent="submitForm">
    <div v-if="formData">
      <input
        v-for="(value, name) in formData.fields"
        :key="name"
        type="hidden"
        :name="name"
        :value="value"
      />
      <button type="submit">前往付款</button>
    </div>
    <div v-else>載入中...</div>
  </form>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

interface FormData {
  action: string
  method: string
  fields: Record<string, string>
}

const formData = ref<FormData | null>(null)

onMounted(async () => {
  const response = await fetch('/api/payment/create', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      orderId: 'ORDER' + Date.now(),
      amount: 1000,
      itemDesc: '測試商品',
      email: '[email protected]',
    }),
  })

  const data = await response.json()
  formData.value = data.formData
})

const submitForm = () => {
  if (!formData.value) return

  const form = document.createElement('form')
  form.method = formData.value.method
  form.action = formData.value.action

  Object.entries(formData.value.fields).forEach(([name, value]) => {
    const input = document.createElement('input')
    input.type = 'hidden'
    input.name = name
    input.value = value
    form.appendChild(input)
  })

  document.body.appendChild(form)
  form.submit()
}
</script>

原生 JavaScript 範例

使用 Fetch API

async function createPayment() {
  try {
    // 從後端 API 取得表單資料
    const response = await fetch('/api/payment/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        orderId: 'ORDER' + Date.now(),
        amount: 1000,
        itemDesc: '測試商品',
        email: '[email protected]',
      }),
    })

    const { formData } = await response.json()

    // 建立動態表單並提交
    const form = document.createElement('form')
    form.method = formData.method
    form.action = formData.action
    form.style.display = 'none'

    Object.entries(formData.fields).forEach(([name, value]) => {
      const input = document.createElement('input')
      input.type = 'hidden'
      input.name = name
      input.value = value
      form.appendChild(input)
    })

    document.body.appendChild(form)
    form.submit()
  } catch (error) {
    console.error('付款失敗:', error)
  }
}

// 使用範例
document.getElementById('pay-button').addEventListener('click', createPayment)

使用 XMLHttpRequest

function createPayment() {
  const xhr = new XMLHttpRequest()
  xhr.open('POST', '/api/payment/create', true)
  xhr.setRequestHeader('Content-Type', 'application/json')

  xhr.onload = function () {
    if (xhr.status === 200) {
      const { formData } = JSON.parse(xhr.responseText)

      // 建立動態表單並提交
      const form = document.createElement('form')
      form.method = formData.method
      form.action = formData.action

      Object.entries(formData.fields).forEach(([name, value]) => {
        const input = document.createElement('input')
        input.type = 'hidden'
        input.name = name
        input.value = value
        form.appendChild(input)
      })

      document.body.appendChild(form)
      form.submit()
    }
  }

  xhr.send(
    JSON.stringify({
      orderId: 'ORDER' + Date.now(),
      amount: 1000,
      itemDesc: '測試商品',
      email: '[email protected]',
    })
  )
}

API 端點範例

Express

import express from 'express'
import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

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

app.post('/api/payment/create', (req, res) => {
  const { orderId, amount, itemDesc, email } = req.body

  const payment = new CreditPayment(
    process.env.NEWEBPAY_MERCHANT_ID!,
    process.env.NEWEBPAY_HASH_KEY!,
    process.env.NEWEBPAY_HASH_IV!
  )
    .setTestMode(process.env.NEWEBPAY_TEST_MODE === 'true')
    .setMerchantOrderNo(orderId)
    .setAmt(amount)
    .setItemDesc(itemDesc)
    .setEmail(email)
    .setReturnURL(process.env.NEWEBPAY_RETURN_URL!)
    .setNotifyURL(process.env.NEWEBPAY_NOTIFY_URL!)

  const formData = FormBuilder.create(payment).getFormData()

  res.json({
    success: true,
    formData: formData,
  })
})

app.listen(3000)

Fastify

import Fastify from 'fastify'
import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

const fastify = Fastify()

fastify.post('/api/payment/create', async (request, reply) => {
  const { orderId, amount, itemDesc, email } = request.body as {
    orderId: string
    amount: number
    itemDesc: string
    email: string
  }

  const payment = new CreditPayment(
    process.env.NEWEBPAY_MERCHANT_ID!,
    process.env.NEWEBPAY_HASH_KEY!,
    process.env.NEWEBPAY_HASH_IV!
  )
    .setTestMode(process.env.NEWEBPAY_TEST_MODE === 'true')
    .setMerchantOrderNo(orderId)
    .setAmt(amount)
    .setItemDesc(itemDesc)
    .setEmail(email)
    .setReturnURL(process.env.NEWEBPAY_RETURN_URL!)
    .setNotifyURL(process.env.NEWEBPAY_NOTIFY_URL!)

  const formData = FormBuilder.create(payment).getFormData()

  return {
    success: true,
    formData: formData,
  }
})

fastify.listen({ port: 3000 })

Koa

import Koa from 'koa'
import Router from '@koa/router'
import bodyParser from 'koa-bodyparser'
import { CreditPayment, FormBuilder } from '@carllee1983/newebpay'

const app = new Koa()
const router = new Router()

app.use(bodyParser())

router.post('/api/payment/create', async (ctx) => {
  const { orderId, amount, itemDesc, email } = ctx.request.body

  const payment = new CreditPayment(
    process.env.NEWEBPAY_MERCHANT_ID!,
    process.env.NEWEBPAY_HASH_KEY!,
    process.env.NEWEBPAY_HASH_IV!
  )
    .setTestMode(process.env.NEWEBPAY_TEST_MODE === 'true')
    .setMerchantOrderNo(orderId)
    .setAmt(amount)
    .setItemDesc(itemDesc)
    .setEmail(email)
    .setReturnURL(process.env.NEWEBPAY_RETURN_URL!)
    .setNotifyURL(process.env.NEWEBPAY_NOTIFY_URL!)

  const formData = FormBuilder.create(payment).getFormData()

  ctx.body = {
    success: true,
    formData: formData,
  }
})

app.use(router.routes())
app.listen(3000)

支援的支付方式

| 支付方式 | 類別 | 說明 | | -------------- | ------------------- | --------------------- | | 信用卡一次付清 | CreditPayment | 支援紅利折抵、銀聯卡 | | 信用卡分期 | CreditInstallment | 3/6/12/18/24/30 期 | | WebATM | WebAtmPayment | 即時網路 ATM 轉帳 | | ATM 轉帳 | AtmPayment | 虛擬帳號轉帳 | | 超商代碼繳費 | CvsPayment | 金額限制 30~20,000 元 | | 超商條碼繳費 | BarcodePayment | 金額限制 20~40,000 元 | | LINE Pay | LinePayPayment | LINE Pay 電子錢包 | | 台灣 Pay | TaiwanPayPayment | 台灣 Pay 行動支付 | | 玉山 Wallet | EsunWalletPayment | 玉山銀行電子錢包 | | BitoPay | BitoPayPayment | 加密貨幣支付 | | TWQR | TwqrPayment | TWQR 共通支付 | | 付啦 | FulaPayment | 先買後付 | | 超商取貨付款 | CvscomPayment | 超商物流取貨付款 | | 全支付方式 | AllInOnePayment | 自訂啟用多種支付 |

使用範例

信用卡分期

import { CreditInstallment, FormBuilder } from '@carllee1983/newebpay'

const payment = new CreditInstallment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true)
  .setMerchantOrderNo('INST' + Date.now())
  .setAmt(3000)
  .setItemDesc('分期商品')
  .setEmail('[email protected]')
  .setInstallment([3, 6, 12]) // 提供 3/6/12 期選項
  .setReturnURL('https://your-site.com/return')
  .setNotifyURL('https://your-site.com/notify')

const form = FormBuilder.create(payment).build()

ATM 虛擬帳號

import { AtmPayment, BankType, FormBuilder } from '@carllee1983/newebpay'

const payment = new AtmPayment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true)
  .setMerchantOrderNo('ATM' + Date.now())
  .setAmt(2000)
  .setItemDesc('ATM 轉帳測試')
  .setEmail('[email protected]')
  .setExpireDate('2025-12-31') // 繳費期限
  .setBankType(BankType.BOT) // 指定銀行(可選)
  .setReturnURL('https://your-site.com/return')
  .setNotifyURL('https://your-site.com/notify')
  .setCustomerURL('https://your-site.com/customer') // 取號完成返回

const form = FormBuilder.create(payment).build()

全支付方式(多種支付選項)

import { AllInOnePayment, FormBuilder } from '@carllee1983/newebpay'

const payment = new AllInOnePayment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true)
  .setMerchantOrderNo('ALL' + Date.now())
  .setAmt(1000)
  .setItemDesc('多元支付測試')
  .setEmail('[email protected]')
  .setReturnURL('https://your-site.com/return')
  .setNotifyURL('https://your-site.com/notify')
  // 啟用多種支付方式(依需求選擇)
  .enableCredit() // 信用卡一次付清
  .enableWebAtm() // WebATM 即時轉帳
  .enableAtm() // ATM 虛擬帳號
  .enableCvs() // 超商代碼繳費
  .enableBarcode() // 超商條碼繳費
  .enableLinePay() // LINE Pay
  .enableTaiwanPay() // 台灣 Pay
  .enableEsunWallet() // 玉山 Wallet
  .enableBitoPay() // BitoPay 加密貨幣
  .enableTwqr() // TWQR 共通支付
  .enableFula() // 付啦(先買後付)
  .enableInstallment([3, 6, 12]) // 信用卡分期(3/6/12 期)
  .enableRedeem() // 信用卡紅利折抵
  .enableUnionPay() // 銀聯卡

const form = FormBuilder.create(payment).build()

AllInOnePayment 可用方法

| 方法 | 說明 | | --------------------------- | ------------------------------ | | .enableCredit() | 啟用信用卡一次付清 | | .enableWebAtm() | 啟用 WebATM 即時轉帳 | | .enableAtm() | 啟用 ATM 虛擬帳號轉帳 | | .enableCvs() | 啟用超商代碼繳費 | | .enableBarcode() | 啟用超商條碼繳費 | | .enableLinePay() | 啟用 LINE Pay | | .enableTaiwanPay() | 啟用台灣 Pay | | .enableEsunWallet() | 啟用玉山 Wallet | | .enableBitoPay() | 啟用 BitoPay 加密貨幣支付 | | .enableTwqr() | 啟用 TWQR 共通支付 | | .enableFula() | 啟用付啦(先買後付) | | .enableInstallment([3,6]) | 啟用信用卡分期(指定可選期數) | | .enableRedeem() | 啟用信用卡紅利折抵 | | .enableUnionPay() | 啟用銀聯卡 |

所有 enable*() 方法都可傳入 false 來停用該支付方式,例如:.enableCredit(false)

超商取貨付款

import { CvscomPayment, LgsType, FormBuilder } from '@carllee1983/newebpay'

const payment = new CvscomPayment('特店編號', 'HashKey', 'HashIV')
  .setTestMode(true)
  .setMerchantOrderNo('CVSCOM' + Date.now())
  .setAmt(500)
  .setItemDesc('超商取貨商品')
  .setEmail('[email protected]')
  .setLgsType(LgsType.B2C) // 大宗寄倉
  .setReceiverName('收件人')
  .setReceiverPhone('0912345678')
  .setReceiverEmail('[email protected]')
  .setReturnURL('https://your-site.com/return')
  .setNotifyURL('https://your-site.com/notify')

const form = FormBuilder.create(payment).build()

通知處理

付款完成通知

import { PaymentNotify } from '@carllee1983/newebpay'

app.post('/payment/notify', (req, res) => {
  const notify = new PaymentNotify('HashKey', 'HashIV')

  try {
    notify.verifyOrFail(req.body)

    if (notify.isSuccess()) {
      const orderNo = notify.getMerchantOrderNo()
      const amount = notify.getAmt()
      const paymentType = notify.getPaymentType()
      const tradeNo = notify.getTradeNo()

      // 更新訂單狀態...
      console.log(`訂單 ${orderNo} 付款成功,金額 ${amount}`)
    }

    res.send('OK')
  } catch (error) {
    console.error('驗證失敗:', error)
    res.status(400).send('Verification failed')
  }
})

ATM 取號通知

import { AtmNotify } from '@carllee1983/newebpay'

app.post('/atm/notify', (req, res) => {
  const notify = new AtmNotify('HashKey', 'HashIV')

  if (notify.verify(req.body) && notify.isSuccess()) {
    const orderNo = notify.getMerchantOrderNo()
    const bankCode = notify.getBankCode() // 銀行代碼
    const codeNo = notify.getCodeNo() // 虛擬帳號
    const expireDate = notify.getExpireDate() // 繳費截止日

    // 儲存繳費資訊,通知買家...
    console.log(`ATM 帳號: ${bankCode}-${codeNo},截止日: ${expireDate}`)
  }

  res.send('OK')
})

超商取號通知

import { CvsNotify } from '@carllee1983/newebpay'

app.post('/cvs/notify', (req, res) => {
  const notify = new CvsNotify('HashKey', 'HashIV')

  if (notify.verify(req.body) && notify.isSuccess()) {
    const codeNo = notify.getCodeNo() // 繳費代碼
    const storeType = notify.getStoreType() // 超商類型
    const expireDate = notify.getExpireDate() // 繳費截止日

    // 條碼繳費資訊
    const barcode1 = notify.getBarcode1()
    const barcode2 = notify.getBarcode2()
    const barcode3 = notify.getBarcode3()

    // 儲存繳費資訊...
  }

  res.send('OK')
})

超商取貨付款通知

import { CvscomNotify } from '@carllee1983/newebpay'

app.post('/cvscom/notify', (req, res) => {
  const notify = new CvscomNotify('HashKey', 'HashIV')

  if (notify.verify(req.body) && notify.isSuccess()) {
    const storeCode = notify.getStoreCode() // 門市代碼
    const storeName = notify.getStoreName() // 門市名稱
    const storeAddr = notify.getStoreAddr() // 門市地址
    const lgsNo = notify.getLgsNo() // 物流編號
    const lgsType = notify.getLgsType() // 物流類型
    const receiverName = notify.getCVSCOMName() // 取貨人姓名

    // 儲存物流資訊...
  }

  res.send('OK')
})

交易查詢

一般交易查詢

import { QueryOrder } from '@carllee1983/newebpay'

const query = QueryOrder.create('特店編號', 'HashKey', 'HashIV').setTestMode(true)

try {
  const result = await query.query('ORDER123456', 1000)

  console.log('交易狀態:', result.TradeStatus)
  console.log('付款方式:', result.PaymentType)
  console.log('付款時間:', result.PayTime)
} catch (error) {
  console.error('查詢失敗:', error.message)
}

信用卡明細查詢

import { QueryCreditDetail } from '@carllee1983/newebpay'

const query = QueryCreditDetail.create('特店編號', 'HashKey', 'HashIV').setTestMode(true)

try {
  const result = await query.query('ORDER123456', 1000)

  console.log('請款狀態:', result.CloseStatus)
  console.log('退款狀態:', result.BackStatus)
  console.log('授權碼:', result.Auth)
  console.log('卡號末四碼:', result.Card4No)
} catch (error) {
  console.error('查詢失敗:', error.message)
}

退款與取消

信用卡請款/退款

import { CreditClose } from '@carllee1983/newebpay'

const creditClose = CreditClose.create('特店編號', 'HashKey', 'HashIV').setTestMode(true)

// 請款(授權後請款)
const payResult = await creditClose.pay('ORDER123456', 1000)

// 退款
const refundResult = await creditClose.refund('ORDER123456', 500)

// 取消請退款
const cancelResult = await creditClose.cancelClose(
  'ORDER123456',
  500,
  CreditClose.CLOSE_TYPE_REFUND,
)

取消授權

import { CreditCancel } from '@carllee1983/newebpay'

const creditCancel = CreditCancel.create('特店編號', 'HashKey', 'HashIV').setTestMode(true)

const result = await creditCancel.cancel('ORDER123456', 1000)

電子錢包退款

import { EWalletRefund } from '@carllee1983/newebpay'

const refund = EWalletRefund.create('特店編號', 'HashKey', 'HashIV').setTestMode(true)

// 支援 LINE Pay、台灣 Pay、玉山 Wallet 等
const result = await refund.refund('ORDER123456', 500, 'LINEPAY')

錯誤處理

SDK 提供 NewebPayError 類別處理各種錯誤情況:

import { CreditPayment, NewebPayError } from '@carllee1983/newebpay'

try {
  const payment = new CreditPayment('特店編號', 'HashKey', 'HashIV')
    .setMerchantOrderNo('ORDER001')
    .setAmt(-100) // 金額錯誤
} catch (error) {
  if (error instanceof NewebPayError) {
    console.log('錯誤代碼:', error.code) // 'INVALID_FIELD'
    console.log('錯誤訊息:', error.message) // 'Amt 無效:金額必須大於 0'
  }
}

常見錯誤代碼

| 錯誤代碼 | 說明 | | -------------------- | ------------------- | | REQUIRED_FIELD | 必填欄位未填寫 | | FIELD_TOO_LONG | 欄位值超過最大長度 | | INVALID_FIELD | 欄位值無效 | | DECRYPT_FAILED | 解密失敗 | | CHECK_VALUE_FAILED | CheckValue 驗證失敗 | | API_ERROR | API 請求錯誤 |

CLI 工具

套件提供 CLI 工具協助快速設定:

# 初始化環境變數設定檔
npx @carllee1983/newebpay init

# 產生 Express 整合範例專案
npx @carllee1983/newebpay express

測試卡號

| 類型 | 卡號 | 說明 | | ----------------------- | ------------------- | --------- | | 信用卡(一次付清/分期) | 4000-2211-1111-1111 | 一般測試 | | 紅利折抵 | 4003-5511-1111-1111 | 紅利測試 | | 美國運通卡 | 3760-000000-00006 | AMEX 測試 |

測試卡號的有效月年及卡片背面末三碼可任意填寫。

API 文件

本套件依據藍新金流「線上交易-幕前支付技術串接手冊」(NDNF-1.1.9)開發。

環境網址

| 環境 | 網址 | | -------- | -------------------------- | | 測試環境 | https://ccore.newebpay.com | | 正式環境 | https://core.newebpay.com |

主要 API 端點

| API | 路徑 | 說明 | | ------------ | ---------------------- | --------------- | | MPG 交易 | /MPG/mpg_gateway | 幕前支付 | | 交易查詢 | /API/QueryTradeInfo | 查詢訂單狀態 | | 取消授權 | /API/CreditCard/Cancel | 取消信用卡授權 | | 請退款 | /API/CreditCard/Close | 信用卡請款/退款 | | 電子錢包退款 | /API/EWallet/Refund | LINE Pay 等退款 |

目錄結構

newebpay-node/
├── src/
│   ├── index.ts                    # 主要匯出
│   ├── content.ts                  # 基礎 Content 類別
│   ├── form-builder.ts             # HTML 表單產生器
│   ├── infrastructure/             # 加解密器
│   ├── operations/                 # 支付操作
│   ├── notifications/              # 通知處理器
│   ├── queries/                    # 查詢 API
│   ├── actions/                    # 退款/取消授權
│   ├── types/                      # TypeScript 型別
│   ├── errors/                     # 例外類別
│   └── frameworks/                 # 框架整合
│       ├── express/                # Express 整合
│       ├── fastify/                # Fastify 整合
│       └── koa/                    # Koa 整合
├── tests/                          # 單元測試
├── examples/                       # 範例程式
├── docs/                           # API 文件
└── README.md

開發

# 安裝依賴
npm install

# 建置
npm run build

# 執行測試(使用 Bun)
bun test

# 執行測試(監看模式)
bun test --watch

# 測試覆蓋率
bun test --coverage

# Lint 檢查
bun run lint

# 格式化程式碼
bun run format

# TypeScript 類型檢查
bun run typecheck

注意:本專案使用 Bun 作為開發基底,所有測試和開發工具都使用 Bun 原生功能。若使用 Node.js,請確保 Node.js 版本為 18.0.0 或更高版本。

授權

MIT License

貢獻

歡迎提交 Issue 和 Pull Request。詳細資訊請參閱 CONTRIBUTING.md

相關連結