新用戶 免費註冊,送 10 次呼叫,最高 $1,免綁卡。

帳單 API

將你自己工作區的用量與費用資料擷取到你自己的系統中,無需開啟控制台。帳單金鑰是一種 唯讀 憑證,作用範圍僅限一個工作區 - 它只能讀取帳單資料,不能做別的事。

⚠

帳單金鑰可以讀取其工作區中記錄的每一次請求,包括之後已被刪除或撤銷的金鑰,但它不能呼叫任何模型,也不能建立、修改或刪除 API 金鑰。 在此之外的任何地方使用它都會回傳 401 wrong_key_kind.

建立帳單金鑰

  1. 開啟 Console → Billing API keys (僅工作區所有者可用)。為其命名,可選擇限制到 IP 白名單或設定到期時間,然後複製金鑰 - 它以 sk-syn-bill- 並且只會顯示一次。
  2. 將其作為 Bearer token 呼叫下方各端點。 可隨時在同一頁面撤銷它 - 撤銷會立即使其失效,且不影響工作區中的任何其他內容。
  3. 金鑰與其建立者綁定:如果該建立者不再是工作區所有者,金鑰會停止運作並回傳 403 key_owner_not_authorized.

驗證

每次呼叫都需要 Authorization: Bearer sk-syn-bill-... ,並針對下方的 base URL 發起請求。帳單金鑰只能用於這些端點,而這些端點也只接受帳單金鑰 - 任何其他組合都會回傳 401 wrong_key_kind.

Authorization: Bearer sk-syn-bill-...

Base URL: https://synthorai.io/api/v1/billing

ℹ

作用範圍是整個工作區:其中的每一個推論金鑰都包含在內,即使已被刪除的金鑰,其歷史記錄也仍可查詢。 api_key_id 和 model 篩選條件只能縮小結果範圍,絕不會擴大;每次查詢都以該金鑰自身的工作區為界。

ℹ

每次查詢都在唯讀副本上執行,絕不會用主庫。未設定副本的行程會回傳 503 replica_unavailable 而不是靜默回退到主庫。

✓

Token 欄位: 遵循 OpenAI 的慣例 - prompt_tokens 是總輸入 token 數,已經包含下面每一項快取讀取與快取寫入,而 completion_tokens 已經包含 reasoning_tokens。兩者都不是在總數之外額外疊加的 - 它們是明細拆分,不是額外的 token。

prompt_tokens 中的快取讀取部分即 cached_tokens;快取寫入部分即 cache_write_tokens,在 /records 的行中會按 TTL 進一步拆分為 cache_write_5m_tokens 和 cache_write_1h_tokens。

✓

金額欄位: cost_usd 是實際收取的金額。 byok_list_price_usd 是 BYOK 請求按標價本應花費的金額 - 非 BYOK 請求為 0。不存在 list_price_usd 這個欄位。

ℹ

此處的「錯誤」指所有已到達 API 並被拒絕的請求 - 包括 402(餘額不足)、403、429 等 4xx,以及上游失敗。只有我方自己的內部基礎設施拒絕會被排除,這與主控台的口徑一致。拒絕請求在每台伺服器上按 key、狀態碼、分鐘最多記錄一次,因此 402、403、429 的次數是下限;成功請求與扣費是完整的。

GET /usage - 匯總用量

GET /usage

按小時或按天預先彙總的資料,適合對帳與儀表板。資料來自小時彙總表,並補上自上次彙總以來新寫入的請求,因此最近的時間桶不會整整落後一個彙總週期。

參數類型說明
start*string範圍起點:RFC 3339 時間戳或類似 2026-09-01 的日期。
endstring範圍終點。預設為目前時間。
granularitystring分桶粒度:hour 或 day。預設為 day。
group_bystring用於拆分行的維度:api_key、model,或兩者都要(任意子集)。預設為兩者都要。
api_key_idinteger按一個或多個 API 金鑰 id 篩選。可重複傳入;只會縮小範圍,絕不會擴大。
modelstring按一個或多個模型 id 篩選。可重複傳入。
limitinteger每頁行數。預設 1000,上限 5000。
cursorstring不透明的分頁游標,取自上一頁回應中的 meta.next_cursor。

