---
# System prepended metadata

title: 用 Markdown 寫 API 規格教學

---

# 用 Markdown 寫 API 規格教學
> 範例以「案件申貸狀態同步」與「案件推廣來源」兩個端點示範。

[TOC]

---

## 1. 文件說明（Overview）

- **目的**：用 *Markdown* 撰寫一份清楚、可維護的 **API 規格**，包含端點定義、參數、請求/回應格式、錯誤碼、範例與 JSON Schema。
- **風格**：採「純 Markdown」為主，並補充「API Blueprint 速記法」區塊，方便團隊快速擬稿。
- **版本**：v1.0.0
- **主機（HOST）**：`https://[domain]/service/api/{Action}`
- **認證**：`Authorization: Bearer {ACCESS_TOKEN}`
- **內容格式**：`application/json; charset=utf-8`

---

## 2. 全域慣例（Conventions）

- **時間格式**：除非特別註明，皆為 `yyyyMMdd` 或 `yyyy-MM-ddTHH:mm:ssZ`（UTC）。
- **字串編碼**：UTF-8。
- **安全性**：所有寫入類（POST/PUT/PATCH/DELETE）應驗證 Bearer Token。
- **冪等性（Idempotency）**：建議對關鍵寫入操作設計冪等鍵（如 `UPD_KEY`）。
- **錯誤模型**：統一以 `Result.ReturnCode != 0` 作為非成功訊號（見 §6）。

---

## 3. 快速藍本：API Blueprint 速記法（*可選*）

> 若團隊熟悉 API Blueprint，可用下列速記區塊在 HackMD 擬稿，等同於「規格提綱」。

```apib
FORMAT: 1A
HOST: https://[domain]/service/api/{Action}

# 雲端API

## 案件申貸狀態同步 [/SyncLoanCase]

### 取得案件申貸狀態 [GET]
+ Response 200 (application/json)

        [
          { /* ... */ }
        ]

### 異動案件申貸狀態、相關欄位 [POST]
+ Headers
      Authorization: Bearer {ACCESS_TOKEN}
+ Request (application/json)

        { /* 請見正式規格 §4.2 請求體 */ }

+ Response 200 (application/json)

        { /* 請見正式規格 §4.3 回應體 */ }
```

> 下方為「正式 Markdown 版規格」，提供完整欄位說明、枚舉、JSON Schema 與範例。

---

## 4. 端點：案件申貸狀態同步 `/SyncLoanCase`

### 4.1 取得案件申貸狀態（GET）

- **Method**：`GET /SyncLoanCase`
- **說明**：依查詢條件取得案件申貸狀態列表（若未提供條件，依系統預設限制返回最近更新）。
- **查詢參數（Query）**：
  | 參數 | 型別 | 必填 | 範例 | 說明 |
  |---|---|---|---|---|
  | `caseId` | string | 否 | `TEST123` | 指定單一案件編號 |
  | `updatedSince` | string(yyyyMMdd) | 否 | `20250101` | 只取此日期（含）之後異動 |
  | `page` | int | 否 | `1` | 分頁頁碼（>=1） |
  | `pageSize` | int | 否 | `50` | 單頁筆數（<=100） |

- **成功回應 200（application/json）**：

```json
[
  {
    "CASE_ID": "TEST123",
    "CASE_STATUS": "1",
    "CASE_TYPE": "1",
    "UPDATED_AT": "2025-10-01T08:30:00Z"
  }
]
```

- **錯誤回應**：見 §6 錯誤模型。

---

### 4.2 異動案件申貸狀態、相關欄位（POST）

- **Method**：`POST /SyncLoanCase`
- **說明**：更新案件申貸狀態與周邊資訊，支援冪等鍵 `UPD_KEY` 以避免重複寫入。
- **必要標頭（Headers）**：
  - `Authorization: Bearer {ACCESS_TOKEN}`
  - `Content-Type: application/json`

