---
title: 電子發票
description: 在結帳流程收集買家的電子發票資訊(載具、統編、捐贈),付款完成後自動開立
---

# 電子發票

當您的組織已連接電子發票服務(Amego 或 ezPay,可在後台「設定 → 整合 → 電子發票」設定)並開啟自動開立時,Recur 會在付款完成後自動為訂單開立電子發票。本頁說明如何在各種結帳整合方式中收集買家的發票選擇。

  **沒有啟用電子發票?** 一切照舊——所有 `einvoice` 相關欄位都是選填。未啟用時,合法的 `einvoice` 值不會影響結帳或觸發任何開立;但欄位**格式仍會被驗證**,格式錯誤(如統編檢查碼不符)無論是否啟用都會回 `422`。

## 發票選擇的格式(EinvoicePrefs)

買家的發票選擇是一個帶 `type` 的物件,四種類型:

| type | 額外欄位 | 說明 |
|------|---------|------|
| `personal` | — | 個人雲端發票,寄送至買家 Email |
| `mobile_barcode` | `carrier_code` | 手機條碼載具,`/` 開頭共 8 碼(如 `/ABC1234`) |
| `ubn` | `ubn`、`buyer_name` | 公司統編三聯式;統編 8 位數字(驗證檢查碼)+ 公司抬頭 |
| `donation` | `donation_code` | 捐贈發票,愛心碼 3–7 位數字(如 `25885`) |

請求本文接受 `snake_case`(建議)與 `camelCase`(如 `carrierCode`)兩種寫法;回應一律為 `snake_case`。格式錯誤(統編檢查碼不符、手機條碼格式錯誤等)會在建立/付款當下回 `422 validation_error`,不會等到開立發票時才失敗。

## Hosted Checkout(最簡單)

託管結帳頁會在組織啟用電子發票時**自動顯示發票資訊區塊**,買家自行選擇,無需任何額外整合。

若您已在自己的系統收集過買家的發票偏好,可在建立 Session 時帶入 `einvoice` 作為預填(買家在結帳頁仍可修改):

```bash
curl -X POST https://api.recur.tw/v1/checkout/sessions \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "prod_abc123",
    "success_url": "https://example.com/success",
    "cancel_url": "https://example.com/pricing",
    "einvoice": { "type": "ubn", "ubn": "04595252", "buyer_name": "恆吉股份有限公司" }
  }'
```

SDK 的 `redirectToCheckout` / `createCheckoutSession` 也接受同一個選項(camelCase):

```typescript
await recur.redirectToCheckout({
  productId: 'prod_abc123',
  successUrl: 'https://example.com/success',
  cancelUrl: 'https://example.com/cancel',
  einvoice: { type: 'mobile_barcode', carrierCode: '/ABC1234' },
});
```

## Embedded / Modal Checkout(SDK 內建 UI)

使用 `recur.checkout({ mode: 'modal' })` 或 `mode: 'iframe'` 時,SDK 的支付表單會在組織啟用電子發票時**自動渲染發票資訊區塊**(與託管結帳頁相同的四個選項與驗證),並在買家送出付款時一併帶上發票選擇——您不需要寫任何程式碼。

預填順序:您在 `checkout()` 傳入的 `einvoice` 選項 → 買家先前的發票偏好(客戶記憶)→ 個人雲端發票。

```typescript
// 可選:帶入您系統中已知的偏好作為預填
recur.checkout({
  productId: 'prod_abc123',
  mode: 'modal',
  einvoice: { type: 'donation', donationCode: '25885' },
});
```

## 自行組裝 UI(進階)

若您使用低階 API 自行渲染結帳流程,有兩個掛載點:

**建立時**傳入(`POST /v1/checkouts`):

```json
{ "product_id": "prod_abc123", "einvoice": { "type": "personal" } }
```

**付款時**傳入(`POST /v1/checkouts/{id}/pay`),適合在自己的表單收集後才確定選擇。付款時的值會覆蓋建立時的值:

```json
{ "creditToken": "...", "timestamp": 1234567890, "einvoice": { "type": "ubn", "ubn": "04595252", "buyer_name": "恆吉股份有限公司" } }
```

判斷是否需要顯示發票欄位:`POST /v1/checkouts` 與 `GET /v1/checkouts/{id}` 的回應都帶有 `einvoice_enabled`,且附上 `einvoice_defaults` 預填值(此結帳已儲存的選擇 → 客戶記憶 → `{ "type": "personal" }`)。

SDK 也匯出驗證工具供您在前端即時驗證:

```typescript
import { validateEinvoicePrefs, isValidTaiwanUbn } from 'recur-tw';

validateEinvoicePrefs({ type: 'ubn', ubn: '04595252', buyerName: '恆吉股份有限公司' }); // null = 合法
isValidTaiwanUbn('12345678'); // false(檢查碼不符)
```

## 查詢開立結果(API 讀回)

`GET /v1/orders/{id}` 與 `GET /v1/invoices/{id}`(及 list)的回應帶有 `einvoice` 物件(未開立或未啟用時為 `null`):

```json
{
  "id": "ord_abc123",
  "einvoice": {
    "status": "ISSUED",
    "invoice_number": "ZA12345678",
    "random_code": "5417",
    "invoice_date": "2026-07-22",
    "sales_amount": 762,
    "tax_amount": 38,
    "total_amount": 800,
    "tax_type": "TAXABLE",
    "buyer": { "type": "mobile_barcode", "carrier_code": "/ABC1234" },
    "voided_at": null,
    "void_reason": null,
    "allowances": []
  }
}
```

`status` 為 `PENDING`(開立中,系統會自動重試)/ `ISSUED` / `FAILED`(附 `failure_message`)/ `VOIDED`。發票號碼與隨機碼為對獎資訊,只在 Secret Key 認證下回傳。

## Webhook 事件

開立/作廢/折讓會發送 `einvoice.issued`、`einvoice.issue_failed`(僅最終失敗)、`einvoice.voided`、`einvoice.allowance_created` 事件,SANDBOX 也會發送方便測試。完整 payload 見 [Webhook 事件](/guides/webhooks/events#電子發票事件einvoice)。

## 開立與記憶

- 付款完成(含 3D 驗證後經 webhook 完成)後,發票依買家選擇自動開立;未提供選擇時,依買家先前記憶的偏好,最後回落為個人雲端發票。
- 買家明確選擇過的偏好會記憶在客戶資料上,下次結帳自動預填。
- 退款時自動作廢或開立折讓,無需額外處理。

  開立結果可在後台訂單詳情頁查看(發票號碼、狀態、作廢/折讓紀錄)。

