taiwan-invoice-skill 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1115 @@
1
+ # 光貿電子發票 API 完整技術規格 (Amego Invoice API)
2
+
3
+ > 官方文檔來源:https://invoice-api.amego.tw
4
+ > 支援 MIG 4.0 規範 (2025/01/01 起)
5
+
6
+ ---
7
+
8
+ ## 目錄
9
+ 1. [基本說明](#基本說明)
10
+ 2. [認證與簽章](#認證與簽章)
11
+ 3. [發票作業](#發票作業)
12
+ 4. [折讓作業](#折讓作業)
13
+ 5. [其他功能](#其他功能)
14
+ 6. [錯誤代碼](#錯誤代碼)
15
+
16
+ ---
17
+
18
+ ## 基本說明
19
+
20
+ ### API 網址
21
+ - **API 網址**:`https://invoice-api.amego.tw`
22
+ - **環境**:測試與正式共用同一個網址
23
+ - **Content-Type**:`application/x-www-form-urlencoded`
24
+
25
+ > **重要**:請勿使用 `application/json` 發送請求。`data` 欄位的 JSON 字串需經過 URL Encode。
26
+
27
+ ### 測試環境資料
28
+ | 項目 | 測試值 |
29
+ |------|--------|
30
+ | **統編** | `12345678` |
31
+ | **App Key** | `sHeq7t8G1wiQvhAuIM27` |
32
+ | **後台網址** | https://invoice.amego.tw/ |
33
+ | **測試帳號** | test@amego.tw |
34
+ | **測試密碼** | 12345678 |
35
+ | **公司名稱** | 測試環境有限公司 |
36
+
37
+ ### 正式環境資料
38
+ | 項目 | 說明 |
39
+ |------|------|
40
+ | **統編** | 貴公司統一編號 |
41
+ | **App Key** | 請與光貿客服聯絡取得 |
42
+
43
+ ---
44
+
45
+ ## 認證與簽章
46
+
47
+ ### 基本傳入參數
48
+ 每支 API 必須帶入以下參數:
49
+
50
+ | 欄位 | 類型 | 描述 |
51
+ |------|------|------|
52
+ | `invoice` | String | 統一編號 (8碼) |
53
+ | `data` | String | API 的 JSON 格式字串 (需 URL Encode) |
54
+ | `time` | Number | Unix Timestamp (誤差容許 ±60 秒) |
55
+ | `sign` | String | MD5 加密簽名 |
56
+
57
+ ### MD5 簽章規則
58
+ ```
59
+ md5(data 轉 json 格式字串 + time + APP_KEY)
60
+ ```
61
+
62
+ **簽章步驟:**
63
+ 1. 將 `data` 欄位的 JSON 物件轉為字串
64
+ 2. 串接 `time` (Unix Timestamp)
65
+ 3. 串接 `APP_KEY`
66
+ 4. 對整個字串執行 MD5 加密
67
+
68
+ **範例:**
69
+ ```javascript
70
+ // JavaScript 範例
71
+ const crypto = require('crypto')
72
+
73
+ const data = JSON.stringify({
74
+ OrderId: "TEST-001",
75
+ BuyerIdentifier: "0000000000",
76
+ // ... 其他欄位
77
+ })
78
+
79
+ const time = Math.floor(Date.now() / 1000) // Unix Timestamp
80
+ const appKey = "sHeq7t8G1wiQvhAuIM27"
81
+
82
+ const signString = data + time + appKey
83
+ const sign = crypto.createHash('md5').update(signString).digest('hex')
84
+
85
+ // POST 參數
86
+ const params = new URLSearchParams()
87
+ params.append('invoice', '12345678')
88
+ params.append('data', encodeURIComponent(data)) // URL Encode
89
+ params.append('time', time.toString())
90
+ params.append('sign', sign)
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 2025 年 MIG 4.0 重要異動
96
+
97
+ 財政部公告的電子發票資料交換標準訊息建置指引 (MIG) 3.2.1 版本已於 2025/01/01 停用,光貿已升級為 MIG 4.0。
98
+
99
+ | 功能 | 舊版路徑 (MIG 3.2.1) | **新版路徑 (MIG 4.0)** |
100
+ |------|---------------------|----------------------|
101
+ | 開立發票 (自動配號) | `/json/c0401` | `/json/f0401` |
102
+ | 作廢發票 | `/json/c0501` | `/json/f0501` |
103
+ | 開立折讓 | `/json/d0401` | `/json/g0401` |
104
+ | 作廢折讓 | `/json/d0501` | `/json/g0501` |
105
+ | 開立發票 (API 配號) | `/json/c0401_custom` | `/json/f0401_custom` |
106
+
107
+ > 舊版 API 目前尚可繼續使用,但建議盡快升級至新版。
108
+
109
+ ---
110
+
111
+ ## 發票作業
112
+
113
+ ### 1. 開立發票 (自動配號)
114
+
115
+ **端點:** `POST /json/f0401`
116
+
117
+ 光貿會自動分配發票號碼、開立時間及隨機碼。
118
+
119
+ #### 請求參數 (data 欄位內容)
120
+
121
+ | 欄位 | 類型 | 必填 | 描述 |
122
+ |------|------|------|------|
123
+ | `OrderId` | String | Y | 訂單編號,不可重複,不可超過 40 字 |
124
+ | `TrackApiCode` | String | N | 指定字軌開立 (需在後台設定 API 指定代碼) |
125
+ | `BuyerIdentifier` | String | Y | 買方統編,無則填 `0000000000` |
126
+ | `BuyerName` | String | Y | 買方名稱 (不可填 0/00/000/0000) |
127
+ | `BuyerAddress` | String | N | 買方地址 |
128
+ | `BuyerTelephoneNumber` | String | N | 買方電話 |
129
+ | `BuyerEmailAddress` | String | N | 買方電子信箱 (寄送通知用) |
130
+ | `MainRemark` | String | N | 總備註,不可超過 200 字 |
131
+ | `CarrierType` | String | N | 載具類別:`3J0002` 手機條碼、`CQ0001` 自然人憑證、`amego` 光貿會員載具 |
132
+ | `CarrierId1` | String | N | 載具顯碼 |
133
+ | `CarrierId2` | String | N | 載具隱碼 |
134
+ | `NPOBAN` | String | N | 捐贈碼 |
135
+ | `ProductItem` | Array | Y | 商品陣列,最多 9999 筆 |
136
+ | `SalesAmount` | Number | Y | 應稅銷售額合計 |
137
+ | `FreeTaxSalesAmount` | Number | Y | 免稅銷售額合計 |
138
+ | `ZeroTaxSalesAmount` | Number | Y | 零稅率銷售額合計 |
139
+ | `TaxType` | Number | Y | 課稅別:1 應稅、2 零稅率、3 免稅、4 特種稅率、9 混合 |
140
+ | `TaxRate` | String | Y | 稅率 (5% 填入 `0.05`) |
141
+ | `TaxAmount` | Number | Y | 營業稅額 (打統編才需計算 5%) |
142
+ | `TotalAmount` | Number | Y | 總計 |
143
+ | `CustomsClearanceMark` | Number | N | 通關方式:1 非經海關出口、2 經海關出口 (零稅率必填) |
144
+ | `ZeroTaxRateReason` | Number | N | 零稅率原因 71-79 (零稅率必填) |
145
+ | `BrandName` | String | N | 品牌名稱 |
146
+ | `DetailVat` | Number | N | 單價含稅或未稅:0 未稅、1 含稅 (預設 1) |
147
+ | `DetailAmountRound` | Number | N | 小計處理:0 精準到 7 位、1 四捨五入 (預設 0) |
148
+ | `PrinterType` | Number | N | 熱感應機型號代碼 (需列印時填入) |
149
+ | `PrinterLang` | Number | N | 熱感應機編碼:1 BIG5、2 GBK、3 UTF-8 |
150
+ | `PrintDetail` | Number | N | 是否列印明細:1 列印、0 不列印 (僅 PrinterType=2) |
151
+
152
+ #### ProductItem 商品陣列欄位
153
+
154
+ | 欄位 | 類型 | 必填 | 描述 |
155
+ |------|------|------|------|
156
+ | `Description` | String | Y | 品名,不可超過 256 字 |
157
+ | `Quantity` | Number | Y | 數量,小數精準度到 7 位數 |
158
+ | `Unit` | String | N | 單位,不可超過 6 字 |
159
+ | `UnitPrice` | Number | Y | 單價,小數精準度到 7 位數 |
160
+ | `Amount` | Number | Y | 小計,小數精準度到 7 位數 |
161
+ | `Remark` | String | N | 備註,不可超過 40 字 |
162
+ | `TaxType` | Number | Y | 課稅別:1 應稅、2 零稅率、3 免稅 |
163
+
164
+ #### 零稅率原因代碼
165
+
166
+ | 代碼 | 說明 |
167
+ |------|------|
168
+ | `71` | 第一款 外銷貨物 |
169
+ | `72` | 第二款 與外銷有關之勞務,或在國內提供而在國外使用之勞務 |
170
+ | `73` | 第三款 依法設立之免稅商店銷售與過境或出境旅客之貨物 |
171
+ | `74` | 第四款 銷售與保稅區營業人供營運之貨物或勞務 |
172
+ | `75` | 第五款 國際間之運輸 |
173
+ | `76` | 第六款 國際運輸用之船舶、航空器及遠洋漁船 |
174
+ | `77` | 第七款 銷售與國際運輸用之船舶、航空器及遠洋漁船所使用之貨物或修繕勞務 |
175
+ | `78` | 第八款 保稅區營業人銷售與課稅區營業人未輸往課稅區而直接出口之貨物 |
176
+ | `79` | 第九款 保稅區營業人銷售與課稅區營業人存入自由港區事業或海關管理之保稅倉庫、物流中心以供外銷之貨物 |
177
+
178
+ #### 請求範例 (一般開立)
179
+
180
+ ```json
181
+ {
182
+ "OrderId": "A20200817101021",
183
+ "BuyerIdentifier": "0000000000",
184
+ "BuyerName": "客人",
185
+ "BuyerAddress": "",
186
+ "BuyerTelephoneNumber": "",
187
+ "BuyerEmailAddress": "",
188
+ "MainRemark": "",
189
+ "CarrierType": "",
190
+ "CarrierId1": "",
191
+ "CarrierId2": "",
192
+ "NPOBAN": "",
193
+ "ProductItem": [
194
+ {
195
+ "Description": "測試商品1",
196
+ "Quantity": 1,
197
+ "UnitPrice": 170,
198
+ "Amount": 170,
199
+ "Remark": "",
200
+ "TaxType": 1
201
+ },
202
+ {
203
+ "Description": "會員折抵",
204
+ "Quantity": 1,
205
+ "UnitPrice": -2,
206
+ "Amount": -2,
207
+ "Remark": "",
208
+ "TaxType": 1
209
+ }
210
+ ],
211
+ "SalesAmount": 168,
212
+ "FreeTaxSalesAmount": 0,
213
+ "ZeroTaxSalesAmount": 0,
214
+ "TaxType": 1,
215
+ "TaxRate": "0.05",
216
+ "TaxAmount": 0,
217
+ "TotalAmount": 168
218
+ }
219
+ ```
220
+
221
+ #### 回應格式 (Success 200)
222
+
223
+ | 欄位 | 類型 | 描述 |
224
+ |------|------|------|
225
+ | `code` | Number | 0 代表成功,其他請參考錯誤代碼 |
226
+ | `msg` | String | 錯誤訊息 |
227
+ | `invoice_number` | String | 發票號碼 (成功時回傳) |
228
+ | `invoice_time` | Number | 發票開立時間 (Unix Timestamp) |
229
+ | `random_number` | String | 隨機碼 (成功時回傳) |
230
+ | `barcode` | String | 電子發票條碼內容 |
231
+ | `qrcode_left` | String | 左側 QRCODE 內容 (0元發票回傳空字串) |
232
+ | `qrcode_right` | String | 右側 QRCODE 內容 (0元發票回傳空字串) |
233
+ | `base64_data` | String | Base64 編碼的列印格式字串 (需列印時才回傳) |
234
+
235
+ #### 金額計算邏輯
236
+
237
+ **含稅商品金額計算 (DetailVat = 1)**
238
+
239
+ ```
240
+ SalesAmount = Round(所有 ProductItem TaxType=1 的 Amount 加總)
241
+ FreeTaxSalesAmount = Round(所有 ProductItem TaxType=3 的 Amount 加總)
242
+ ZeroTaxSalesAmount = Round(所有 ProductItem TaxType=2 的 Amount 加總)
243
+
244
+ 【不打統編 (不須分拆稅額)】
245
+ TaxAmount = 0
246
+
247
+ 【打統編 (須分拆稅額)】
248
+ TaxAmount = SalesAmount - Round(SalesAmount / 1.05)
249
+ SalesAmount = SalesAmount - TaxAmount
250
+
251
+ 【總計】
252
+ TotalAmount = SalesAmount + FreeTaxSalesAmount + ZeroTaxSalesAmount + TaxAmount
253
+ ```
254
+
255
+ **未稅商品金額計算 (DetailVat = 0)**
256
+
257
+ ```
258
+ SalesAmount = Round(所有 ProductItem TaxType=1 的 Amount 加總)
259
+ FreeTaxSalesAmount = Round(所有 ProductItem TaxType=3 的 Amount 加總)
260
+ ZeroTaxSalesAmount = Round(所有 ProductItem TaxType=2 的 Amount 加總)
261
+
262
+ 【計算稅額】
263
+ TaxAmount = Round(SalesAmount * 0.05)
264
+
265
+ 【總計】
266
+ TotalAmount = SalesAmount + FreeTaxSalesAmount + ZeroTaxSalesAmount + TaxAmount
267
+ ```
268
+
269
+ ---
270
+
271
+ ### 2. 作廢發票
272
+
273
+ **端點:** `POST /json/f0501`
274
+
275
+ 作廢已開立的發票。
276
+
277
+ #### 請求參數 (data 欄位內容)
278
+
279
+ ```json
280
+ [
281
+ {
282
+ "CancelInvoiceNumber": "AB00001111"
283
+ }
284
+ ]
285
+ ```
286
+
287
+ 支援單張或多張發票同時作廢。
288
+
289
+ #### 回應格式
290
+
291
+ | 欄位 | 類型 | 描述 |
292
+ |------|------|------|
293
+ | `code` | Number | 0 代表成功 |
294
+ | `msg` | String | 錯誤訊息 |
295
+
296
+ ---
297
+
298
+ ### 3. 發票狀態查詢
299
+
300
+ **端點:** `POST /json/invoice_status`
301
+
302
+ 查詢發票的上傳狀態。
303
+
304
+ #### 請求參數
305
+
306
+ ```json
307
+ [
308
+ {
309
+ "InvoiceNumber": "AB00001111"
310
+ }
311
+ ]
312
+ ```
313
+
314
+ #### 回應格式
315
+
316
+ | 欄位 | 類型 | 描述 |
317
+ |------|------|------|
318
+ | `code` | Number | 0 代表成功 |
319
+ | `msg` | String | 錯誤訊息 |
320
+ | `data` | Array | 發票狀態陣列 |
321
+
322
+ **data 陣列內容:**
323
+
324
+ | 欄位 | 類型 | 描述 |
325
+ |------|------|------|
326
+ | `invoice_number` | String | 發票號碼 |
327
+ | `type` | String | 發票類型 (NOT_FOUND/C0401/C0501/C0701/TYPE_ERROR) |
328
+ | `status` | Number | 1:待處理 2:上傳中 3:已上傳 31:處理中 32:處理完成 91:錯誤 99:完成 |
329
+ | `total_amount` | Number | 發票金額 |
330
+
331
+ **發票類型說明:**
332
+ - `NOT_FOUND`: 查無發票
333
+ - `C0401`: 發票開立
334
+ - `C0501`: 發票作廢
335
+ - `C0701`: 發票註銷
336
+ - `TYPE_ERROR`: 類型錯誤
337
+
338
+ ---
339
+
340
+ ### 4. 發票查詢
341
+
342
+ **端點:** `POST /json/invoice_query`
343
+
344
+ 查詢發票詳細內容 (以發票日期為主,只能查詢 180 天內的發票)。
345
+
346
+ #### 請求參數
347
+
348
+ ```json
349
+ {
350
+ "type": "order",
351
+ "order_id": "P202212010001"
352
+ }
353
+ ```
354
+
355
+
356
+
357
+ ```json
358
+ {
359
+ "type": "invoice",
360
+ "invoice_number": "AB00001111"
361
+ }
362
+ ```
363
+
364
+ #### 回應格式
365
+
366
+ 包含完整的發票資訊:
367
+
368
+ - 發票號碼、類型、狀態
369
+ - 買受人資訊
370
+ - 金額明細
371
+ - 商品明細 (ProductItem 陣列)
372
+ - 載具資訊
373
+ - 捐贈碼
374
+ - 中獎資訊
375
+ - 折讓單陣列 (allowance)
376
+ - 未處理的排程 (wait)
377
+
378
+ ---
379
+
380
+ ### 5. 發票列表
381
+
382
+ **端點:** `POST /json/invoice_list`
383
+
384
+ 取得發票主檔資料列表。
385
+
386
+ #### 請求參數
387
+
388
+ ```json
389
+ {
390
+ "date_select": 1,
391
+ "date_start": "20230101",
392
+ "date_end": "20230228",
393
+ "limit": 20,
394
+ "page": 1
395
+ }
396
+ ```
397
+
398
+ | 欄位 | 類型 | 描述 |
399
+ |------|------|------|
400
+ | `date_select` | Number | 1:發票日期 2:建立日期 |
401
+ | `date_start` | String | 開始日期 (YYYYMMDD) |
402
+ | `date_end` | String | 結束日期 (YYYYMMDD) |
403
+ | `limit` | Number | 每頁顯示筆數 (20-500,預設 20) |
404
+ | `page` | Number | 目前頁數 (預設 1) |
405
+
406
+ #### 回應格式
407
+
408
+ | 欄位 | 類型 | 描述 |
409
+ |------|------|------|
410
+ | `code` | Number | 0 代表成功 |
411
+ | `msg` | String | 錯誤訊息 |
412
+ | `page_total` | Number | 總頁數 |
413
+ | `page_now` | Number | 目前頁數 |
414
+ | `data_total` | Number | 總資料數 |
415
+ | `data` | Array | 發票陣列 |
416
+
417
+ ---
418
+
419
+ ### 6. 發票檔案下載
420
+
421
+ **端點:** `POST /json/invoice_file`
422
+
423
+ 下載發票 PDF 檔案。載具發票中獎後才可下載,非載具發票可無限次下載。
424
+
425
+ #### 請求參數
426
+
427
+ ```json
428
+ {
429
+ "type": "order",
430
+ "order_id": "P202212010001",
431
+ "download_style": 0
432
+ }
433
+ ```
434
+
435
+ | 欄位 | 類型 | 描述 |
436
+ |------|------|------|
437
+ | `type` | String | order (訂單編號) 或 invoice (發票號碼) |
438
+ | `order_id` | String | 訂單編號 |
439
+ | `invoice_number` | String | 發票號碼 |
440
+ | `download_style` | Number | 下載樣式 (見下表) |
441
+
442
+ **下載樣式:**
443
+
444
+ | 樣式代碼 | 適用範圍 | 說明 |
445
+ |---------|---------|------|
446
+ | `0` | 有統編 / 無統編 | A4 整張 (無統編需雙面列印) |
447
+ | `1` | 有統編 | A4 (地址+A5) |
448
+ | `2` | 有統編 | A4 (A5x2) |
449
+ | `3` | 有統編 | A5 |
450
+
451
+ #### 回應格式
452
+
453
+ ```json
454
+ {
455
+ "code": 0,
456
+ "msg": "",
457
+ "data": {
458
+ "file_url": "https://invoice.amego.tw/user/invoice_print_type?token=..."
459
+ }
460
+ }
461
+ ```
462
+
463
+ > 檔案連結僅 10 分鐘有效
464
+
465
+ ---
466
+
467
+ ### 7. 發票列印
468
+
469
+ **端點:** `POST /json/invoice_print`
470
+
471
+ 產出熱感應機列印格式字串。
472
+
473
+ > 注意: 0 元發票無法產生 QRCode,所以無法列印發票正本及補印。
474
+
475
+ #### 請求參數
476
+
477
+ ```json
478
+ {
479
+ "type": "order",
480
+ "order_id": "P202212010001",
481
+ "printer_type": 2,
482
+ "print_invoice_type": 1,
483
+ "print_invoice_detail": 1
484
+ }
485
+ ```
486
+
487
+ | 欄位 | 類型 | 描述 |
488
+ |------|------|------|
489
+ | `type` | String | order 或 invoice |
490
+ | `order_id` | String | 訂單編號 |
491
+ | `invoice_number` | String | 發票號碼 |
492
+ | `printer_type` | Number | 熱感應機型號代碼 |
493
+ | `printer_lang` | Number | 熱感應機編碼 (1:BIG5 2:GBK 3:UTF-8) |
494
+ | `print_invoice_type` | Number | 1:發票正本 2:發票補印 3:單印明細 |
495
+ | `print_invoice_detail` | Number | 1:列印明細 0:不列印 (打統編一律列印) |
496
+
497
+ #### 回應格式
498
+
499
+ ```json
500
+ {
501
+ "code": 0,
502
+ "msg": "",
503
+ "data": {
504
+ "base64_data": "G0AbQ............."
505
+ }
506
+ }
507
+ ```
508
+
509
+ ---
510
+
511
+ ## 折讓作業
512
+
513
+ ### 1. 開立折讓
514
+
515
+ **端點:** `POST /json/g0401`
516
+
517
+ 折讓已開立的發票。
518
+
519
+ #### 請求參數
520
+
521
+ ```json
522
+ [
523
+ {
524
+ "AllowanceNumber": "3821061800001",
525
+ "AllowanceDate": "20210618",
526
+ "AllowanceType": 2,
527
+ "BuyerIdentifier": "0000000000",
528
+ "BuyerName": "蕭XX",
529
+ "BuyerAddress": "",
530
+ "BuyerTelephoneNumber": "",
531
+ "BuyerEmailAddress": "",
532
+ "ProductItem": [
533
+ {
534
+ "OriginalInvoiceDate": 20210520,
535
+ "OriginalInvoiceNumber": "NW93016392",
536
+ "OriginalDescription": "超聲波清洗機",
537
+ "Quantity": 2,
538
+ "UnitPrice": 2180,
539
+ "Amount": 4360,
540
+ "Tax": 218,
541
+ "TaxType": 1
542
+ }
543
+ ],
544
+ "TaxAmount": 218,
545
+ "TotalAmount": 4360
546
+ }
547
+ ]
548
+ ```
549
+
550
+ | 欄位 | 類型 | 必填 | 描述 |
551
+ |------|------|------|------|
552
+ | `AllowanceNumber` | String | Y | 折讓單編號,不可重複,不可超過 16 字 |
553
+ | `AllowanceDate` | String | Y | 折讓單日期 (Ymd) |
554
+ | `AllowanceType` | Number | Y | 1:買方開立折讓證明單 2:賣方折讓證明通知單 |
555
+ | `BuyerIdentifier` | String | Y | 買方統編,無則填 `0000000000` |
556
+ | `BuyerName` | String | Y | 買方名稱 |
557
+ | `BuyerAddress` | String | N | 買方地址 |
558
+ | `BuyerTelephoneNumber` | String | N | 買方電話 |
559
+ | `BuyerEmailAddress` | String | N | 買方電子信箱 |
560
+ | `ProductItem` | Array | Y | 商品陣列,最多 9999 筆 |
561
+ | `TaxAmount` | Number | Y | 營業稅額 |
562
+ | `TotalAmount` | Number | Y | 金額合計 (不含稅) |
563
+
564
+ **ProductItem 欄位:**
565
+
566
+ | 欄位 | 類型 | 描述 |
567
+ |------|------|------|
568
+ | `OriginalInvoiceNumber` | String | 原發票號碼 |
569
+ | `OriginalInvoiceDate` | Number | 原發票日期 (Ymd) |
570
+ | `OriginalDescription` | String | 原品名,不可超過 256 字 |
571
+ | `Quantity` | Number | 數量 |
572
+ | `UnitPrice` | Number | 單價 (不含稅) |
573
+ | `Amount` | Number | 小計 (不含稅) |
574
+ | `Tax` | Number | 稅金 |
575
+ | `TaxType` | Number | 課稅別:1 應稅、2 零稅率、3 免稅 |
576
+
577
+ ---
578
+
579
+ ### 2. 作廢折讓
580
+
581
+ **端點:** `POST /json/g0501`
582
+
583
+ 作廢已開立的折讓單。
584
+
585
+ #### 請求參數
586
+
587
+ ```json
588
+ [
589
+ {
590
+ "CancelAllowanceNumber": "3821061800001"
591
+ }
592
+ ]
593
+ ```
594
+
595
+ ---
596
+
597
+ ### 3. 折讓狀態查詢
598
+
599
+ **端點:** `POST /json/allowance_status`
600
+
601
+ 查詢折讓單的上傳狀態。
602
+
603
+ ---
604
+
605
+ ### 4. 折讓查詢
606
+
607
+ **端點:** `POST /json/allowance_query`
608
+
609
+ 查詢折讓單詳細內容。
610
+
611
+ ---
612
+
613
+ ### 5. 折讓列表
614
+
615
+ **端點:** `POST /json/allowance_list`
616
+
617
+ 取得折讓單主檔資料列表。
618
+
619
+ ---
620
+
621
+ ### 6. 折讓檔案下載
622
+
623
+ **端點:** `POST /json/allowance_file`
624
+
625
+ 下載折讓單 PDF 檔案 (可無限次下載)。
626
+
627
+ ---
628
+
629
+ ### 7. 折讓列印
630
+
631
+ **端點:** `POST /json/allowance_print`
632
+
633
+ 產出折讓單熱感應機列印格式字串。
634
+
635
+ ---
636
+
637
+ ## 其他功能
638
+
639
+ ### 1. 手機條碼查詢
640
+
641
+ **端點:** `POST /json/barcode`
642
+
643
+ 查詢手機條碼是否正確。
644
+
645
+ ```json
646
+ {
647
+ "barCode": "/TRM+O+P"
648
+ }
649
+ ```
650
+
651
+ ---
652
+
653
+ ### 2. 公司名稱查詢
654
+
655
+ **端點:** `POST /json/ban_query`
656
+
657
+ 查詢統編對應的公司名稱 (資料來源:財政部財政資訊中心)。
658
+
659
+ ```json
660
+ [
661
+ {
662
+ "ban": "28080623"
663
+ },
664
+ {
665
+ "ban": "85101991"
666
+ }
667
+ ]
668
+ ```
669
+
670
+ **回應範例:**
671
+
672
+ ```json
673
+ {
674
+ "code": 0,
675
+ "msg": "",
676
+ "data": [
677
+ {
678
+ "ban": "28080623",
679
+ "name": "光貿科技股份有限公司"
680
+ },
681
+ {
682
+ "ban": "85101991",
683
+ "name": "紅磚數位有限公司"
684
+ }
685
+ ]
686
+ }
687
+ ```
688
+
689
+ ---
690
+
691
+ ### 3. 所有字軌資料
692
+
693
+ **端點:** `POST /json/track_all`
694
+
695
+ 取得該公司在加值中心的所有字軌資料 (三層結構)。
696
+
697
+ ---
698
+
699
+ ### 4. 伺服器時間查詢
700
+
701
+ **端點:** `GET /json/time`
702
+
703
+ 查詢目前伺服器時間 (不需要帶入 invoice、data、time 也不須計算 sign)。
704
+
705
+ **回應範例:**
706
+
707
+ ```json
708
+ {
709
+ "timestamp": 1683776130,
710
+ "text": "2023/05/11 11:35:30",
711
+ "year": 2023,
712
+ "month": 5,
713
+ "day": 11,
714
+ "hour": 11,
715
+ "minute": 35,
716
+ "second": 30
717
+ }
718
+ }
719
+ ```
720
+
721
+ ---
722
+
723
+ ### 5. 獎項定義
724
+
725
+ **端點:** `POST /json/lottery_type`
726
+
727
+ 取得中獎發票類型定義 (data 欄位不需要傳入資料)。
728
+
729
+ ---
730
+
731
+ ### 6. 中獎發票查詢
732
+
733
+ **端點:** `POST /json/lottery_status`
734
+
735
+ 查詢中獎的發票,建議雙月 1 號才查詢 (例如 9-10 月的發票,11/25 開獎,建議 12/1 再查詢)。
736
+
737
+ ```json
738
+ {
739
+ "Year": 2022,
740
+ "Period": 3
741
+ }
742
+ ```
743
+
744
+ **Period 期別:**
745
+ - 0: 01-02 月
746
+ - 1: 03-04 月
747
+ - 2: 05-06 月
748
+ - 3: 07-08 月
749
+ - 4: 09-10 月
750
+ - 5: 11-12 月
751
+
752
+ ---
753
+
754
+ ## 自行配號專用
755
+
756
+ ### 1. 字軌取號
757
+
758
+ **端點:** `POST /json/track_get`
759
+
760
+ 取發票字軌,只能取用字軌類型為「API 配號」的字軌 (1 本 = 50 張發票)。
761
+
762
+ ---
763
+
764
+ ### 2. 字軌狀態
765
+
766
+ **端點:** `POST /json/track_status`
767
+
768
+ 查詢發票字軌配號狀態 (只會回傳「API 配號」類型的字軌)。
769
+
770
+ ---
771
+
772
+ ### 3. 開立發票 (API 配號)
773
+
774
+ **端點:** `POST /json/f0401_custom`
775
+
776
+ 需自行指定發票號碼、發票日期時間及隨機碼。
777
+
778
+ > 注意: 若有傳入熱感應機型號代碼,一次只限制上傳一張。
779
+
780
+ #### 額外必填欄位
781
+
782
+ | 欄位 | 類型 | 描述 |
783
+ |------|------|------|
784
+ | `InvoiceNumber` | String | 發票號碼 (英文 2 碼 + 數字 8 碼) |
785
+ | `InvoiceDate` | String | 發票日期 (YYYYMMDD) |
786
+ | `InvoiceTime` | String | 發票時間 (HH:MM:SS) |
787
+ | `RandomNumber` | String | 隨機碼 (4 碼數字) |
788
+ | `PrintMark` | String | 列印註記 (Y:列印 N:不列印) |
789
+
790
+ ---
791
+
792
+ ## 錯誤代碼
793
+
794
+ ### 通用錯誤代碼
795
+
796
+ | 代碼 | 說明 |
797
+ |------|------|
798
+ | `0` | 成功 |
799
+ | `1` | 參數錯誤 |
800
+ | `2` | 簽章驗證失敗 |
801
+ | `3` | 時間戳記誤差過大 (超過 ±60 秒) |
802
+ | `4` | 統一編號不存在 |
803
+ | `5` | 訂單編號重複 |
804
+ | `100` | 發票號碼不存在 |
805
+ | `101` | 發票已作廢 |
806
+ | `102` | 發票已註銷 |
807
+ | `200` | 折讓單號碼重複 |
808
+ | `201` | 折讓金額超過原發票金額 |
809
+
810
+ ### 發票開立錯誤
811
+
812
+ | 代碼 | 說明 |
813
+ |------|------|
814
+ | `1001` | OrderId 不可為空 |
815
+ | `1002` | OrderId 已存在 |
816
+ | `1003` | BuyerIdentifier 格式錯誤 |
817
+ | `1004` | BuyerName 不可為空或無效值 (0/00/000/0000) |
818
+ | `1005` | ProductItem 不可為空 |
819
+ | `1006` | ProductItem 欄位不完整 |
820
+ | `1007` | 金額計算錯誤 |
821
+ | `1008` | TaxType 與 ProductItem TaxType 不符 |
822
+ | `1009` | 零稅率發票缺少必填欄位 (CustomsClearanceMark/ZeroTaxRateReason) |
823
+ | `1010` | 載具格式錯誤 |
824
+ | `1011` | 捐贈碼格式錯誤 |
825
+ | `1012` | 打統編發票不可使用載具或捐贈 |
826
+
827
+ ### 發票作廢錯誤
828
+
829
+ | 代碼 | 說明 |
830
+ |------|------|
831
+ | `2001` | 發票號碼不存在 |
832
+ | `2002` | 發票已作廢 |
833
+ | `2003` | 發票已超過作廢期限 |
834
+ | `2004` | B2B 交換發票無法作廢 (需由買方退回) |
835
+
836
+ ### 折讓單錯誤
837
+
838
+ | 代碼 | 說明 |
839
+ |------|------|
840
+ | `3001` | AllowanceNumber 不可為空 |
841
+ | `3002` | AllowanceNumber 已存在 |
842
+ | `3003` | 原發票號碼不存在 |
843
+ | `3004` | 折讓金額超過可折讓額度 |
844
+ | `3005` | 折讓單商品與原發票不符 |
845
+
846
+ ---
847
+
848
+ ## 補充說明
849
+
850
+ ### 光貿會員載具規則
851
+
852
+ 使用光貿會員載具 (CarrierType = `amego`) 時:
853
+
854
+ 1. **載具顯碼/隱碼格式:**
855
+ - `a` + 手機號碼,例如:`a0912345678`
856
+ - 電子信箱,例如:`test@example.com`
857
+
858
+ 2. **注意事項:**
859
+ - 載具顯碼或隱碼帶入電子信箱,並不會發送信件
860
+ - 若想發送信件,請另外填寫 `BuyerEmailAddress` 欄位
861
+
862
+ ### 統一編號、載具、捐贈碼檢查
863
+
864
+ **統編檢查邏輯:**
865
+ - 參考財政部「營利事業統一編號檢查碼邏輯修正說明」
866
+ - 可使用 `/json/ban_query` API 驗證統編與公司名稱
867
+
868
+ **載具與捐贈互斥規則:**
869
+ - 有統編:不可使用載具或捐贈
870
+ - 無統編:載具與捐贈二擇一
871
+ - 捐贈:不可使用載具
872
+ - 載具:不可捐贈
873
+
874
+ **手機條碼格式:**
875
+ - 以 `/` 開頭,共 8 碼
876
+ - 可使用 `/json/barcode` API 驗證
877
+
878
+ **自然人憑證格式:**
879
+ - 2 碼英文大寫 + 14 碼數字,共 16 碼
880
+
881
+ ---
882
+
883
+ ## 開立發票與自行配號說明
884
+
885
+ ### 開立發票 (自動配號) `/json/f0401`
886
+ - 光貿會自動分配發票號碼、開立時間及隨機碼
887
+ - 適合大部分情況使用
888
+ - 系統會按照後台「發票字軌列表」的排序開立
889
+ - 可透過 `TrackApiCode` 指定特定字軌
890
+
891
+ ### 開立發票 (API 配號) `/json/f0401_custom`
892
+ - 需自行指定發票號碼、日期時間、隨機碼
893
+ - 適合需要自行管理發票號碼的情況
894
+ - 需先透過 `/json/track_get` 取得字軌
895
+ - 發票號碼必須在取得的字軌範圍內
896
+
897
+ ---
898
+
899
+ ## 相關文件
900
+
901
+ - [速買配 API 規格](./SMILEPAY_API_REFERENCE.md)
902
+ - [綠界 API 規格](./ECPAY_API_REFERENCE.md)
903
+ - [發票開立流程](./INVOICE_FLOW.md)
904
+
905
+ ---
906
+
907
+ ## 聯絡客服
908
+
909
+ 如有任何問題,請聯絡光貿客服:
910
+ - **官方網站**:https://www.amego.tw
911
+ - **客服信箱**:請至官網查詢
912
+ - **測試後台**:https://invoice.amego.tw/
913
+
914
+ ---
915
+
916
+ ## 開發筆記 (踩坑紀錄)
917
+
918
+ > 以下是實際整合光貿電子發票 API 時遇到的問題與解決方案,供後續開發參考。
919
+
920
+ ### 1. 測試與正式環境共用 URL
921
+
922
+ **問題描述:**
923
+ 與綠界、速買配不同,光貿的測試與正式環境使用**同一個 API URL** (`https://invoice-api.amego.tw`),差別只在於使用的 `統編` 和 `App Key`。
924
+
925
+ **解決方案:**
926
+ ```typescript
927
+ // 光貿測試與正式共用同一個 API URL,差別在於使用的 key
928
+ // isProd 只是標記,不影響 API URL
929
+ private API_BASE_URL = 'https://invoice-api.amego.tw'
930
+ ```
931
+
932
+ 不需要根據環境切換 URL,只需要在設定頁面讓使用者輸入正確的測試/正式金鑰即可。
933
+
934
+ ---
935
+
936
+ ### 2. 必填欄位容易遺漏
937
+
938
+ **問題描述:**
939
+ 開立發票時 API 回傳錯誤,原因是遺漏了以下必填欄位:
940
+
941
+ - `FreeTaxSalesAmount` - 免稅銷售額(即使為 0 也必須填)
942
+ - `ZeroTaxSalesAmount` - 零稅率銷售額(即使為 0 也必須填)
943
+ - `TaxRate` - 稅率(必須填入字串 "0.05")
944
+ - `ProductItem[].TaxType` - 每個商品的課稅別(必填)
945
+
946
+ **解決方案:**
947
+ ```typescript
948
+ const amegoData = {
949
+ // ... 其他欄位
950
+ SalesAmount: salesAmount,
951
+ FreeTaxSalesAmount: 0, // 容易遺漏!即使為 0 也必填
952
+ ZeroTaxSalesAmount: 0, // 容易遺漏!即使為 0 也必填
953
+ TaxAmount: taxAmount,
954
+ TotalAmount: totalAmount,
955
+ TaxType: 1,
956
+ TaxRate: '0.05', // 容易遺漏!必填
957
+ ProductItem: data.ProductItem?.map(item => ({
958
+ Description: item.Description,
959
+ Quantity: item.Quantity,
960
+ UnitPrice: item.UnitPrice,
961
+ Amount: item.Amount,
962
+ TaxType: 1, // 容易遺漏!每個商品都要有 TaxType
963
+ })) || [],
964
+ }
965
+ ```
966
+
967
+ ---
968
+
969
+ ### 3. 隨機碼 (random_number) 必須儲存
970
+
971
+ **問題描述:**
972
+ 光貿開立發票成功後會回傳 `random_number`(隨機碼),這個值在列印發票時會用到。如果沒有儲存,可能導致列印時出現問題。
973
+
974
+ **解決方案:**
975
+ 1. 在 API 回應中正確取得並回傳 `randomNumber`:
976
+ ```typescript
977
+ return {
978
+ success: result.code === 0,
979
+ code: result.code,
980
+ msg: result.msg,
981
+ invoiceNumber: result.invoice_number,
982
+ randomNumber: result.random_number, // [重要] 記得回傳隨機碼
983
+ raw: result
984
+ }
985
+ ```
986
+
987
+ 2. 在資料庫中儲存隨機碼:
988
+ ```typescript
989
+ await prisma.financialRecord.update({
990
+ where: { id: recordId },
991
+ data: {
992
+ invoiceNo: result.invoiceNumber,
993
+ invoiceDate: new Date(),
994
+ invoiceRandomNum: result.randomNumber, // [重要] 儲存隨機碼
995
+ // ...
996
+ },
997
+ })
998
+ ```
999
+
1000
+ ---
1001
+
1002
+ ### 4. B2B vs B2C 金額計算差異 (DetailVat)
1003
+
1004
+ **問題描述:**
1005
+ 光貿使用 `DetailVat` 欄位來區分含稅/未稅價格計算方式:
1006
+ - `DetailVat = 0` - 未稅價(B2B 三聯式使用)
1007
+ - `DetailVat = 1` - 含稅價(B2C 二聯式使用,預設值)
1008
+
1009
+ **解決方案:**
1010
+ ```typescript
1011
+ const isB2B = data.IsB2B === true
1012
+
1013
+ // B2C: SalesAmount = 含稅總額, TaxAmount = 0, TotalAmount = 含稅總額
1014
+ // B2B: SalesAmount = 未稅, TaxAmount = 稅額, TotalAmount = 含稅
1015
+ const salesAmount = isB2B ? (data.SalesAmount || 0) : (data.TotalAmount || data.SalesAmount || 0)
1016
+ const taxAmount = isB2B ? (data.TaxAmount || 0) : 0
1017
+ const totalAmount = isB2B ? (data.TotalAmount || salesAmount + taxAmount) : salesAmount
1018
+
1019
+ const amegoData = {
1020
+ // ...
1021
+ DetailVat: isB2B ? 0 : 1, // [重要] B2B 使用未稅價 (0),B2C 使用含稅價 (1)
1022
+ SalesAmount: salesAmount,
1023
+ TaxAmount: taxAmount,
1024
+ TotalAmount: totalAmount,
1025
+ }
1026
+ ```
1027
+
1028
+ ---
1029
+
1030
+ ### 5. 發票列印需綁定服務商
1031
+
1032
+ **問題描述:**
1033
+ 如果使用者用光貿開立發票,之後將預設服務商切換成其他(如速買配),點選列印時會使用速買配的 API 去查詢光貿開立的發票,導致「查詢不到該發票」錯誤。
1034
+
1035
+ **解決方案:**
1036
+ 1. 開立發票時,將使用的服務商記錄到 `FinancialRecord`:
1037
+ ```typescript
1038
+ // issue-invoice/route.ts
1039
+ await prisma.financialRecord.update({
1040
+ where: { id: recordId },
1041
+ data: {
1042
+ invoiceNo: result.invoiceNumber,
1043
+ invoiceProvider: actualProvider as InvoiceProvider, // [重要] 儲存開立時使用的服務商
1044
+ // ...
1045
+ },
1046
+ })
1047
+ ```
1048
+
1049
+ 2. 列印發票時,優先使用記錄中的服務商:
1050
+ ```typescript
1051
+ // print-invoice/route.ts
1052
+ const service = record.invoiceProvider
1053
+ ? InvoiceServiceFactory.getService(record.invoiceProvider) // [重要] 使用開立時的服務商
1054
+ : await InvoiceServiceFactory.getServiceForUser(userId) // 降級:使用使用者預設
1055
+ ```
1056
+
1057
+ ---
1058
+
1059
+ ### 6. 列印發票 API 回傳 PDF URL
1060
+
1061
+ **問題描述:**
1062
+ 光貿的列印發票是透過 `/json/invoice_file` API 取得 PDF 檔案的臨時 URL,然後前端開啟該 URL。URL 有效期限只有 10 分鐘。
1063
+
1064
+ **解決方案:**
1065
+ ```typescript
1066
+ async printInvoice(userId: string, invoiceNumber: string): Promise<InvoicePrintResponse> {
1067
+ const settings = await this.getUserInvoiceSettings(userId)
1068
+
1069
+ const data = {
1070
+ type: 'invoice',
1071
+ invoice_number: invoiceNumber,
1072
+ download_style: 0 // A4 整張
1073
+ }
1074
+
1075
+ // ... 簽章計算
1076
+
1077
+ const response = await fetch(`${this.API_BASE_URL}/json/invoice_file`, {
1078
+ method: 'POST',
1079
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1080
+ body: params.toString(),
1081
+ })
1082
+
1083
+ const result = await response.json()
1084
+
1085
+ if (result.code === 0 && result.data?.file_url) {
1086
+ return {
1087
+ success: true,
1088
+ printUrl: result.data.file_url, // [重要] 回傳 PDF URL 給前端開啟
1089
+ }
1090
+ }
1091
+ }
1092
+ ```
1093
+
1094
+ 前端收到 `type: 'redirect'` 時直接開啟該 URL:
1095
+ ```typescript
1096
+ if (result.type === 'redirect' && result.url) {
1097
+ window.open(result.url, '_blank')
1098
+ }
1099
+ ```
1100
+
1101
+ ---
1102
+
1103
+ ### 7. 實作檔案參考
1104
+
1105
+ | 檔案 | 說明 |
1106
+ |------|------|
1107
+ | `lib/services/amego-service.ts` | 光貿 API 服務實作 |
1108
+ | `lib/services/invoice-service-factory.ts` | 發票服務工廠 |
1109
+ | `app/api/v1/financials/[id]/issue-invoice/route.ts` | 開立發票 API |
1110
+ | `app/api/v1/financials/[id]/print-invoice/route.ts` | 列印發票 API |
1111
+
1112
+ ---
1113
+
1114
+ 最後更新:2026/01/28
1115
+ 文件版本:MIG 4.0