在每一行中,api_key_id 與 api_key_name 只有在 group_by 包含 api_key 時才會出現,model 同理只有在包含 model 時才會出現。當某個桶沒有延遲取樣時,avg_latency_ms 可能為 null。

範例請求

curl "https://synthorai.io/api/v1/billing/usage?start=2026-09-01&end=2026-09-24&granularity=day" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{
  "data": [
    {
      "bucket_start": "2026-09-23T00:00:00Z",
      "bucket_end": "2026-09-24T00:00:00Z",
      "api_key_id": 42,
      "api_key_name": "prod-backend",
      "model": "claude-sonnet-5",
      "requests": 1280,
      "success_requests": 1265,
      "error_requests": 15,
      "errors_4xx": 12,
      "errors_429": 2,
      "errors_5xx": 1,
      "prompt_tokens": 512000,
      "completion_tokens": 98000,
      "cached_tokens": 210000,
      "cache_write_tokens": 8000,
      "reasoning_tokens": 4000,
      "cost_usd": 4.1732,
      "byok_list_price_usd": 0,
      "byok_requests": 0,
      "avg_latency_ms": 812,
      "final": true
    }
  ],
  "meta": {
    "generated_at": "2026-09-24T08:00:00Z",
    "data_complete_until": "2026-09-24T06:00:00Z",
    "timezone": "UTC",
    "currency": "USD",
    "next_cursor": null,
    "has_more": false
  }
}

GET /records - 逐請求行

GET /records

每個請求一行,用於增量同步到你自己的資料庫。請按 cursor 同步,絕不要按時間同步,並按 record_id 對收到的行去重 - 原因見下方「避免時間間隙」。

參數類型說明
cursorstring不透明的同步游標(字串),取自上一次呼叫回應中的 meta.next_cursor。cursor 與 start 只能提供一個;它沒有範圍上限。
startstring範圍起點(RFC 3339 時間戳或日期)。cursor 與 start 只能提供一個;start/end 範圍上限為 31 天,而 cursor 沒有範圍上限。
endstring範圍終點。預設為目前時間。
api_key_idinteger按一個或多個 API 金鑰 id 篩選。可重複傳入;只會縮小範圍,絕不會擴大。
modelstring按一個或多個模型 id 篩選。可重複傳入。
limitinteger每頁行數。預設 500,上限 1000。

範例請求

curl "https://synthorai.io/api/v1/billing/records?start=2026-09-24T00:00:00Z&limit=500" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{
  "data": [
    {
      "record_id": "rec_8f2a91c4",
      "request_id": "req_9f3c2b1a",
      "recorded_at": "2026-09-24T05:58:31Z",
      "completed_at": "2026-09-24T05:58:29Z",
      "api_key_id": 42,
      "api_key_name": "prod-backend",
      "model": "claude-sonnet-5",
      "status": "success",
      "status_code": 200,
      "prompt_tokens": 812,
      "completion_tokens": 194,
      "cached_tokens": 512,
      "cache_write_tokens": 64,
      "cache_write_5m_tokens": 64,
      "cache_write_1h_tokens": 0,
      "cost_usd": 0.00412,
      "byok_list_price_usd": 0,
      "is_byok": false,
      "is_stream": true,
      "duration_ms": 1340,
      "ttft_ms": 210
    }
  ],
  "meta": {
    "next_cursor": "eyJvIjoiODgxNDA5MCJ9",
    "has_more": false,
    "window_final": true,
    "safe_until": "2026-09-24T05:58:31Z",
    "latest_recorded_at": "2026-09-24T05:58:31Z",
    "data_complete_until": "2026-09-24T05:58:00Z"
  }
}
參數說明
next_cursor用於下一次呼叫的游標。始終存在。
has_more此時用該游標再次呼叫是否會回傳更多行。
window_final只有在提供了 end 且它早於或等於 safe_until 時才為 true - 此時你要求的範圍才可確保完整。否則不存在或為 false。
safe_until呼叫方可信為已定稿的最新 recorded_at;比這更新的行仍在被暫時保留。
latest_recorded_at所有行(無論是否已定稿)中最新的 recorded_at。
data_complete_until與 /freshness 回傳的值相同 - 按小時匯總表完整到什麼時間,用於與 /usage 交叉核對。
⚠

