> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 预览税额

> 渐进式查询收银台会话的税务规则并计算税额

查询适用于某个收银台会话的税务规则；当已收集到足够的账单信息时，返回计算出的税额。

该端点为**渐进式采集**设计：只有 `billingDetail.country` 是必需的。响应会通过 `rules.requiredFields` 告知该国家还需要哪些字段，因此收银台表单可以逐步询问，而不必一次性索要全部信息。

```
POST /v1/actions/checkout/preview-tax
```

**认证方式：** Store Slug（`visitor` 角色）

<Note>
  托管收银台页面会在 customer 填写账单信息的过程中调用该端点。如果你自建收银台界面，请在 customer 的国家或企业身份发生变化时调用它。
</Note>

## 请求体

| 字段                  | 类型     | 必需 | 说明                                                                             |
| ------------------- | ------ | -- | ------------------------------------------------------------------------------ |
| `checkoutSessionId` | string | 是  | [创建收银台会话](/zh/api-reference/endpoints/orders/create-checkout-session) 返回的会话 ID |
| `billingDetail`     | object | 是  | 目前已收集到的账单信息（见下方）                                                               |

### billingDetail

| 字段             | 类型      | 必需 | 说明                                         |
| -------------- | ------- | -- | ------------------------------------------ |
| `country`      | string  | 是  | ISO 3166-1 alpha-2 国家代码（例如 `US`、`DE`、`JP`） |
| `isBusiness`   | boolean | 否  | 是否为企业购买                                    |
| `state`        | string  | 否  | 州/省代码                                      |
| `postcode`     | string  | 否  | 邮政编码                                       |
| `businessName` | string  | 否  | 企业法定名称                                     |
| `taxId`        | string  | 否  | 企业税务登记号（例如欧盟 VAT 号码）                       |

只有 `country` 是必需的。**剩余字段中哪些需要收集，由响应给出**，而不是按国家写死的规则 —— 见 `rules.requiredFields`。

## 响应

| 字段            | 类型             | 说明                     |
| ------------- | -------------- | ---------------------- |
| `currency`    | string         | 收银台会话的货币               |
| `rules`       | object         | 给定国家的税务规则              |
| `calculation` | object \| null | 计算出的金额；仍需补充字段时为 `null` |

### rules

| 字段                          | 类型      | 说明                     |
| --------------------------- | ------- | ---------------------- |
| `country`                   | string  | 规则适用的国家代码              |
| `taxName`                   | string  | 税种名称（例如 `JCT`、`VAT`）   |
| `standardRate`              | number  | 标准税率，小数表示（`0.1` = 10%） |
| `isTaxFree`                 | boolean | 该国家是否免税                |
| `isEuReverseChargeEligible` | boolean | 是否可适用欧盟反向征收            |
| `hasReducedRates`           | boolean | 部分商品类别是否存在优惠税率         |
| `requiredFields`            | array   | 计算税额前仍需补充的字段（见下方）      |

### requiredFields

每一项描述收银台表单接下来应收集的一个字段：

| 字段          | 类型     | 说明                                                        |
| ----------- | ------ | --------------------------------------------------------- |
| `field`     | string | `isBusiness`、`state`、`postcode`、`businessName`、`taxId` 之一 |
| `label`     | string | 供输入框使用的可读标签                                               |
| `reason`    | string | 该国家为何需要它 —— 可直接展示给 customer                               |
| `inputType` | string | 建议使用的输入控件                                                 |

`requiredFields` 为空时，`calculation` 有值。

### calculation

| 字段          | 类型     | 说明                     |
| ----------- | ------ | ---------------------- |
| `subtotal`  | string | 税前金额，显示格式（例如 `"8.39"`） |
| `taxAmount` | string | 税额，显示格式                |
| `total`     | string | customer 实际被扣收的金额      |
| `taxRate`   | number | 本笔订单适用的税率              |

<Note>
  金额为显示格式字符串，与 API 其余部分保持一致。`taxRate` 为小数（`0.19` = 19%）。
</Note>

## 示例

<CodeGroup>
  ```bash 信息仍不完整 theme={"system"}
  curl -X POST https://api.waffo.ai/v1/actions/checkout/preview-tax \
    -H "X-Store-Slug: my-store-abc123" \
    -H "X-Environment: prod" \
    -H "Content-Type: application/json" \
    -d '{
      "checkoutSessionId": "cs_xxx",
      "billingDetail": { "country": "US" }
    }'
  ```

  ```bash 可以计算 theme={"system"}
  curl -X POST https://api.waffo.ai/v1/actions/checkout/preview-tax \
    -H "X-Store-Slug: my-store-abc123" \
    -H "X-Environment: prod" \
    -H "Content-Type: application/json" \
    -d '{
      "checkoutSessionId": "cs_xxx",
      "billingDetail": { "country": "DE", "isBusiness": false }
    }'
  ```
</CodeGroup>

信息仍不完整 —— 表单接下来应询问 `state`：

```json theme={"system"}
{
  "data": {
    "currency": "USD",
    "rules": {
      "country": "US",
      "taxName": "Sales Tax",
      "standardRate": 0,
      "isTaxFree": false,
      "isEuReverseChargeEligible": false,
      "hasReducedRates": false,
      "requiredFields": [
        {
          "field": "state",
          "label": "State",
          "reason": "Sales tax in the United States is determined at state level",
          "inputType": "select"
        }
      ]
    },
    "calculation": null
  }
}
```

可以计算：

```json theme={"system"}
{
  "data": {
    "currency": "EUR",
    "rules": {
      "country": "DE",
      "taxName": "VAT",
      "standardRate": 0.19,
      "isTaxFree": false,
      "isEuReverseChargeEligible": true,
      "hasReducedRates": true,
      "requiredFields": []
    },
    "calculation": {
      "subtotal": "8.39",
      "taxAmount": "1.60",
      "total": "9.99",
      "taxRate": 0.19
    }
  }
}
```

## 错误响应

| 状态码 | 消息                                                 | 原因                                       |
| --- | -------------------------------------------------- | ---------------------------------------- |
| 400 | `Missing required field: checkoutSessionId`        | 未提供 `checkoutSessionId`                  |
| 400 | `Missing required field: billingDetail.country`    | `billingDetail` 缺失或其中没有 `country`        |
| 400 | `Missing or invalid header: x-context-environment` | `X-Environment` 请求头缺失或不是 `test` / `prod` |
| 404 | `Checkout session not found or expired`            | 会话不存在、已过期、属于其他门店，或创建于另一个环境               |
| 500 | `Internal server error`                            | 服务端意外失败                                  |

## 当前税务覆盖范围

税额判定基于 customer 的账单地，税务义务由 Waffo Pancake 作为记录商（Merchant of Record）承担。按当前配置的覆盖范围，**所有国家返回的 `taxAmount` 与 `taxRate` 均为 `0`** —— 本端点是某笔订单实际扣收金额的权威来源，因此请读取 `calculation.total`，而不要假定某个税率。

`rules.requiredFields` 同样由线上配置驱动。不要在收银台界面里写死「美国和加拿大需要 state」或「欧盟企业需要税号」—— 按响应要求的内容渲染即可。
