# 政府預算查詢平台 — `tw.openfun~api~tw.budget`

給 AI 閱讀的使用指引。人類可在 https://data.openfun.tw/datasets/tw.openfun~api~tw.budget 看到資料集說明。

臺灣中央與 22 個縣市政府「總預算書」的歲出、歲入、基金用途查詢 API。資料
來源是各級政府公告的總預算書 PDF，經過解析、正規化後存入 Elasticsearch，
網站 https://budget.openfun.app 跟這份 API 讀的是同一份資料，網站上能查到
的東西，這份 API 基本上都能查到。

---

## ⚠️ 開始之前（AI agent 必讀）

**Base URL**：`https://budget.openfun.app/api`
**認證**：使用 data.openfun.tw 核發的 Bearer Token 可解除流量限制；不帶
Token 仍可呼叫，但可能因超過流量門檻被擋（門檻隨時調整，不保證特定
數字）。
**回應格式**：一律 `application/json`，CORS 完全開放（前端可直接呼叫）。

最簡查詢範例：
```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/county/中央/115/歲出"
```

**取得 Token 方式（Device Authorization Grant）：**
```bash
# 步驟一：取得驗證連結
curl -X POST https://data.openfun.tw/api/v1/auth/device

# 步驟二：在瀏覽器開啟回應中的 verification_uri_complete，用 Google 帳號登入授權

# 步驟三：輪詢取得 Token（約 10-30 秒後成功）
curl -X POST https://data.openfun.tw/api/v1/auth/token \
  -d "device_code=DEVICE_CODE_FROM_STEP1"
```
若無 Token，也可在 https://data.openfun.tw/user 登入後從 Dashboard 取得
長效 API 金鑰。

禁止用 WebFetch 抓 HTML 頁面，請直接呼叫 API。

OpenAPI 規格：`https://budget.openfun.app/swagger`（互動式文件：
`https://budget.openfun.app/swagger/ui`）。更完整的背景知識（資料涵蓋
範圍、名詞對應的法規依據）見 [knowledge.md](knowledge.md)。

---

## ⚠️ 金額單位，非常重要

**除了 `type=基金用途` 以外，所有端點回傳的金額欄位單位都是「元」**，
不是「千元」（總預算書 PDF 印出來大多是千元，但這份 API 已經統一換算
成元了）。`/api/county/{county}/{year}/基金用途` 這一個 type 例外，
回傳單位是「千元」（對應網站上基金比較表的顯示邏輯），使用時務必注意，
不要把兩者的金額直接加總或比較。

## ⚠️ 資料涵蓋範圍與已知限制

收錄範圍：中央 92-116 年度、六都及大部分縣市涵蓋度不一（100 年度以後
普遍較完整），實際涵蓋範圍請用 `/api/counties`（歲出/歲入）、
`/api/countiesfund`（基金）查詢，不要假設所有年度都有資料。已知造成
缺口的原因：

- 部分較舊年度的原始 PDF 是掃描檔，沒有可抽取的文字層，無法解析。
- 部分縣市網站需要 ASP.NET `__doPostBack()` 表單才能切換年度，或有
  Cloudflare／JS 動態載入限制，暫時無法自動收錄。
- 基金分支明細（`/fundplan`）目前只有臺南市、新竹市有資料，其他縣市
  呼叫會拿到 `{"來源":null,"records":[]}`（空結果，不是錯誤）。
- 歲出分支明細裡的 `結構化細項`（把冗長的「說明」文字拆解出的子項目）
  目前只做了中央政府 115 年度，且約 8% 的項目因敘述格式特殊沒有拆解
  成功（`結構化細項` 會是 `null`，不會給錯誤的假數字）。

---

## 端點與查詢說明