- **請求體（Request Body）**：主要欄位如下；完整驗證規則見 §7 JSON Schema。

  | 欄位 | 型別/格式 | 必填 | 範例 | 說明 |
  |---|---|---|---|---|
  | `MOTO_CASE_MAJ` | string | 是 | `"string"` | 案件唯一值 |
  | `CASE_TYPE` | enum string | 否 | `"1"` | `0=None, 1=Mobile, 2=Scooter, 3=Hybrid` |
  | `CASE_STATUS` | string | 否 | `"1"` | 申貸狀態代碼（內規定義） |
  | `PRD_NUM` | string | 否 | `"4000"` | 商品代碼 |
  | `PRD_AMT` | string | 否 | `"4000"` | 商品金額 |
  | `LOAN_AMT` | string | 否 | `"4000"` | 申貸金額 |
  | `HAND_FEE` | string | 否 | `"4000"` | 手續費 |
  | `DSB_AMT` | string | 否 | `"4000"` | 撥款金額 |
  | `CR_DOC_FILE_U_ID` | uuid string | 否 | `"ee1d662d-54ca-441e-919a-abe93b15d51d"` | 徵審文件檔 UUID |
  | `UPD_KEY` | string | 是 | `"{UPD_KEY}"` | 冪等鍵（同請求多次只生效一次） |
  | `SIGN_CONTRACT` | `"0"|"1"` | 否 | `"1"` | 是否簽約 |
  | `PAYMENT_UNUSUAL` | `"0"|"1"` | 否 | `"1"` | 付款是否異常 |
  | `CONTRACT_BEFORE_FILE_UUID` | uuid | 否 | `"ee1d...d51d"` | 簽約前檔案 |
  | `CONTRACT_SIGN_FILE_UUID` | uuid | 否 | `"ee1d...d51d"` | 簽約後檔案 |
  | `IS_ABT` | `"0"|"1"` | 否 | `"1"` | 是否棄件/撤件（依定義） |
  | `IS_END` | `"0"|"1"` | 否 | `"1"` | 是否已結案 |
  | `CONTACT_METHOD` | enum | 否 | `"1"` | 連絡方式代碼 |
  | `APP_FIRST_DT` | string(yyyyMMdd) | 否 | `"19990101"` | 初次申請日 |
  | `CREDIT_SCORE` | string | 否 | `"80"` | 信評分數 |
  | `CUST_ID` | string | 否 | `"X123123123"` | 身分證/統編 |
  | `MOBILE_1` | string | 否 | `"0912123123"` | 手機 |
  | `MOVABLES_AMT` | string | 否 | `"20000"` | 動產金額 |
  | `REAL_DSB_AMT` | string | 否 | `"1500"` | 實際撥款金額 |
  | `CC` | string | 否 | `"100"` | 其他代碼 |
  | `BIRTHDAY` | string(yyyyMMdd) | 否 | `"19880707"` | 生日 |
  | `MOBILE_IMEI_01` | string | 否 | `"357221098977524"` | IMEI |
  | `MOBILE_IMEI_02` | string | 否 | `"353990106364578"` | 备用 IMEI |
  | `MOBILE_BRAND` | string | 否 | `"Apple"` | 手機品牌 |
  | `MOBILE_MODEL` | string | 否 | `"6s"` | 手機型號 |
  | `ID_CARD_DATE` | string | 否 | `"20200101"` | 證件發證日（如適用） |
  | `CASE_ID` | string | 否 | `"TEST123"` | 案件代碼（系統/外部來源） |

- **請求體範例**：