時間基準: /usage 按 completed_at 分桶(即請求完成的時間)。/records 的 start/end 篩選則按 recorded_at 篩選(即行被寫入的時間,在高負載下可能滯後於完成時間)。要將 /records 與 /usage 對齊,請自行按 completed_at 而非 recorded_at 對同步到的行分桶。

GET /records/export - 串流匯出

GET /records/export

篩選條件與 /records 相同,以換行分隔的 JSON(application/x-ndjson)串流回傳 - 專為大量補齊歷史資料設計,而非分頁列表。每個工作區同一時間只能有一個匯出串流;第二個會收到 429 too_many_concurrent_requests。

範例請求

curl -N "https://synthorai.io/api/v1/billing/records/export?cursor=eyJvIjoiODgxNDAzMiJ9" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{"record_id":"rec_8f2a91c4","request_id":"req_9f3c2b1a","model":"claude-sonnet-5","status":"success","cost_usd":0.00412}
{"record_id":"rec_8f2a91c5","request_id":"req_9f3c2b1b","model":"claude-sonnet-5","status":"success","cost_usd":0.00398}
{"_meta":{"next_cursor":"eyJvIjoiODgxNDA5MSJ9","rows":2,"complete":true,"window_final":true,"generated_at":"2026-09-24T06:00:02Z"}}

該串流的最後一行是一個 _meta 物件:

參數說明
next_cursor用於下一次匯出呼叫的游標。
rows此次串流傳輸中寫入的記錄數。
completefalse 表示該串流在耗盡整個範圍之前就已停止 - 請用 cursor=next_cursor 繼續。
window_final與 /records 中含義相同:只有在匯出的 end 早於或等於 safe_until 時才為 true。
generated_at該行的寫入時間。
stopped_becausecomplete 為 false 時出現:row_cap、scan_cap(已掃完單次允許的最大 id 範圍但結果未滿,常見於過濾條件很窄時)、time_cap、query_error 或 window_not_final。

GET /summary - 初步統計與異常

GET /summary

總量、按費用排名的模型與金鑰,以及該範圍的錯誤率,再加上一個 anomalies 清單(high_error_rate、rate_limited、data_not_final、rollup_delayed),每一項都帶有 info 或 warning 的嚴重級別以及一段易讀的說明文字。尚未定稿範圍內的數字仍可能變動 - 見下文。

參數類型說明
startstring範圍起點。預設為終點前 30 天。
endstring範圍終點。預設為目前時間。
api_key_idinteger按一個或多個 API 金鑰 id 篩選。可重複傳入;只會縮小範圍,絕不會擴大。
modelstring按一個或多個模型 id 篩選。可重複傳入。

models_count 與 keys_count 給出 top_models 與 top_keys 背後的總數,而這兩個清單最多列出按費用排名前 20 的項目。範圍預設為 end 之前的 30 天,用於 start 被省略的情況。

範例請求

curl "https://synthorai.io/api/v1/billing/summary?start=2026-09-17&end=2026-09-24" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{
  "data": {
    "totals": { "requests": 48210, "cost_usd": 132.55, "error_rate": 0.021 },
    "models_count": 6,
    "keys_count": 3,
    "top_models": [ { "model": "claude-sonnet-5", "cost_usd": 88.10, "byok_list_price_usd": 0 } ],
    "top_keys": [ { "api_key_id": 42, "api_key_name": "prod-backend", "cost_usd": 61.30, "byok_list_price_usd": 0 } ],
    "anomalies": [
      { "type": "data_not_final", "severity": "info", "message": "The last 2 hours of this range are not yet final." }
    ]
  },
  "meta": {
    "generated_at": "2026-09-24T06:00:02Z",
    "data_complete_until": "2026-09-24T04:00:00Z"
  }
}

