← 回首頁 English

AstroChart API 文件BETA

占星星盤運算 API — 本命盤、合盤、行運、推運、太陽回歸、組合盤

總覽

Base URL 為 同源(same-origin):所有路徑皆為相對路徑(例如 /api/v1/charts),直接對本站發送請求即可。

本 API 目前為 Beta、開放測試(open beta)狀態

API 金鑰為選填:你可自行帶上金鑰把用量歸戶到該金鑰,並用 GET /api/v1/usage 查詢自己的用量。目前開放模式下不帶金鑰也能正常呼叫;未來伺服器可能切換為 required 模式,屆時匿名呼叫將回 401 key_required。金鑰的取得、傳遞方式與用量端點詳見驗證與用量

所有請求與回應皆為 JSON(Content-Type: application/json)。所有 /api 回應皆帶有 Access-Control-Allow-Origin: *,可直接從瀏覽器跨域呼叫;OPTIONS /api/v1/* 預檢請求回傳 204,並帶 Access-Control-Allow-Methods: POST,GET,OPTIONSAccess-Control-Allow-Headers: Content-Type, Authorization, X-API-Key

機器可讀的完整規格見 /openapi.json(OpenAPI 3.1)。

出生資料物件(共用格式)

以下所有需要出生資料的端點(/charts 本身、/synastrya/b/transits/progressions/solar-returnnatal/compositea/b)都使用同一組欄位與驗證規則:

名稱型別必填說明範例
birth_datestring出生日期,格式 YYYY-MM-DD(需補零),並須為有效日期"1990-01-01"
birth_timestring出生時間(當地時間),格式 H:MMHH:MM,24 小時制(時 0–23、分 0–59)"12:00"
latitudenumber出生地緯度,範圍 −90 ~ 90(須為 JSON 數字,字串會被拒絕)25.033
longitudenumber出生地經度,範圍 −180 ~ 180(東經為正)121.5654
timezonestringIANA 時區識別碼"Asia/Taipei"
house_systemstring宮位制。"P" / "placidus" = Placidus(預設);"W" / "whole_sign" = 整宮制。不分大小寫;其他值回 400 invalid_house_system"W"

多語言(lang 參數)

API 回應預設使用繁體中文(zh-TW)詞彙。所有起盤端點(/charts/synastry/transits/progressions/composite/solar-return)接受選填的請求主體欄位 langGET /api/v1/cities 接受查詢參數 ?lang=/api/v1/health 無語言參數。

接受的值

送入值(不分大小寫)語言說明
zh-TWzh-twzh_twzh繁體中文預設:省略或 null 時等同 zh-TW,回應與不帶 lang 完全相同
enEnglish行星/星座/相位等詞彙譯為英文
ja日本語詞彙譯為日文(部分詞彙與中文同形)
ko한국어詞彙譯為韓文

其他任何值(含空字串 "")回 400 invalid_lang,且此錯誤訊息固定為 zh-TW。

翻譯範圍

lang 只翻譯「詞彙」,不改變任何 JSON 結構:

主體無法解析時一律 zh-TW:請求主體不是合法 JSON(invalid_json)時伺服器讀不到 lang,該錯誤訊息固定為 zh-TW。
詞彙對照備註:日文(ja)元素中「土」譯為 (火/地/風/水),模式為 活動不動柔軟;韓文(ko)元素為 공기,模式為 활동궁고정궁변통궁

範例:lang: "ja"

請求範例

{
  "birth_date": "1990-01-01",
  "birth_time": "12:00",
  "latitude": 25.033,
  "longitude": 121.5654,
  "timezone": "Asia/Taipei",
  "lang": "ja"
}

回應 200(實際輸出,節錄)

{
  "data": {
    "input": { /* 原樣回傳,不翻譯 */ },
    "chart": {
      "ascendant": { "zodiac": "牡羊座", "degree": 16.4422, "total_degree": 16.4422 },
      "house_system": "P",
      "planets": [
        { "planet": "太陽", "zodiac": "山羊座", "house": 9, "degree": 10.4744, "total_degree": 280.4744, "retrograde": false,
          "aspects": [
            { "planet": "木星", "aspect_type": "オポジション", "orb": 5.28 },
            { "planet": "土星", "aspect_type": "コンジャンクション", "orb": 5.14 }
            // …其餘 2 筆省略
          ] },
        { "planet": "月", "zodiac": "水瓶座", "house": 11, "degree": 28.7886, "total_degree": 328.7886, "retrograde": false },
        { "planet": "ドラゴンヘッド", "zodiac": "水瓶座", "house": 11, "degree": 16.863, "total_degree": 316.863, "retrograde": false }
        // …其餘 14 筆省略(結構不變,共 17 筆)
      ],
      "element_stats": {
        "elements":   { "火": 1, "地": 5, "風": 2, "水": 2 },
        "modalities": { "活動": 6, "不動": 3, "柔軟": 1 }
      }
      // …houses/patterns 結構不變
    }
  }
}

驗證與用量(API 金鑰)

API 金鑰讓你把呼叫用量歸戶、設定每月用量上限,並查詢自己的用量。是否強制帶金鑰由伺服器環境變數 API_KEY_MODE 控制:

API_KEY_MODE行為
open(預設,本站目前狀態金鑰選填。不帶金鑰=匿名呼叫,一切正常;帶了金鑰則把該次用量計入該金鑰。
required金鑰必填。所有計費端點的匿名呼叫回 401 key_required
目前為 open 模式:你現在完全不帶金鑰也能呼叫本站所有端點(唯一例外是 GET /api/v1/usage,因為匿名用量無從歸戶,即使在 open 模式也需要金鑰)。以下關於金鑰的說明是為了讓你在需要時(或伺服器日後切換為 required)能無痛接上。

傳遞金鑰的方式

金鑰長相為 ak_XXXXXXXX…。以下任一種方式擇一即可(優先序:Authorization > X-API-Key > ?api_key=):

方式範例
請求標頭 Authorization: BearerAuthorization: Bearer ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ
請求標頭 X-API-KeyX-API-Key: ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ
查詢參數 ?api_key=/api/v1/cities?q=tai&api_key=ak_7hgEJAyQ…
CORS:預檢(OPTIONS /api/v1/*)已允許 Content-Type, Authorization, X-API-Key 標頭,可直接從瀏覽器帶金鑰跨域呼叫。

哪些端點會驗證並計入用量(計費端點)

下列端點在 open 模式允許匿名,成功(HTTP 200)時計入用量一次;在 required 模式則必須帶金鑰:

不計入用量GET /api/v1/health(永遠公開、免金鑰)與 GET /api/v1/usage(需金鑰,但查詢自身用量本身不計費)。

金鑰相關錯誤

HTTPcode觸發條件回應範例
401key_requiredrequired 模式下匿名呼叫計費端點;或任何模式下呼叫 /usage 卻未帶金鑰{"error":{"code":"key_required","message":"此端點需要 API 金鑰"}}
401invalid_api_key金鑰不存在或已被撤銷(revoked){"error":{"code":"invalid_api_key","message":"API 金鑰無效或已撤銷"}}
429quota_exceeded該金鑰本月用量已達其 monthly_limit 上限(訊息內含上限次數){"error":{"code":"quota_exceeded","message":"已超過本月用量上限(1 次)"}}
這三個金鑰錯誤的 HTTP 狀態不是 400key_requiredinvalid_api_key401quota_exceeded429),與錯誤碼一節中其餘 400 類參數錯誤不同——請以 code 判斷錯誤種類。用量上限只在該金鑰設有 monthly_limit(非 null)時才會觸發 429。

查詢用量

GET/api/v1/usage

查詢目前金鑰當月的用量摘要。此端點一定需要金鑰(即使在 open 模式;匿名用量無從歸戶),且本身不計費、不翻譯(回應無詞彙欄位)。也接受 ?lang=,但只影響錯誤訊息的語言(如 key_requiredinvalid_api_key),不影響資料內容。

請求範例

curl -s https://your-host/api/v1/usage \
  -H "Authorization: Bearer ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ"

回應 200(實際輸出)

{
  "data": {
    "key": {
      "prefix": "ak_7hgEJAyQ",
      "label": "Acme Web App",
      "tier": "free"
    },
    "month": "2026-07",
    "total": 5,
    "monthly_limit": 1000,
    "remaining": 995,
    "by_endpoint": {
      "charts": 2,
      "cities": 2,
      "synastry": 1
    },
    "by_day": {
      "2026-07-25": 5
    }
  }
}
欄位型別說明
key.prefixstring金鑰前綴(ak_ + 8 碼,共 11 字),可安全顯示;完整金鑰不會回傳
key.labelstring建立金鑰時給的標籤
key.tierstring方案級別(如 freepro,僅為標記)
monthstring統計月份 YYYY-MM(UTC)
totalinteger本月總計費呼叫數
monthly_limitinteger | null每月上限;null 表示無上限
remaininginteger | null本月剩餘可用次數(max(limit − total, 0));無上限時為 null
by_endpointobject各端點呼叫數(端點名為去掉 /api/v1/ 前綴的鍵,如 charts),依次數由多到少排序
by_dayobject本月各日(YYYY-MM-DD)呼叫數,依日期升冪排序

計費端點帶金鑰的呼叫範例

# Authorization: Bearer(本命盤)
curl -s -X POST https://your-host/api/v1/charts \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ" \
  -d '{"birth_date":"1990-01-01","birth_time":"12:00","latitude":25.033,"longitude":121.5654,"timezone":"Asia/Taipei"}'

# X-API-Key 標頭(城市搜尋)
curl -s "https://your-host/api/v1/cities?q=tai" \
  -H "X-API-Key: ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ"

# 查詢參數 ?api_key=(城市搜尋)
curl -s "https://your-host/api/v1/cities?q=tokyo&api_key=ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ"

自助申請 API 金鑰(Self-serve signup)

不需要管理權杖,任何人都能自助申請一把免費 API 金鑰。流程採雙重確認(double opt-in),分兩步:

  1. 申請POST /api/v1/signup 送出你的 email。系統暫存一筆待確認申請並寄出一封含確認連結的信。此步驟不會回傳金鑰。
  2. 確認:點擊信中的連結(指向 GET /verify?token=…),在該頁按下確認鈕,前端即以該 token 呼叫 POST /api/v1/verify,此時才簽發並只顯示一次明文金鑰。

整個流程公開、免費、不計費、免金鑰。金鑰本身也是免費的;email 這一步只是為了確認你對該信箱的擁有權。取得金鑰後如何傳遞、如何查詢用量,見驗證與用量。另有兩個公開 HTML 頁面:GET /signup(申請頁)與 GET /verify(信件連結的到達頁,內含確認鈕)。

開放測試期的信件寄送:確認信目前透過 Resend 寄出。在尚未驗證自訂寄件網域、仍使用共用測試寄件者的情況下,信件可能只會送達營運者本人的信箱,直到綁定並驗證自訂網域為止。自行部署時若未設定 RESEND_API_KEY,信件不會真的寄出,而是把連結寫入伺服器日誌(「logged 模式」),本地與測試環境下整條雙重確認流程仍可運作。

步驟一:申請(寄出確認信)

POST/api/v1/signup

暫存一筆待確認申請並寄出確認連結。公開端點、不計費、免金鑰。防濫用:同一來源 IP(Fly 會設定的 X-Forwarded-For 第一段)每日申請次數達 SIGNUP_DAILY_IP_LIMIT(預設 5)時回 429 signup_rate_limited

請求欄位

名稱型別必填說明範例
emailstring開發者的電子郵件。格式無效或長度 > 254 字回 400 invalid_email;拋棄式(暫時)信箱網域(如 mailinator.com)回 400 disposable_email"dev@example.com"
langstring錯誤訊息與確認信的語言(見多語言"zh-TW"

請求範例

{
  "email": "dev@example.com"
}

回應 202(實際輸出)

{
  "data": {
    "status": "verification_sent",
    "email": "dev@example.com"
  }
}
回應為 202 Accepted,代表「已受理、確認信已寄出」,而金鑰已簽發——此步驟不會回傳任何金鑰。確認連結(GET /verify?token=…)的有效期為 24 小時,逾期需重新申請。

錯誤

HTTPcode觸發條件回應範例
400invalid_emailemail 格式無效,或長度超過 254 字{"error":{"code":"invalid_email","message":"電子郵件格式無效"}}
400disposable_emailemail 屬於拋棄式(暫時)信箱網域(如 mailinator.com{"error":{"code":"disposable_email","message":"拋棄式(暫時)信箱不予受理,請改用常用信箱"}}
429signup_rate_limited同一來源 IP 當日申請次數達上限{"error":{"code":"signup_rate_limited","message":"今日申請次數過多,請明日再試"}}

步驟二:確認並取得金鑰

POST/api/v1/verify

以確認信連結中的 token 確認信箱擁有權,成功時簽發並回傳明文金鑰(只回傳這一次)。一般使用者是經由 GET /verify?token=… 頁面按下確認鈕,由該頁前端 POST 此端點;也可直接以程式呼叫。公開端點、不計費、免金鑰。

請求欄位

名稱型別必填說明範例
tokenstring確認信連結(/verify?token=…)中的一次性 token"3f9c…"
langstring錯誤訊息語言(見多語言"zh-TW"

請求範例

{
  "token": "3f9c1e7a8b2d4f60a1c3e5d7b9f0a2c4"
}

回應 201(實際輸出,明文 token 只回傳這一次)

{
  "data": {
    "token": "ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ",
    "prefix": "ak_7hgEJAyQ",
    "monthly_limit": null,
    "tier": "free"
  }
}
明文 token(即 API 金鑰)只在此回傳這一次(伺服器只保存其 SHA-256 雜湊),之後任何端點都不會再吐出完整金鑰——請當場保存。新金鑰 tierfreemonthly_limit 預設為 null(無上限,除非營運者設定 SIGNUP_MONTHLY_LIMIT)。一次性 token 一經成功使用即失效。

錯誤

HTTPcode觸發條件回應範例
400verification_invalidtoken 不存在或已使用過{"error":{"code":"verification_invalid","message":"驗證連結無效或已使用過"}}
400verification_expired連結已逾 24 小時過期{"error":{"code":"verification_expired","message":"驗證連結已過期,請重新申請"}}

健康檢查

GET/api/v1/health

確認服務狀態與底層 astro_chart gem 版本。

回應 200

{"status":"ok","gem_version":"0.3.0"}

本命盤

POST/api/v1/charts

依出生資料計算完整本命盤:上升點、行星位置(含逆行標記、福點、莉莉絲)、宮位(Placidus 或整宮制)、相位、相位圖形(大三角/T三角/大十字)、元素統計。

請求欄位

即為一個出生資料物件(5 個必填欄位 + 選填 house_system)。

請求範例

{
  "birth_date": "1990-01-01",
  "birth_time": "12:00",
  "latitude": 25.033,
  "longitude": 121.5654,
  "timezone": "Asia/Taipei",
  "house_system": "P"
}

回應 200(實際輸出,planets/houses 節錄)

{
  "data": {
    "input": {
      "birth_date": "1990-01-01",
      "birth_time": "12:00",
      "coordinates": { "latitude": 25.033, "longitude": 121.5654 },
      "timezone": "Asia/Taipei"
    },
    "chart": {
      "ascendant": { "zodiac": "牡羊座", "degree": 16.4422, "total_degree": 16.4422 },
      "house_system": "P",
      "planets": [
        {
          "planet": "太陽",
          "zodiac": "摩羯座",
          "house": 9,
          "degree": 10.4744,
          "total_degree": 280.4744,
          "retrograde": false,
          "aspects": [
            { "planet": "木星", "aspect_type": "對分相", "orb": 5.28 },
            { "planet": "土星", "aspect_type": "合相", "orb": 5.14 },
            { "planet": "天王星", "aspect_type": "合相", "orb": 4.71 },
            { "planet": "海王星", "aspect_type": "合相", "orb": 1.55 }
          ]
        },
        {
          "planet": "水星",
          "zodiac": "摩羯座",
          "house": 10,
          "degree": 25.76,
          "total_degree": 295.76,
          "retrograde": true
        },
        // …月亮、金星、火星、木星、土星、天王星、海王星、冥王星、
        //   北交點、南交點省略(12 個實體星體/交點)
        {
          "planet": "福點",
          "zodiac": "雙子座",
          "house": 2,
          "degree": 4.7564,
          "total_degree": 64.7564,
          "retrograde": false
        },
        {
          "planet": "莉莉絲",
          "zodiac": "天蠍座",
          "house": 7,
          "degree": 6.4703,
          "total_degree": 216.4703,
          "retrograde": false
        },
        {
          "planet": "北交點定位星",
          "ruling_planet": "天王星",
          "zodiac": "摩羯座",
          "house": 9,
          "degree": 5.7656,
          "total_degree": 275.7656,
          "aspects": [
            { "planet": "太陽", "aspect_type": "合相", "orb": 4.71 },
            { "planet": "木星", "aspect_type": "對分相", "orb": 0.57 }
            // …其餘 2 筆省略
          ],
          "retrograde": false
        }
        // …南交點定位星、上升星座定位星省略(planets 共 17 筆,見「回應欄位說明」)
      ],
      "houses": [
        { "house_number": 1, "degree": 16.4422, "zodiac": "牡羊座" },
        { "house_number": 2, "degree": 50.317, "zodiac": "金牛座" }
        // …其餘 10 筆省略,共 12 宮
      ],
      "patterns": [],
      "element_stats": {
        "elements":   { "火": 1, "土": 5, "風": 2, "水": 2 },
        "modalities": { "基本": 6, "固定": 3, "變動": 1 }
      }
    }
  }
}

整宮制(Whole Sign)

"house_system": "W" 時,宮首固定落在每個星座 0°(第 1 宮 = 上升星座的 0°),ascendant 本身與 Placidus 完全相同。實際輸出節錄(同一筆出生資料):

{
  "chart": {
    "ascendant": { "zodiac": "牡羊座", "degree": 16.4422, "total_degree": 16.4422 },
    "house_system": "W",
    "houses": [
      { "house_number": 1, "degree": 0.0,  "zodiac": "牡羊座" },
      { "house_number": 2, "degree": 30.0, "zodiac": "金牛座" },
      { "house_number": 3, "degree": 60.0, "zodiac": "雙子座" }
      // …其餘 9 筆省略,每宮 +30°
    ]
    // …planets/patterns/element_stats 結構相同(行星宮位依整宮制重新歸宮)
  }
}

相位圖形範例

patterns 多數星盤為空陣列;以 1999-08-11(著名的日食大十字)為例,實際輸出:

"patterns": [
  { "pattern_type": "T三角", "planets": ["水星", "海王星", "木星"], "apex": "木星" },
  { "pattern_type": "大十字", "planets": ["天王星", "太陽", "土星", "火星"] },
  { "pattern_type": "大十字", "planets": ["南交點", "太陽", "土星", "火星"] }
  // …共 5 組大十字,此處省略 3 組
]

合盤(Synastry)

POST/api/v1/synastry

計算兩人的本命盤,以及兩張盤之間的相位與「A 的行星落入 B 的宮位」對照。

請求欄位

名稱型別必填說明範例
aobjectA 的出生資料物件(可含 house_system{"birth_date": …}
bobjectB 的出生資料物件{"birth_date": …}
orb_limitnumber | null跨盤相位的容許度上限(度)。省略或 null 時使用本命盤預設容許度(合相 15° 等,見下方);合盤實務常用較緊的 6.0必須為 JSON 數字或 null,其他型別回 400 missing_param6.0

請求範例

{
  "a": {
    "birth_date": "1990-01-01",
    "birth_time": "12:00",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei"
  },
  "b": {
    "birth_date": "1992-06-15",
    "birth_time": "08:30",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei"
  },
  "orb_limit": 6.0
}

回應 200(實際輸出,節錄)

{
  "data": {
    "a_chart": { /* A 的完整本命盤,結構同 /api/v1/charts 的 data */ },
    "b_chart": { /* B 的完整本命盤 */ },
    "synastry": {
      "aspects": [
        { "a_planet": "冥王星", "b_planet": "天王星", "aspect_type": "六分相", "orb": 0.16 },
        { "a_planet": "太陽", "b_planet": "水星", "aspect_type": "對分相", "orb": 0.19 },
        { "a_planet": "冥王星", "b_planet": "海王星", "aspect_type": "六分相", "orb": 1.13 }
        // …其餘筆數省略;一律依 orb 由小到大排序
      ],
      "a_planets_in_b_houses": {
        "太陽": 6, "月亮": 7, "水星": 6, "金星": 6, "火星": 5, "木星": 11,
        "土星": 6, "天王星": 5, "海王星": 6, "冥王星": 4, "北交點": 7
      },
      "b_planets_in_a_houses": {
        "太陽": 3, "月亮": 9, "水星": 3, "金星": 3, "火星": 1, "木星": 5,
        "土星": 11, "天王星": 10, "海王星": 10, "冥王星": 8, "北交點": 9
      }
    }
  }
}
aspects 中每筆的 a_planet 屬於 A、b_planet 屬於 B;a_planets_in_b_houses 表示 A 的行星落入 B 的第幾宮(反之亦然)。合盤比較固定使用 11 個星體(太陽~冥王星+北交點);南交點不參與(恆與北交點正對分,只會鏡射北交點的相位)。福點、莉莉絲與定位星點位也不參與兩張盤的比較。