```json
{
  "MOTO_CASE_MAJ": "string",
  "CASE_TYPE": "1",
  "CASE_STATUS": "1",
  "PRD_NUM": "4000",
  "PRD_AMT": "4000",
  "LOAN_AMT": "4000",
  "HAND_FEE": "4000",
  "DSB_AMT": "4000",
  "CR_DOC_FILE_U_ID": "ee1d662d-54ca-441e-919a-abe93b15d51d",
  "UPD_KEY": "{UPD_KEY}",
  "SIGN_CONTRACT": "1",
  "PAYMENT_UNUSUAL": "1",
  "CONTRACT_BEFORE_FILE_UUID": "ee1d662d-54ca-441e-919a-abe93b15d51d",
  "CONTRACT_SIGN_FILE_UUID": "ee1d662d-54ca-441e-919a-abe93b15d51d",
  "IS_ABT": "1",
  "IS_END": "1",
  "CONTACT_METHOD": "1",
  "APP_FIRST_DT": "19990101",
  "CREDIT_SCORE": "80",
  "CUST_ID": "X123123123",
  "MOBILE_1": "0912123123",
  "MOVABLES_AMT": "20000",
  "REAL_DSB_AMT": "1500",
  "CC": "100",
  "BIRTHDAY": "19880707",
  "MOBILE_IMEI_01": "357221098977524",
  "MOBILE_IMEI_02": "353990106364578",
  "MOBILE_BRAND": "Apple",
  "MOBILE_MODEL": "6s",
  "ID_CARD_DATE": "20200101",
  "CASE_ID": "TEST123"
}
```

- **成功回應 200（application/json）**：

```json
{
  "Data": {
    "IS_SUCCESS": "Y",
    "ERR_MSG": ""
  },
  "Result": {
    "ReturnCode": 0,
    "ReturnMsg": "更新成功",
    "Alert": "更新成功",
    "Count": 1
  }
}
```

- **常見狀態碼**：
  - `200 OK`：更新成功
  - `400 Bad Request`：參數格式錯誤、缺少必填欄位
  - `401 Unauthorized`：Token 失效或未帶入
  - `409 Conflict`：冪等鍵重複提交（已處理）
  - `422 Unprocessable Entity`：商業規則未通過
  - `500 Internal Server Error`：伺服器錯誤

---

## 5. 端點：案件推廣來源 `/NewsSrc`

### 5.1 取得案件推廣來源（GET）

- **Method**：`GET /NewsSrc`
- **說明**：取得推廣來源清單（僅返回 `IsEnable=1` 且依 `Sort` 排序）。
- **成功回應 200（application/json）**：

```json
[
  { "NewsValue": 1, "NewsText": "Google搜尋" },
  { "NewsValue": 16, "NewsText": "貸鼠先生" },
  { "NewsValue": 2, "NewsText": "網路廣告" },
  { "NewsValue": 3, "NewsText": "簡訊推廣" },
  { "NewsValue": 4, "NewsText": "新聞網站" },
  { "NewsValue": 48, "NewsText": "電話推廣" },
  { "NewsValue": 5, "NewsText": "報章雜誌" },
  { "NewsValue": 6, "NewsText": "電視媒體" },
  { "NewsValue": 7, "NewsText": "親友介紹" }
]
```

---

## 6. 統一錯誤模型與處理建議

- **回應結構**（建議）：
  ```json
  {
    "Result": {
      "ReturnCode": 1234,
      "ReturnMsg": "錯誤訊息",
      "TraceId": "dd0c836e-...",
      "Alert": "可顯示給使用者的友善提示"
    },
    "Data": null
  }
  ```
- **處理原則**：
  - `ReturnCode = 0` 視為成功，其餘為失敗。
  - 需記錄 `TraceId` 於後端日誌，方便追查。
  - 對外錯誤訊息應避免洩露內部系統訊息。

---

## 7. JSON Schema（請求體驗證：/SyncLoanCase POST）