GET /freshness - 資料完整度

GET /freshness

回傳 data_complete_until, latest_recorded_at, safe_until 和 pipeline_lag_seconds - 在把剛剛擷取的範圍視為已定稿之前,請先輪詢這個端點。safe_until 是呼叫方可信為已完整的最新 recorded_at;比它更新的行可能仍在到達中。

範例請求

curl "https://synthorai.io/api/v1/billing/freshness" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{
  "data": {
    "data_complete_until": "2026-09-24T04:00:00Z",
    "latest_recorded_at": "2026-09-24T05:58:31Z",
    "safe_until": "2026-09-24T05:58:31Z",
    "pipeline_lag_seconds": 47
  },
  "meta": { "generated_at": "2026-09-24T06:00:02Z" }
}

GET /balance - 工作區目前可用餘額

GET /balance

回傳工作區目前可用餘額,與主控台顯示的可用餘額一致。專為輪詢設計:每 30 到 60 秒查一次就足夠。它有獨立的速率限制,輪詢不會佔用資料類端點的額度;餘額為零時照常回傳。

範例請求

curl "https://synthorai.io/api/v1/billing/balance" \
  -H "Authorization: Bearer sk-syn-bill-..."

範例回應

{
  "data": {
    "available_usd": 1284.37,
    "debt_usd": 0,
    "source": "live",
    "voucher": null,
    "scheduled_credits": [
      { "amount_usd": 250, "release_at": "2026-10-01T00:00:00Z" }
    ],
    "scheduled_credit_total_usd": 250
  },
  "meta": { "generated_at": "2026-09-24T06:00:02Z", "currency": "USD" }
}
參數說明
available_usd目前請求實際扣費所用的通用餘額,最低為 0。在途請求結算後可能短暫回升;統計消費請用 /usage 或 /records。
debt_usd欠款:超出已儲值額度的用量,沒有欠款時為 0。儲值會先抵扣欠款,剩餘部分才計入 available_usd。
sourcelive:讀自即時帳本。delayed:即時帳本暫時無法讀取,數值來自資料庫副本,最多可能落後約 30 秒。
voucher活動/代金券額度,僅用於影像生成(見 applies_to),限所列模型、在 expires_at 之前可用;其他請求只使用 available_usd,券額不計入 available_usd。沒有時為 null;過期後 active 為 false。
scheduled_credits已約定、分期到帳的額度(amount_usd、release_at);每一期在 release_at 之後約 10 分鐘內計入餘額,之前不可使用。scheduled_credit_total_usd 為其合計。

錯誤

每個錯誤都是 {"error": {"type", "message", "hint"}}:

{
  "error": {
    "type": "range_too_large",
    "message": "the requested range exceeds this endpoint's cap",
    "hint": "narrow start/end to at most 31 days, or sync /records with a cursor instead"
  }
}
類型HTTP 狀態碼含義
invalid_parameter400某個查詢參數缺失、格式錯誤或超出範圍。
range_too_large400請求的時間範圍或 id 窗口超出該端點允許的上限;hint 欄位會說明具體上限。
start_too_recent400start/end 時間窗的開始時間晚於 safe_until,起點邊界尚未穩定。請依 Retry-After 標頭稍後重試,或改用 cursor 同步。
wrong_key_kind401該憑證不是帳單金鑰,或帳單金鑰被用在了這些端點之外。
authentication_error401金鑰缺失、無效、已過期,或被其 IP 白名單擋下。
key_owner_not_authorized403該金鑰的建立者已不再是工作區所有者。帳單金鑰僅限所有者本人使用,所有權轉移的那一刻起就會停止運作;新所有者必須建立自己的金鑰。
rate_limited429該工作區每分鐘請求數超過 60 次。請在 Retry-After 回應標頭指示的時間之後重試。
too_many_concurrent_requests429該工作區並行請求超過 3 個,或已有一個匯出正在進行。
replica_unavailable503該行程未設定唯讀副本;API 絕不會回退到主庫。
query_timeout503查詢超過了 10 秒的語句逾時限制或 15 秒的截止時限。請縮小範圍後重試。
internal_error500意外的伺服器錯誤。請重試,如果持續發生請回報。

