| name | taiwan-invoice |
| description | Taiwan E-Invoice API integration specialist for ECPay, SmilePay, Amego, ezPay, and PayNow. Use when developing invoice systems, implementing B2C/B2B invoice issuance, invoice printing, allowance creation, or working with Taiwan E-Invoice APIs. Handles encryption (AES-128, AES-256, MD5, JWT), API requests, and service provider differences. |
| user-invocable | true |
Taiwan E-Invoice Development Skill
此技能涵蓋台灣電子發票 API 整合開發,包含綠界 (ECPay)、速買配 (SmilePay)、光貿 (Amego)、ezPay (藍新集團) 與 PayNow (立吉富) 五家服務商。
快速導覽
相關文件
使用此技能時,請參考專案中的 API 規格文件:
references/ECPAY_API_REFERENCE.md - 綠界 API 規格
references/SMILEPAY_API_REFERENCE.md - 速買配 API 規格
references/AMEGO_API_REFERENCE.md - 光貿 API 規格
references/EZPAY_API_REFERENCE.md - ezPay 簡單付 API 規格(藍新金流集團)
references/PAYNOW_API_REFERENCE.md - 立吉富 PayNow API 規格(含 POS 機批次取號流程)
- EXAMPLES.md - 程式碼範例集
智能工具
scripts/search.py - BM25 搜索引擎(查詢 API、錯誤碼、欄位映射)
scripts/recommend.py - 加值中心推薦系統
scripts/generate-invoice-service.py - 服務代碼生成器
scripts/persist.py - 持久化配置工具(MASTER.md 生成)
data/ - CSV 數據檔(providers, operations, error-codes, field-mappings, tax-rules, troubleshooting, reasoning)
何時使用此技能
- 開發電子發票開立功能
- 整合台灣電子發票服務商 API
- 實作 B2C(二聯式)或 B2B(三聯式)發票
- 處理發票列印、作廢、折讓等功能
- 處理加密簽章(AES、MD5)
- 解決發票 API 整合問題
智能搜索與推薦
搜索引擎 (search.py)
使用 BM25 算法在資料庫中搜索相關資訊:
python scripts/search.py "ecpay" --domain provider
python scripts/search.py "10000016" --domain error
python scripts/search.py "MerchantID" --domain field
python scripts/search.py "B2B 稅額計算" --domain tax
python scripts/search.py "列印空白" --domain troubleshoot
python scripts/search.py "折讓" --format json
搜索域:
| 域 | 說明 | CSV 檔案 |
|---|
provider | 加值中心比較 | providers.csv |
operation | API 操作端點 | operations.csv |
error | 錯誤碼查詢 | error-codes.csv |
field | 欄位映射 | field-mappings.csv |
tax | 稅務計算規則 | tax-rules.csv |
troubleshoot | 疑難排解 | troubleshooting.csv |
reasoning | 推薦決策規則 | reasoning.csv |
推薦系統 (recommend.py)
根據需求自動推薦最適合的加值中心:
python scripts/recommend.py "電商 高交易量 穩定"
python scripts/recommend.py "簡單 快速 小型專案"
python scripts/recommend.py "API 設計 MIG標準"
python scripts/recommend.py "穩定 文檔完整" --format json
推薦關鍵字:
- ECPay: 穩定、市佔、文檔、SDK、高交易量、電商
- SmilePay: 簡單、快速、小型、測試、無加密、便宜
- Amego: API、設計、新、MIG、標準
- ezPay: 藍新、簡單付、AES-256、字軌管理、批次開立、與 Newebpay 同集團
- PayNow: 立吉富、JWT、金物流發票一站式、POS 批次取號、外帶 POS 機
代碼生成器 (generate-invoice-service.py)
自動生成服務商專用代碼:
python scripts/generate-invoice-service.py ECPay --output ts
python scripts/generate-invoice-service.py SmilePay --output py
python scripts/generate-invoice-service.py Amego --output ts > amego-service.ts
持久化配置 (persist.py)
將發票配置保存為 MASTER.md,供 AI 助手持續參考:
python scripts/persist.py init ECPay
python scripts/persist.py init SmilePay -p "MyProject"
python scripts/persist.py show
python scripts/persist.py list
python scripts/persist.py init Amego --force
生成結構:
invoice-config/
└── MASTER.md # 專案發票配置
├── 基本資訊
├── 服務商配置
├── API 端點
├── 發票類型設定
├── 環境變數建議
└── 開發檢查清單
發票類型
B2C 二聯式發票
- 買受人無統編
BuyerIdentifier = 0000000000
- 金額為含稅價
- 可使用載具或捐贈
- 示例:一般消費者購物
B2B 三聯式發票
- 買受人有 8 碼統編
BuyerIdentifier = 實際統編(需驗證格式)
- 金額為未稅價,需另計稅額
- 不可使用載具或捐贈
- 示例:公司採購
各服務商特性比較
| 特性 | 綠界 ECPay | 速買配 SmilePay | 光貿 Amego | ezPay 簡單付 | PayNow 立吉富 |
|---|
| 測試/正式 URL | 不同 URL | 不同 URL | 相同 URL | 不同 URL (cinv/inv) | 不同 URL (dev/prod) |
| 認證方式 | AES-128-CBC + HashKey/HashIV | Grvc + Verify_key | MD5 簽章 + App Key | AES-256-CBC + 32 碼 HashKey + 16 碼 HashIV + SHA256 CheckCode | JWT Bearer Token |
| 列印方式 | POST 表單提交 | GET URL 參數 | API 取得 PDF URL | API 觸發補開立 (Api_invoice_touch) | (需向 PayNow 索取) |
| B2B 金額欄位 | SalesAmount (未稅) | UnitTAX=N | DetailVat=0 | Category=B2B + Amt/TaxAmt 拆分 | BuyerIdentifier + TaxType 切換 |
| 傳輸格式 | JSON (AES 加密) | URL Parameters | JSON (URL Encode) | Form Post (MerchantID_/PostData_ 後綴底線) | JSON (Bearer Header) |
| 與其他系統共用加密 | 獨立 | 獨立 | 獨立 | 與藍新 Newebpay 金流共用 | 與 PayNow 金流不同(金流端用動態 AES-256) |
| 文件成熟度 | 高 | 高 | 中 | 中(5 本 PDF) | 低(公開頁面僅約 70 行,多項 API 須索取 PDF) |
開發實作步驟
1. 服務實作架構
創建服務時遵循以下結構:
export interface InvoiceService {
issueInvoice(userId: string, data: InvoiceIssueData): Promise<InvoiceIssueResponse>
voidInvoice(userId: string, invoiceNumber: string, reason: string): Promise<InvoiceVoidResponse>
printInvoice(userId: string, invoiceNumber: string): Promise<InvoicePrintResponse>
}
export class ECPayInvoiceService implements InvoiceService {
private async encryptData(data: any, hashKey: string, hashIV: string): Promise<string> {
}
async issueInvoice(userId: string, data: InvoiceIssueData) {
}
}
2. 金額計算邏輯
含稅總額 → 未稅金額 + 稅額:
function calculateInvoiceAmounts(totalAmount: number, isB2B: boolean) {
if (isB2B) {
const taxAmount = Math.round(totalAmount - (totalAmount / 1.05))
const salesAmount = totalAmount - taxAmount
return { salesAmount, taxAmount, totalAmount }
} else {
return { salesAmount: totalAmount, taxAmount: 0, totalAmount }
}
}
const amounts = calculateInvoiceAmounts(1050, true)
3. 加密實作
綠界 (ECPay) - AES 加密:
import crypto from 'crypto'
function encryptECPay(data: object, hashKey: string, hashIV: string): string {
const jsonString = JSON.stringify(data)
const urlEncoded = encodeURIComponent(jsonString)
const cipher = crypto.createCipheriv('aes-128-cbc', hashKey, hashIV)
let encrypted = cipher.update(urlEncoded, 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
function decryptECPay(encryptedData: string, hashKey: string, hashIV: string): object {
const decipher = crypto.createDecipheriv('aes-128-cbc', hashKey, hashIV)
let decrypted = decipher.update(encryptedData, 'base64', 'utf8')
decrypted += decipher.final('utf8')
const urlDecoded = decodeURIComponent(decrypted)
return JSON.parse(urlDecoded)
}
光貿 (Amego) - MD5 簽章:
function generateAmegoSign(data: object, time: number, appKey: string): string {
const dataString = JSON.stringify(data)
const signString = dataString + time + appKey
return crypto.createHash('md5').update(signString).digest('hex')
}
4. 服務商綁定
關鍵:開立發票時必須記錄使用的服務商,列印時才能正確調用
await prisma.financialRecord.update({
where: { id: recordId },
data: {
invoiceNo: result.invoiceNumber,
invoiceProvider: actualProvider,
invoiceRandomNum: result.randomNumber,
invoiceDate: new Date(),
}
})
const service = record.invoiceProvider
? InvoiceServiceFactory.getService(record.invoiceProvider)
: await InvoiceServiceFactory.getServiceForUser(userId)
5. 列印回應處理
前端需根據回應類型處理:
interface InvoicePrintResponse {
success: boolean
type?: 'html' | 'redirect' | 'form'
htmlContent?: string
printUrl?: string
formUrl?: string
formParams?: Record<string, string>
}
if (result.type === 'html') {
const win = window.open('', '_blank')
win.document.write(result.htmlContent)
} else if (result.type === 'redirect') {
window.open(result.url, '_blank')
} else if (result.type === 'form') {
const form = document.createElement('form')
form.method = 'POST'
form.action = result.formUrl
form.target = '_blank'
form.submit()
}
常見問題排除
問題 1: 開立發票失敗,錯誤訊息不明確
診斷步驟:
- 檢查 logger 輸出,查看
raw 欄位完整錯誤
- 確認環境變數(測試/正式)是否正確
- 驗證必填欄位是否完整
綠界常見錯誤:
10000006: RelateNumber 重複 → 訂單編號已使用
10000016: 金額計算錯誤 → 檢查 B2C/B2B 金額計算
10000019: 打統編不可使用載具 → 移除 CarrierType
速買配常見錯誤:
-10066: AllAmount 驗算錯誤 → 檢查是否傳入 TotalAmount
-10084: orderid 格式錯誤 → 限制 30 字元
-10053: 載具號碼錯誤 → 驗證手機條碼格式
光貿常見錯誤:
1002: OrderId 已存在 → 使用唯一訂單編號
1007: 金額計算錯誤 → 檢查 DetailVat 設定
1012: 打統編發票不可使用載具或捐贈
問題 2: 列印時顯示「查詢不到該發票」
解決方案:
確認 invoiceProvider 欄位有正確儲存,列印時使用開立時的服務商。
const service = record.invoiceProvider
? InvoiceServiceFactory.getService(record.invoiceProvider)
: await InvoiceServiceFactory.getServiceForUser(userId)
const service = await InvoiceServiceFactory.getServiceForUser(userId)
問題 3: B2B 發票金額錯誤
各服務商金額欄位:
const b2bData = {
SalesAmount: 1000,
TaxAmount: 50,
TotalAmount: 1050,
ItemPrice: 100,
ItemAmount: 1000,
ItemTax: 50
}
const b2bData = {
AllAmount: '1050',
SalesAmount: '1000',
TaxAmount: '50',
UnitTAX: 'N',
UnitPrice: '100',
Amount: '1000'
}
const b2bData = {
DetailVat: 0,
SalesAmount: 1000,
TaxAmount: 50,
TotalAmount: 1050,
ProductItem: [{
UnitPrice: 100,
Amount: 1000
}]
}
問題 4: 速買配列印空白
原因: 回傳 method: 'GET' 時錯誤使用 type: 'form'
解決:
if (printData.method === 'GET' && printData.url) {
return { type: 'redirect', url: printData.url }
}
return { type: 'form', url: printData.url, params: printData.params }
問題 5: 時間戳記逾時
綠界錯誤 10000005: 時間戳記超過 10 分鐘
解決:
const timestamp = Math.floor(Date.now() / 1000)
const time = Math.floor(Date.now() / 1000)
測試帳號
綠界測試環境
MerchantID: 2000132
HashKey: ejCk326UnaZWKisg
HashIV: q9jcZX8Ib9LM8wYk
URL: https://einvoice-stage.ecpay.com.tw
速買配測試環境
Grvc: SEI1000034
Verify_key: 9D73935693EE0237FABA6AB744E48661
測試統編: 80129529
URL: https://ssl.smse.com.tw/api_test/SPEinvoice_Storage.asp
光貿測試環境
統編: 12345678
App Key: sHeq7t8G1wiQvhAuIM27
後台: https://invoice.amego.tw/
測試帳號: test@amego.tw
測試密碼: 12345678
ezPay 簡單付測試環境
測試後台: https://cinv.ezpay.com.tw/
申請流程: 自行註冊測試會員 → 取得 MerchantID + HashKey + HashIV
官方範例 HashKey: abcdefghijklmnopqrstuvwxyzabcdef (32 碼)
官方範例 HashIV: 1234567891234567 (16 碼)
正式環境: https://inv.ezpay.com.tw/
重要:ezPay HashKey 為 32 碼、HashIV 16 碼(與 ECPay 16/16 不同)。
ezPay 與藍新 Newebpay 金流共用同一套加密邏輯(TradeInfo / TradeSha 機制),但發票端與金流端的金鑰各自獨立。
PayNow 立吉富測試環境
測試環境 URL: https://invoiceapi-dev.paynow.com.tw/
正式環境 URL: https://invoiceapi-prod.paynow.com.tw/
認證方式: JWT Bearer Token (向 einvoice@paynow.com.tw 申請)
主站: https://gateway.paynow.com.tw/
注意:PayNow 公開技術文件較稀疏,多數請求/回應 schema 與錯誤碼需向 PayNow 索取官方 Invoice Management v1.5 PDF 才能取得完整規格。POS 機流程有「未使用發票號碼於次期單數月 5 號自動上傳空白發票」的特殊規則,務必注意。
開發檢查清單
使用此清單確保實作完整:
新增服務商步驟
- 在
lib/services/ 建立 {provider}-invoice-service.ts
- 實作
InvoiceService 介面的所有方法
- 在
InvoiceServiceFactory 註冊新服務商
- 在
prisma/schema.prisma 的 InvoiceProvider enum 新增選項
- 執行
prisma migrate 或 prisma db push
- 更新前端設定頁面(
app/settings/invoice/page.tsx)
- 撰寫單元測試
參考資料
詳細 API 規格請查看 references/ 目錄:
最後更新:2026/01/29