> 可用於前後端驗證與合約測試。

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "SyncLoanCaseRequest",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "MOTO_CASE_MAJ": { "type": "string", "minLength": 1 },
    "CASE_TYPE": { "type": "string", "enum": ["0", "1", "2", "3"] },
    "CASE_STATUS": { "type": "string" },
    "PRD_NUM": { "type": "string" },
    "PRD_AMT": { "type": "string", "pattern": "^[0-9]+$" },
    "LOAN_AMT": { "type": "string", "pattern": "^[0-9]+$" },
    "HAND_FEE": { "type": "string", "pattern": "^[0-9]+$" },
    "DSB_AMT": { "type": "string", "pattern": "^[0-9]+$" },
    "CR_DOC_FILE_U_ID": { "type": "string", "format": "uuid" },
    "UPD_KEY": { "type": "string", "minLength": 1 },
    "SIGN_CONTRACT": { "type": "string", "enum": ["0", "1"] },
    "PAYMENT_UNUSUAL": { "type": "string", "enum": ["0", "1"] },
    "CONTRACT_BEFORE_FILE_UUID": { "type": "string", "format": "uuid" },
    "CONTRACT_SIGN_FILE_UUID": { "type": "string", "format": "uuid" },
    "IS_ABT": { "type": "string", "enum": ["0", "1"] },
    "IS_END": { "type": "string", "enum": ["0", "1"] },
    "CONTACT_METHOD": { "type": "string" },
    "APP_FIRST_DT": { "type": "string", "pattern": "^\\d{8}$" },
    "CREDIT_SCORE": { "type": "string", "pattern": "^[0-9]+$" },
    "CUST_ID": { "type": "string" },
    "MOBILE_1": { "type": "string" },
    "MOVABLES_AMT": { "type": "string", "pattern": "^[0-9]+$" },
    "REAL_DSB_AMT": { "type": "string", "pattern": "^[0-9]+$" },
    "CC": { "type": "string" },
    "BIRTHDAY": { "type": "string", "pattern": "^\\d{8}$" },
    "MOBILE_IMEI_01": { "type": "string", "pattern": "^\\d{14,17}$" },
    "MOBILE_IMEI_02": { "type": "string", "pattern": "^\\d{14,17}$" },
    "MOBILE_BRAND": { "type": "string" },
    "MOBILE_MODEL": { "type": "string" },
    "ID_CARD_DATE": { "type": "string" },
    "CASE_ID": { "type": "string" }
  },
  "required": ["MOTO_CASE_MAJ", "UPD_KEY"]
}
```

---

## 8. 範例請求（cURL / C#）

### 8.1 cURL：POST /SyncLoanCase
```bash
curl -X POST "https://[domain]/service/api/SyncLoanCase" \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "MOTO_CASE_MAJ": "string",
    "UPD_KEY": "abc123",
    "CASE_STATUS": "1"
  }'
```

### 8.2 C#：POST /SyncLoanCase（RestSharp 範例）
```csharp
var client = new RestClient("https://[domain]/service/api/SyncLoanCase");
var req = new RestRequest(Method.Post);
req.AddHeader("Authorization", "Bearer {ACCESS_TOKEN}");
req.AddHeader("Content-Type", "application/json");
req.AddStringBody(@"{
  ""MOTO_CASE_MAJ"": ""string"",
  ""UPD_KEY"": ""abc123"",
  ""CASE_STATUS"": ""1""
}", DataFormat.Json);

var res = await client.ExecuteAsync(req);
Console.WriteLine(res.Content);
```

---

## 9. Database 參考 SQL（對應 `/NewsSrc`）

```sql
/****** SSMS 中 SelectTopNRows 命令的指令碼 ******/
SELECT [NewsValue], [NewsText]
FROM [dbo].[NEWS_OPTION]
WHERE IsEnable = 1
ORDER BY [Sort];
```

---

## 10. 撰寫檢查清單（Checklist）

- [ ] 主機/環境位址是否明確（Dev/SIT/UAT/Prod）
- [ ] 認證與權限（Bearer、Scopes）是否定義
- [ ] 必填欄位與枚舉值是否完整列出
- [ ] JSON Schema 是否覆蓋格式/型別/模式
- [ ] 回應模型（成功/錯誤）是否一致
- [ ] 範例（cURL/C#）是否可直接執行
- [ ] 變更紀錄（Changelog）是否更新

---

## 11. 變更紀錄（Changelog）
- **v1.0.0 (2025-10-06)**：初版釋出（新增 `/SyncLoanCase`、`/NewsSrc` 規格、JSON Schema、範例程式、SQL 參考）。