速率限制與上限

防護措施值
速率限制每個工作區每分鐘 60 次請求,為全實例共享的滑動窗口。
並發數每個工作區在每台伺服器上最多 3 個並行請求,匯出串流在每台伺服器上每個工作區最多 1 個。
餘額輪詢/balance:每個工作區每分鐘 60 次、同時最多 2 個請求,與其他端點分開計數。
範圍上限/usage:hour 粒度 31 天,day 粒度 366 天。/summary:最多 366 天。/records 與匯出:最多 31 天。
分頁上限/usage 每頁最多回傳 5,000 行,/records 最多 1,000 行。匯出以每頁 2,000 行串流傳輸,並在 1,000,000 行處停止 - 可用 cursor 繼續。單次匯出掃過 2,000,000 個紀錄 id 後也會停止(stopped_because=scan_cap),並會依資料庫負載自動放慢;用 cursor 繼續。
快取每個回應都帶有 Cache-Control: no-store。

絕不會回傳: channel_id, upstream_request_id, usage_raw, other, content, ip_address, user_agent, cost_detail.

避免時間間隙

請求完成後會非同步寫入日誌(通常幾秒鐘,積壓時會更久),而 /usage 與 /summary 讀取的按小時匯總表是按批次寫入的。最近幾個小時的資料總是有一點不完整。/usage 與 /summary 會補上自上次彙總以來新寫入的請求(meta.live_tail 為 true);彙總落後太多時不再補(meta.live_tail 為 false),最近的時間桶是不完整的。

data_complete_until 取以下兩者中較早的一個:按小時匯總表的水位線減去目前的處理延遲,或尚未被匯總的最早請求 - 再減去 30 分鐘的安全餘量,並向下取整到小時。

ℹ

已定稿的桶是穩定的,只有一個例外:每日對帳任務如果發現偏差,仍可能在 48 小時內修正某個小時的資料。/records 永遠是某次請求精確數字的權威來源。

每個 /usage 行都帶有一個 final 標誌: true ,即當其所在的桶結束時間早於或等於 data_complete_until (/freshness 回傳的值)時成立。已定稿的桶不會再變化。

  • 聚合資料: 按 (bucket_start, api_key_id, model) 將每一行 upsert 到你自己的儲存中,並在某個桶仍為 final: false 時重新擷取它。絕不要用新總量減去舊總量的方式來推算增量。
  • 原始行: 按 cursor 同步,絕不要按時間同步。請保留 next_cursor,並在下一次呼叫時從它繼續,同時按 record_id(每行穩定的不透明 id)對收到的行去重,以防某次續傳重複送達同一行。晚於約 5 分鐘的行會被暫時保留 - safe_until 即最新已記錄行的時間減去 5 分鐘 - 因此一個仍在提交中的行絕不會跑到已發出的游標位置之前,也就不會有資料落入間隙。統計請求數時,請依 request_id 去重計數。
  • 限定窗口: 如果你查詢的是 start/end 範圍而不是按 cursor 同步,只有在 window_final 為 true 時才可信其為完整(只有當你提供了 end 且它早於或等於 safe_until 時才為 true)。如果 window_final 為 false,請稍後用相同範圍再次呼叫,或改為按 cursor 同步。時間窗的開始時間必須不晚於 safe_until;更晚的開始時間會回傳 400 start_too_recent,並帶 Retry-After 標頭。

建議的整合方式

  • 每晚帳單處理: 每天呼叫一次 /usage,並使用 granularity=day;對上一次執行中仍為 final: false 的桶重新擷取。
  • 逐請求明細: 每小時呼叫一次 /records,將 cursor 設為你儲存的上一次 next_cursor,並在 has_more 為 true 時持續翻頁,同時按 record_id 對收到的行去重。
  • 儀表板: 對目前可見範圍呼叫 /summary,而不是自己聚合 /records - 它已經附帶了異常清單。

需要以程式化方式簽發或管理一般 API 金鑰,而不是讀取帳單資料?請參閱 Provisioning Keys。