行運(Transits)

POST/api/v1/transits

計算某一時刻(預設為「現在」)天上行星的位置、其落入本命盤的宮位,以及行運行星對本命行星的相位。

請求欄位

名稱型別必填說明範例
natalobject本命出生資料物件(可含 house_system,影響行運行星歸入哪一宮){"birth_date": …}
atobject行運時刻。省略時使用伺服器當下的 UTC 時間。若提供,三個子欄位皆必填{"date": …}
at.datestring是*日期 YYYY-MM-DD(驗證規則同 birth_date"2026-07-24"
at.timestring是*時間 HH:MM(驗證規則同 birth_time"12:00"
at.timezonestring是*IANA 時區識別碼(at.date/at.time 視為此時區的當地時間)"Asia/Taipei"
orb_limitnumber行運相位容許度上限(度),預設 3.0(行運實務用緊容許度)3

* 僅在有提供 at 物件時必填。

請求範例

{
  "natal": {
    "birth_date": "1990-01-01",
    "birth_time": "12:00",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei"
  },
  "at": { "date": "2026-07-24", "time": "12:00", "timezone": "Asia/Taipei" },
  "orb_limit": 3
}

回應 200(實際輸出,節錄)

{
  "data": {
    "natal_chart": { /* 完整本命盤,結構同 /api/v1/charts 的 data */ },
    "transit_time_utc": "2026-07-24T04:00:00Z",
    "planets": [
      {
        "planet": "太陽",
        "zodiac": "獅子座",
        "degree": 1.3043,
        "total_degree": 121.3043,
        "natal_house": 4
      },
      {
        "planet": "月亮",
        "zodiac": "射手座",
        "degree": 1.4324,
        "total_degree": 241.4324,
        "natal_house": 8
      }
      // …其餘 10 筆省略,共 12 筆(太陽~冥王星+北交點+南交點)
    ],
    "aspects": [
      { "transit_planet": "金星", "natal_planet": "土星", "aspect_type": "三分相", "orb": 0.18 },
      { "transit_planet": "水星", "natal_planet": "土星", "aspect_type": "對分相", "orb": 0.7 },
      { "transit_planet": "水星", "natal_planet": "冥王星", "aspect_type": "三分相", "orb": 0.77 },
      { "transit_planet": "海王星", "natal_planet": "木星", "aspect_type": "四分相", "orb": 0.85 }
      // …其餘筆數省略;依 orb 由小到大排序
    ]
  }
}
transit_time_utc 為行運時刻換算成 UTC 的 ISO 8601 字串。planets[].natal_house 是行運行星落入本命宮位的宮號。相位比較固定使用 11 個星體(南交點不參與,理由同合盤);行運相位無視本命盤中的福點/莉莉絲/定位星。若 at 時刻落在日光節約時間切換區間,回 400 invalid_time

二次推運(Secondary Progressions)

POST/api/v1/progressions

「一天推一年」:目標日期距出生每滿一年,推運盤即取出生後一天的天象。回傳推運行星位置(落入本命宮位)與推運行星對本命行星的相位。

請求欄位

名稱型別必填說明範例
natalobject本命出生資料物件(可含 house_system{"birth_date": …}
target_datestring推運目標日期 YYYY-MM-DD。目標時刻取「同一出生時間+出生時區」,讓整年乾淨地換算"2026-07-24"
orb_limitnumber推運相位容許度上限(度),預設 1.0(推運移動極慢,只看極精準的相位)1

請求範例

{
  "natal": {
    "birth_date": "1990-01-01",
    "birth_time": "12:00",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei"
  },
  "target_date": "2026-07-24",
  "orb_limit": 1
}

回應 200(實際輸出,節錄)

{
  "data": {
    "natal_chart": { /* 完整本命盤,結構同 /api/v1/charts 的 data */ },
    "progression": {
      "progressed_jd": 2447929.2259389306,
      "years_elapsed": 36.56,
      "planets": [
        {
          "planet": "太陽",
          "zodiac": "水瓶座",
          "degree": 17.6684,
          "total_degree": 317.6684,
          "natal_house": 11
        }
        // …其餘 11 筆省略,共 12 筆(結構同行運的 planets)
      ],
      "aspects_to_natal": [
        { "progressed_planet": "火星", "natal_planet": "天王星", "aspect_type": "合相", "orb": 0.11 },
        { "progressed_planet": "北交點", "natal_planet": "北交點", "aspect_type": "合相", "orb": 0.37 },
        { "progressed_planet": "太陽", "natal_planet": "冥王星", "aspect_type": "四分相", "orb": 0.58 }
        // …其餘筆數省略;依 orb 由小到大排序
      ]
    }
  }
}
progressed_jd 為推運時刻的儒略日(Julian Day)、years_elapsed 為出生至目標日期經過的年數(四捨五入至小數 2 位)。若目標日期的出生時刻在該時區不存在或不唯一(日光節約切換),回 400 invalid_time

太陽回歸(Solar Return)

POST/api/v1/solar-return

找出指定年份中「行運太陽回到本命太陽經度」的精確時刻(牛頓迭代,精度約 10 秒內),並以該時刻起一張完整的回歸盤。可選擇改用其他地點(回歸移置)。

請求欄位

名稱型別必填說明範例
natalobject本命出生資料物件(可含 house_system,只影響 natal_chart{"birth_date": …}
yearinteger回歸年份。必須為 JSON 整數(字串或小數回 400 missing_param);超出 1885–2099 回 400 date_out_of_range2026
latitudenumber回歸地點緯度(省略時用本命座標)。範圍 −90 ~ 9035.6762
longitudenumber回歸地點經度(省略時用本命座標)。範圍 −180 ~ 180139.6503
timezonestring回歸地點時區(IANA)。僅供顯示(回傳於 location),不影響計算 — 回歸時刻本身是 UTC 定義的"Asia/Tokyo"

請求範例

{
  "natal": {
    "birth_date": "1990-01-01",
    "birth_time": "12:00",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei"
  },
  "year": 2026
}

回應 200(實際輸出,節錄)

{
  "data": {
    "natal_chart": { /* 完整本命盤,結構同 /api/v1/charts 的 data */ },
    "solar_return": {
      "return_jd": 2461041.407478858,
      "return_time_utc": "2025-12-31T21:46:46Z",
      "location": {
        "latitude": 25.033,
        "longitude": 121.5654,
        "timezone": "Asia/Taipei"
      },
      "chart": {
        "ascendant": { "zodiac": "射手座", "degree": 27.3962, "total_degree": 267.3962 },
        "planets": [
          {
            "planet": "太陽",
            "zodiac": "摩羯座",
            "house": 1,
            "degree": 10.4744,
            "total_degree": 280.4744,
            "aspects": [
              { "planet": "金星", "aspect_type": "合相", "orb": 1.38 },
              { "planet": "北交點", "aspect_type": "六分相", "orb": 0.5 }
              // …其餘筆數省略
            ]
          }
          // …其餘 14 筆省略(回歸盤 planets 共 15 筆,見下方注意事項)
        ],
        "houses": [ /* 12 筆宮首,結構同本命盤 houses */ ]
      }
    }
  }
}
「year 2026」的回歸時刻可能落在前一年年底(如本例 2025-12-31T21:46:46Z):迭代從該年份的生日正午出發,找最近的太陽回歸瞬間,生日在年初或年尾時屬正常現象。
注意(結構差異):回歸盤 solar_return.chart 沿用舊版盤面結構 — planets15 筆(12 星體/交點+3 定位星點位),不含 retrograde福點莉莉絲house_systempatternselement_stats,宮位固定使用 Placidus。同一回應中的 natal_chart 則是新版 17 筆完整結構。

回歸移置(relocation)

latitudelongitudetimezone 覆寫時,回歸時刻不變(太陽經度與地點無關),但回歸盤的上升點與宮位改以新地點計算。實際輸出節錄:

"solar_return": {
  "return_time_utc": "2025-12-31T21:46:46Z",
  "location": { "latitude": 35.6762, "longitude": 139.6503, "timezone": "Asia/Tokyo" }
  // …chart 改以東京座標起盤
}

組合盤(Composite)

POST/api/v1/composite

兩張本命盤的中點盤:每個星體取兩盤經度的短弧中點(350° 與 10° 的中點是 0°,不是 180°),再計算中點位置彼此之間的相位。

請求欄位

名稱型別必填說明範例
aobjectA 的出生資料物件(可含 house_system{"birth_date": …}
bobjectB 的出生資料物件{"birth_date": …}

請求範例

{
  "a": {
    "birth_date": "1990-01-01", "birth_time": "12:00",
    "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei"
  },
  "b": {
    "birth_date": "1992-06-15", "birth_time": "08:30",
    "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei"
  }
}

回應 200(實際輸出,節錄)

{
  "data": {
    "a_chart": { /* A 的完整本命盤,結構同 /api/v1/charts 的 data */ },
    "b_chart": { /* B 的完整本命盤 */ },
    "composite": {
      "planets": [
        { "planet": "太陽", "zodiac": "牡羊座", "degree": 2.3199, "total_degree": 2.3199 },
        { "planet": "月亮", "zodiac": "摩羯座", "degree": 25.4433, "total_degree": 295.4433 }
        // …其餘 10 筆省略,共 12 筆(太陽~冥王星+北交點+南交點)
      ],
      "aspects": [
        { "planet_a": "北交點", "planet_b": "南交點", "aspect_type": "對分相", "orb": 0.0 },
        { "planet_a": "金星", "planet_b": "海王星", "aspect_type": "四分相", "orb": 0.28 },
        { "planet_a": "太陽", "planet_b": "土星", "aspect_type": "六分相", "orb": 0.39 }
        // …其餘筆數省略;依 orb 由小到大排序
      ]
    }
  }
}
組合盤不含宮位與上升點:中點組合盤的宮位制在占星實務上沒有公認作法(宮首中點 vs. 依參考地點重新起盤),因此刻意不回傳。相位使用本命盤預設容許度(無 orb_limit 參數)。

城市搜尋

GET/api/v1/cities?q=<關鍵字>

供出生地輸入使用的城市座標/時區查詢。內建約 160 筆城市:台灣全部 22 縣市(縣治座標)+世界主要城市,支援中文名與英文/拼音別名。

查詢參數

名稱型別必填說明範例
qstring關鍵字,不分大小寫。前綴符合優先於子字串符合;最多回傳 10 筆。缺少或空白回 400 missing_paramtai東京tokyo
langstring回應語言(見多語言)。enjakonamecountry 改為英文名(如 台北市Taipei);不影響比對邏輯en

回應 200(GET /api/v1/cities?q=tai 實際輸出)

{
  "data": [
    { "name": "台北市", "country": "台灣", "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei" },
    { "name": "台中市", "country": "台灣", "latitude": 24.1477, "longitude": 120.6736, "timezone": "Asia/Taipei" },
    { "name": "台南市", "country": "台灣", "latitude": 22.9999, "longitude": 120.2269, "timezone": "Asia/Taipei" },
    { "name": "嘉義縣", "country": "台灣", "latitude": 23.4518, "longitude": 120.2555, "timezone": "Asia/Taipei" },
    { "name": "台東縣", "country": "台灣", "latitude": 22.7583, "longitude": 121.1444, "timezone": "Asia/Taipei" },
    { "name": "新北市", "country": "台灣", "latitude": 25.012, "longitude": 121.4657, "timezone": "Asia/Taipei" }
  ]
}
排序規則:先列出「名稱或別名以 q 開頭」的城市,再列出「名稱或別名包含 q」的城市(如上例:嘉義縣因別名 Taibao 前綴符合而排在僅子字串符合的新北市之前)。查無結果時回傳 {"data":[]}(HTTP 200)。

回應欄位說明

行星物件(chart.planets[]

欄位型別說明
planetstring行星/點位名稱(中文)
zodiacstring所在星座(12 星座中文名,例如 摩羯座
houseinteger所在宮位(1–12,依所選宮位制)
degreenumber在該星座內的度數(0–30)
total_degreenumber黃道絕對經度(0–360,牡羊座 0° 起算)
retrogradeboolean是否逆行。太陽/月亮恆為 false;南交點與北交點同值;福點/莉莉絲/定位星點位恆為 false(非實體天體)
aspectsarray與其他行星形成的相位清單(僅特定行星帶有此欄位,見下)。每筆含 planet(對象)、aspect_typeorb(偏差度數)
ruling_planetstring僅三個「定位星」點位帶有此欄位:實際擔任定位星的行星名稱

行星清單(planets 陣列共 17 筆,依序)

aspects 欄位只出現在:太陽月亮金星土星北交點南交點,以及三個定位星點位。其餘(水星、火星、木星、天王星、海王星、冥王星、福點、莉莉絲)不帶 aspects

宮位制(chart.house_system

宮位制說明
"P"Placidus(普拉西德)預設。宮首依半弧迭代計算;極區(約 |緯度| ≥ 66°)無定義,回 400 polar_latitude
"W"Whole Sign(整宮制)第 1 宮=上升星座整個星座(宮首 = 該星座 0°),其後每宮 +30°。上升點計算與 Placidus 相同;極區緯度也可計算

相位圖形(chart.patterns[]

從 12 個星體/交點的位置偵測三種經典圖形;無圖形時為空陣列 []

pattern_type組成額外欄位
大三角3 星兩兩三分相element:三星同元素時為 "火"/"土"/"風"/"水",否則 null
T三角2 星對分相,兩者皆四分相於端點星apex:端點星名稱
大十字4 星構成 2 組對分相、相鄰皆四分相

每筆皆含 planets(組成星體名稱陣列)。去重規則:大十字會吸收其自身 4 星構成的 T三角(不重複回報);北交點—南交點這組「定義上的對分相」不作為 T三角/大十字的對分軸(但交點仍可作為端點星等其他角色);由於南交點恆與北交點正對,對分相被交點軸四分時只回報一筆 T三角(端點星為北交點),不會出現北/南交點鏡像的重複組。

元素統計(chart.element_stats

統計 10 個古典行星(太陽~冥王星,不含交點與衍生點)落入星座的元素與模式分布,兩組計數各自加總為 10:

"element_stats": {
  "elements":   { "火": 1, "土": 5, "風": 2, "水": 2 },
  "modalities": { "基本": 6, "固定": 3, "變動": 1 }
}

對應規則:牡羊=火/基本、金牛=土/固定、雙子=風/變動⋯依序循環(元素每 4 個星座一輪、模式每 3 個星座一輪)。

相位種類與容許度(orb)

相位角度最大容許度
合相15°
六分相60°
四分相90°
三分相120°
對分相180°10°

回應中的 orb 為實際角度與準確相位角的偏差(度,四捨五入至小數 2 位),數值越小相位越緊密。行運(預設 3°)與推運(預設 1°)另以 orb_limit 過濾。

上升點與宮位

錯誤碼

所有錯誤皆回傳 JSON,格式為:

{ "error": { "code": "<code>", "message": "<訊息(預設中文,依 lang 在地化)>" } }

message 會依請求的 lang 在地化(見多語言;主體無法解析或 lang 本身無效時固定 zh-TW);code 與語言無關,下表範例皆為預設 zh-TW 訊息。大多數參數錯誤為 HTTP 400,但金鑰相關錯誤帶不同狀態(key_requiredinvalid_api_key401quota_exceeded429)——請務必以 code 而非 HTTP 狀態或訊息文字判斷錯誤種類。

HTTPcode觸發條件回應範例
400invalid_json主體不是合法 JSON 或不是 JSON 物件{"error":{"code":"invalid_json","message":"無效的 JSON 格式"}}
400missing_param缺少必填欄位(含 a/b/natal 物件、target_dateat.* 子欄位、q)、orb_limit 不是數字/null,或 year 不是整數{"error":{"code":"missing_param","message":"缺少參數:birth_date"}}
400invalid_datebirth_dateat.datetarget_date 格式錯誤或非有效日期{"error":{"code":"invalid_date","message":"無效的出生日期,格式須為 YYYY-MM-DD"}}
400invalid_timebirth_timeat.time 格式錯誤、超出 0–23 / 0–59,或該時刻(含推運目標日期的出生時刻)落在日光節約時間切換的無效/不明確區間{"error":{"code":"invalid_time","message":"無效的出生時間,格式須為 HH:MM"}}
400invalid_coordinates緯度/經度非數字或超出範圍(字串一律拒絕;含太陽回歸的地點覆寫){"error":{"code":"invalid_coordinates","message":"無效的座標:緯度須在 ±90、經度須在 ±180 之間"}}
400invalid_timezonetimezoneat.timezone 非有效 IANA 識別碼{"error":{"code":"invalid_timezone","message":"無效的時區識別碼:Asia/Tokio"}}
400invalid_house_systemhouse_system 不是 P/placidus/W/whole_sign(不分大小寫){"error":{"code":"invalid_house_system","message":"無效的宮位制式:K(支援 P / placidus 或 W / whole_sign)"}}
400invalid_langlang 不是支援的語言(zh-TWzh-twzh_twzhenjako,不分大小寫;空字串也算無效)。此錯誤訊息固定為 zh-TW{"error":{"code":"invalid_lang","message":"不支援的語言:fr(支援 zh-TW / en / ja / ko)"}}
400polar_latitude極區緯度(約 |緯度| ≥ 66°)使 Placidus 宮位無解(整宮制 W 不受此限){"error":{"code":"polar_latitude","message":"極區緯度無法計算 Placidus 宮位"}}
400date_out_of_range任一計算時刻(出生日期、行運 at、推運目標、回歸年份)超出冥王星可計算範圍(1885–2099){"error":{"code":"date_out_of_range","message":"日期超出可計算範圍(1885–2099)"}}
401key_required需要 API 金鑰但未提供(required 模式的計費端點,或任何模式的 /usage)。詳見驗證與用量{"error":{"code":"key_required","message":"此端點需要 API 金鑰"}}
401invalid_api_key提供的金鑰不存在或已被撤銷{"error":{"code":"invalid_api_key","message":"API 金鑰無效或已撤銷"}}
429quota_exceeded該金鑰本月用量已達 monthly_limit 上限(訊息含上限次數){"error":{"code":"quota_exceeded","message":"已超過本月用量上限(1 次)"}}
400invalid_email自助申請的 email 格式無效或長度 > 254 字(POST /api/v1/signup{"error":{"code":"invalid_email","message":"電子郵件格式無效"}}
400disposable_email自助申請使用拋棄式(暫時)信箱網域(POST /api/v1/signup{"error":{"code":"disposable_email","message":"拋棄式(暫時)信箱不予受理,請改用常用信箱"}}
429signup_rate_limited同一來源 IP 當日自助申請次數達上限(POST /api/v1/signup{"error":{"code":"signup_rate_limited","message":"今日申請次數過多,請明日再試"}}
400verification_invalid確認 token 不存在或已使用過(POST /api/v1/verify{"error":{"code":"verification_invalid","message":"驗證連結無效或已使用過"}}
400verification_expired確認連結已逾 24 小時過期(POST /api/v1/verify{"error":{"code":"verification_expired","message":"驗證連結已過期,請重新申請"}}
404not_found不存在的 /api 路徑{"error":{"code":"not_found","message":"找不到此 API 路徑"}}
500internal_error未預期的伺服器錯誤(不洩漏堆疊資訊){"error":{"code":"internal_error","message":"伺服器內部錯誤,請稍後再試"}}
訊息措辭:行運 at.* 與推運 target_date 的驗證沿用出生欄位的驗證器,因此錯誤訊息會寫作「出生日期/出生時間」——請以 code 判斷錯誤種類,勿依賴訊息文字。

限制

程式範例

curl — 本命盤(整宮制)

curl -s -X POST https://your-host/api/v1/charts \
  -H "Content-Type: application/json" \
  -d '{
    "birth_date": "1990-01-01",
    "birth_time": "12:00",
    "latitude": 25.033,
    "longitude": 121.5654,
    "timezone": "Asia/Taipei",
    "house_system": "W"
  }'

curl — 合盤

curl -s -X POST https://your-host/api/v1/synastry \
  -H "Content-Type: application/json" \
  -d '{
    "a": {"birth_date": "1990-01-01", "birth_time": "12:00",
          "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei"},
    "b": {"birth_date": "1992-06-15", "birth_time": "08:30",
          "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei"},
    "orb_limit": 6.0
  }'

curl — 此刻行運(省略 at)

curl -s -X POST https://your-host/api/v1/transits \
  -H "Content-Type: application/json" \
  -d '{
    "natal": {"birth_date": "1990-01-01", "birth_time": "12:00",
              "latitude": 25.033, "longitude": 121.5654, "timezone": "Asia/Taipei"}
  }'

JavaScript — fetch()

const res = await fetch("/api/v1/charts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    birth_date: "1990-01-01",
    birth_time: "12:00",
    latitude: 25.033,
    longitude: 121.5654,
    timezone: "Asia/Taipei",
  }),
});
const json = await res.json();
if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
console.log(json.data.chart.ascendant); // { zodiac: "牡羊座", degree: 16.4422, … }
const retro = json.data.chart.planets.filter(p => p.retrograde);
console.log(retro.map(p => p.planet)); // ["水星", "金星", "木星"]

Ruby — Net::HTTP

require "net/http"
require "json"

uri = URI("https://your-host/api/v1/charts")
res = Net::HTTP.post(
  uri,
  {
    birth_date: "1990-01-01",
    birth_time: "12:00",
    latitude: 25.033,
    longitude: 121.5654,
    timezone: "Asia/Taipei",
  }.to_json,
  "Content-Type" => "application/json"
)

json = JSON.parse(res.body)
if res.is_a?(Net::HTTPSuccess)
  sun = json.dig("data", "chart", "planets").find { |p| p["planet"] == "太陽" }
  puts "太陽:#{sun["zodiac"]} #{sun["degree"]} 度(第 #{sun["house"]} 宮)"
  puts "元素分布:#{json.dig("data", "chart", "element_stats", "elements")}"
else
  warn "#{json.dig("error", "code")}: #{json.dig("error", "message")}"
end

管理 API(營運用)

此區僅供營運者(operator)使用,不是給一般 API 消費者的。所有 /admin/api-keys/admin/usage 端點都由伺服器機密 ADMIN_TOKEN 保護,用來簽發/撤銷 API 金鑰與檢視全站用量。

驗證方式:以 Authorization: Bearer <ADMIN_TOKEN> 傳入伺服器設定的密鑰(與 API 金鑰無關,是另一組營運機密)。

HTTPcode觸發條件回應範例
503admin_disabled伺服器未設定 ADMIN_TOKEN(管理 API 整個停用){"error":{"code":"admin_disabled","message":"管理介面未啟用"}}
401admin_unauthorized提供的 ADMIN_TOKEN 錯誤{"error":{"code":"admin_unauthorized","message":"管理權杖無效"}}

建立金鑰

POST/admin/api-keys

請求主體:{"label":"...","tier":"free","monthly_limit":1000|null}monthly_limitnull 表示無上限;須為非負整數或 null)。

回應 201(實際輸出)

{
  "data": {
    "id": 1,
    "token": "ak_7hgEJAyQvsuO4zHntkpoMvnvrecJ_6QJ",
    "prefix": "ak_7hgEJAyQ",
    "label": "Acme Web App",
    "tier": "free",
    "monthly_limit": 1000,
    "created_at": "2026-07-25T04:55:45Z"
  }
}
明文 token 只在建立當下回傳這一次(伺服器只保存其 SHA-256 雜湊),之後任何端點都不會再吐出完整金鑰——請當場保存並交給使用者。
實作注意:monthly_limit 若為負數或非整數(如字串),回 400,但 codemissing_param(訊息為「monthly_limit 必須為非負整數或留空」),並非另一組專屬錯誤碼。label 省略時預設空字串、tier 省略時預設 "free"

列出金鑰

GET/admin/api-keys

id 由新到舊列出所有金鑰,不含 token/雜湊

回應 200(實際輸出,節錄)

{
  "data": [
    {
      "id": 3, "prefix": "ak_IVRZsXlz", "label": "tiny", "tier": "free",
      "monthly_limit": 1, "created_at": "2026-07-25T04:55:45Z", "revoked_at": null
    },
    {
      "id": 1, "prefix": "ak_7hgEJAyQ", "label": "Acme Web App", "tier": "free",
      "monthly_limit": 1000, "created_at": "2026-07-25T04:55:45Z", "revoked_at": null
    }
    // …其餘省略
  ]
}

revoked_atnull 表示金鑰仍有效;已撤銷者帶 UTC 時間字串。

撤銷金鑰

DELETE/admin/api-keys/:id

撤銷指定金鑰;撤銷後該金鑰立即失效(之後呼叫回 401 invalid_api_key)。

回應 200(實際輸出)

{ "data": { "id": 1, "revoked": true } }
實作注意:找不到該 id(或已撤銷)時回 404,主體為 JSON 錯誤物件 {"error":{"code":"not_found",…}}

全站用量

GET/admin/usage?month=YYYY-MM

檢視某月(省略 month 時為當月 UTC)的全站用量。by_key 以金鑰 id 為鍵對應該金鑰呼叫數,匿名呼叫歸在 "anonymous"

回應 200(實際輸出)

{
  "data": {
    "month": "2026-07",
    "total": 7,
    "by_endpoint": { "cities": 3, "charts": 3, "synastry": 1 },
    "by_key": { "1": 5, "anonymous": 1, "3": 1 }
  }
}

瀏覽器管理頁

GET/admin

另提供一個瀏覽器管理頁面 /admin:這是一個公開的外殼頁(頁面本身免驗證即可載入),會在前端提示輸入 ADMIN_TOKEN,再以該權杖呼叫上述管理 API。實際操作仍受 ADMIN_TOKEN 保護。

OpenAPI 規格

完整的機器可讀 API 規格(OpenAPI 3.1,含所有端點的請求/回應 schema 與範例):GET /openapi.json。可直接匯入 Swagger UI、Postman、Insomnia 等工具。