| 方法 | 路徑 | 說明 |
|---|---|---|
| GET | `/county/{county}/{year}/{type}` | 某縣市某年度的預算明細（`type`：歲出／歲入／基金用途，預設歲出） |
| GET | `/counties` | 全部縣市/年度彙整資料（含歲出/歲入攤平列表、人口數） |
| GET | `/countiesfund` | 有基金資料的縣市/年度清單 |
| GET | `/plan/{county}/{type}/{id}/{year}` | 某個工作計劃/細目的分支明細（`type`：歲出／歲入） |
| GET | `/fundplan/{county}/{id}/{year}` | 某個基金工作計劃的分支明細 |
| GET | `/search?q=&p=&type=` | 全文搜尋歲出/歲入分支計畫（`type=fund` 改搜基金用途明細） |
| GET | `/stat` | 全縣市/年度的預算案、法定預算、決算總額統計 |

完整參數/回應 schema 見 `openapi.yaml`（`/swagger`）。以下是實際測試過、
可直接執行的查詢範例。

### 查某縣市某年度的歲出（依政事別彙整的工作計劃列表）

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/county/中央/115/歲出"
```

回應裡每筆 `工作計劃` 項目的 `編號` 欄位就是「工作計畫編號」，可以接著
拿去查 `/plan/...` 看更細的分支計畫內容。

### 查某個工作計畫的分支明細（含逐項說明、部分已拆解出結構化子項目）

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/plan/中央/歲出/3808219002/115"
```

`records[].明細[]` 是「用途別編號/名稱/說明/預算數」的階層資料。其中
`層級=0` 的項目原本「說明」欄位是一整段落落長的文字（例如「1.精實員警
教育訓練計畫...2.警察公墓南區分址中長程個案興建計畫...」），部分（目前
僅涵蓋中央/115 年度，涵蓋率約 92%）已經用規則式比對／LLM 輔助拆解出
`結構化細項`（巢狀的 `{name, amount, children}` 列表），`結構化細項_信心`
標示拆解結果跟原始金額是否完全吻合（`exact`）或有 5% 以內的誤差
（`close`）；沒拆解出來的項目這個欄位會是 `null`，請不要假設一定存在。

### 全文搜尋（可加篩選條件）

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/search?q=%E8%AD%A6%E6%94%BF&p=1"
```

`q` 支援空白分隔多個詞（各自精確片語比對），`p` 是頁數（每頁 10 筆）。
可加 `縣市=`、`年度=`、`種類=`、`預算機關=` 篩選（可重複帶多次疊加多個
值），例如 `?q=長照&縣市=臺北市&縣市=新北市`。回傳的 `aggs` 欄位是這次
查詢在各篩選維度下的命中數，適合拿來畫篩選側邊欄。搜基金用途明細改用
`type=fund`：

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/search?q=%E9%9A%9C%E7%A2%8D&type=fund"
```

### 查基金分支明細

`id` 要用「基金名稱-預算機關-業務計劃-工作計劃」組合鍵（從
`/county/{county}/{year}/基金用途` 或 `/search?type=fund` 回應的 `編號`
欄位取得，記得 URL encode）：

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://budget.openfun.app/api/fundplan/臺南市/臺南市殯葬事業管理基金-臺南市政府民政局-(無計畫名稱)-(無工作計劃)/115"
```

### 全國/全縣市統計

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" "https://budget.openfun.app/api/counties"   # 逐筆攤平資料，適合自己再彙整
curl -H "Authorization: Bearer YOUR_TOKEN" "https://budget.openfun.app/api/stat"       # 已經彙整好的縣市/年度加總數字
```

---

## 快速參考

| 項目 | 說明 |
|------|------|
| Base URL | `https://budget.openfun.app/api` |
| 認證 | `Authorization: Bearer {token}` 可解除流量限制（不帶也能呼叫） |
| 取得 Token | https://data.openfun.tw/user |
| OpenAPI 規格 | https://budget.openfun.app/swagger |
| 互動式文件 | https://budget.openfun.app/swagger/ui |
| 背景知識文件（資料涵蓋範圍、法源依據） | https://budget.openfun.app/knowledge.md |
| 金額單位 | 元（僅 `基金用途` type 例外為千元，見上方警告） |
| 分頁 | `/search` 用 `p`（每頁 10 筆）；其餘端點不分頁 |
