課金 API
コンソールを開かずに、自分のワークスペースの使用量とコストのデータを自分のシステムに取り込めます。課金キーは 読み取り専用の 資格情報で、1 つのワークスペースに限定されます - 課金データを読み取れるだけで、他には何もできません。
課金キーはそのワークスペースに記録されたすべてのリクエストを読み取れます。その後削除または取り消されたキーも含まれますが、モデルを呼び出すことはできず、API キーの作成・変更・削除もできません。 これら以外の場所で使用すると、 401 wrong_key_kind.
課金キーを作成する
- 開く: Console → Billing API keys (ワークスペースの所有者のみ)。名前を付け、必要に応じて IP 許可リストで制限するか有効期限を設定し、キーをコピーします - キーは
sk-syn-bill-で、表示されるのは一度だけです。 - これを Bearer トークンとして、以下のエンドポイントを呼び出します。 同じページからいつでも取り消せます - 取り消すと即座に無効になり、ワークスペース内の他の何にも影響しません。
- キーはその作成者に紐づいています。作成者がワークスペースの所有者でなくなると動作を停止し、
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 静かにフォールバックすることはありません。
トークンフィールド: OpenAI の規約に従います - prompt_tokens は入力トークンの合計で、以下のすべてのキャッシュ読み取りとキャッシュ書き込みを既に含んでいます。そして completion_tokens は既に reasoning_tokensを含んでいます。どちらも合計に上乗せされるものではなく、内訳であって追加のトークンではありません。
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のどこにも存在しません。
ここでの「エラー」とは、API に到達して拒否されたすべてのリクエストを指します - 402(残高不足)、403、429 などの 4xx、および上流の失敗が含まれます。除外されるのは自社の内部インフラによる拒否のみで、コンソールと同じ基準です。拒否されたリクエストは各サーバーで key・ステータスコード・分ごとに最大 1 回記録されるため、402、403、429 の件数は下限値です。成功したリクエストと課金は完全です。
GET /usage - 集計使用量
GET /usage
時間単位または日単位で事前集計された行。請求書やダッシュボード向けです。時間ごとのロールアップに、前回の取り込み以降に書き込まれたリクエストを加えるため、直近のバケットが取り込み 1 周期分まるごと遅れることはありません。
| パラメータ | 型 | 説明 |
|---|---|---|
start* | string | 範囲の開始:RFC 3339 のタイムスタンプ、または 2026-09-01 のような日付。 |
end | string | 範囲の終了。デフォルトは現在時刻です。 |
granularity | string | バケットの粒度:hour または day。デフォルトは day です。 |
group_by | string | 行を分割する次元:api_key、model、または両方(任意の組み合わせ)。デフォルトは両方です。 |
api_key_id | integer | 1 つ以上の API キー id で絞り込みます。繰り返し指定可能で、範囲を狭めるだけで広げることはありません。 |
model | string | 1 つ以上のモデル id で絞り込みます。繰り返し指定可能です。 |
limit | integer | 1 ページあたりの行数。デフォルトは 1000、上限は 5000 です。 |
cursor | string | 前のページの 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
リクエストごとに 1 行あり、自社データベースへの差分同期を想定しています。cursor で同期してください。時間で同期してはいけません。受け取った行は record_id で重複排除してください - 理由は下記の「時間の欠落を避ける」を参照してください。
| パラメータ | 型 | 説明 |
|---|---|---|
cursor | string | 前回の呼び出しの meta.next_cursor から取得する、不透明な同期用カーソル(文字列)。cursor と start はどちらか一方のみを指定してください。範囲の上限はありません。 |
start | string | 範囲の開始(RFC 3339 のタイムスタンプまたは日付)。cursor と start はどちらか一方のみを指定してください。start/end の範囲は最大 31 日ですが、cursor には範囲の上限がありません。 |
end | string | 範囲の終了。デフォルトは現在時刻です。 |
api_key_id | integer | 1 つ以上の API キー id で絞り込みます。繰り返し指定可能で、範囲を狭めるだけで広げることはありません。 |
model | string | 1 つ以上のモデル id で絞り込みます。繰り返し指定可能です。 |
limit | integer | 1 ページあたりの行数。デフォルトは 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 と一致させるには、同期した行を recorded_at ではなく completed_at 自身で分桶してください。
GET /records/export - ストリーミングエクスポート
GET /records/export
/records と同じフィルタを使い、改行区切りの JSON(application/x-ndjson)としてストリーミングされます - ページ分けされたリストではなく、大量のバックフィル向けに作られています。1 つのワークスペースで同時にストリーミングできるエクスポートは 1 つだけで、2 つ目は 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 | このストリームで書き込まれたレコード数。 |
complete | false は、範囲を使い切る前にストリームが停止したことを意味します - cursor=next_cursor で再開してください。 |
window_final | /records と同じ意味です:エクスポートの end が safe_until 以前である場合にのみ true になります。 |
generated_at | この行が書き込まれた時刻です。 |
stopped_because | complete が false のときに付きます:row_cap、scan_cap(1 回に走査できる最大 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 の重大度と、人が読める形式のメッセージが含まれます。確定していない範囲の数値は今後も変わる可能性があります - 詳細は下記を参照してください。
| パラメータ | 型 | 説明 |
|---|---|---|
start | string | 範囲の開始。デフォルトは end の 30 日前です。 |
end | string | 範囲の終了。デフォルトは現在時刻です。 |
api_key_id | integer | 1 つ以上の API キー id で絞り込みます。繰り返し指定可能で、範囲を狭めるだけで広げることはありません。 |
model | string | 1 つ以上のモデル 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 になります。 |
source | live:リアルタイム台帳から読み取った値。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_parameter | 400 | クエリパラメータが欠落、不正な形式、または範囲外です。 |
range_too_large | 400 | 要求された時間範囲または id ウィンドウが、そのエンドポイントで許可されている上限を超えています。hint に上限の名前が示されます。 |
start_too_recent | 400 | start/end の期間の開始が safe_until より後で、開始境界がまだ確定していません。Retry-After ヘッダーの時間後に再試行するか、cursor で同期してください。 |
wrong_key_kind | 401 | この資格情報は課金キーではありません。あるいは課金キーがこれらのエンドポイント以外で使われました。 |
authentication_error | 401 | キーが欠落、無効、期限切れ、または IP 許可リストによってブロックされています。 |
key_owner_not_authorized | 403 | このキーの作成者はもうワークスペースの所有者ではありません。課金キーは所有者本人専用で、所有権が移った瞬間に動作を停止します。新しい所有者は自分のキーを作成する必要があります。 |
rate_limited | 429 | このワークスペースで 1 分あたり 60 リクエストを超えました。Retry-After ヘッダーに示された時間の後に再試行してください。 |
too_many_concurrent_requests | 429 | このワークスペースで同時リクエストが 3 件を超えたか、別のエクスポートがすでに実行中です。 |
replica_unavailable | 503 | このプロセスには読み取り専用レプリカが設定されていません。API はプライマリにフォールバックすることはありません。 |
query_timeout | 503 | クエリが 10 秒のステートメントタイムアウトまたは 15 秒の期限を超えました。範囲を狭めて再試行してください。 |
internal_error | 500 | 予期しないサーバーエラーです。再試行し、繰り返す場合はご報告ください。 |
レート制限と上限
| ガード | 値 |
|---|---|
| レート制限 | ワークスペースごとに 1 分あたり 60 リクエスト。すべてのインスタンスで共有されるスライディングウィンドウです。 |
| 同時実行数 | ワークスペースごと・サーバーごとに同時 3 リクエストまで。エクスポートはワークスペースごと・サーバーごとに 1 本まで。 |
| 残高のポーリング | /balance:ワークスペースごとに毎分 60 リクエスト、同時 2 件まで。他のエンドポイントとは別に数えます。 |
| 範囲の上限 | /usage:hour 粒度で 31 日、day 粒度で 366 日。/summary:最大 366 日。/records とエクスポート:最大 31 日。 |
| ページの上限 | /usage は 1 ページあたり最大 5,000 行、/records は最大 1,000 行を返します。エクスポートは 1 ページ 2,000 行でストリーミングし、1,000,000 行で停止します - cursor で再開できます。記録 id を 2,000,000 件分走査した時点でも停止し(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 は次の 2 つのうち早い方です:時間単位のロールアップの水位線から現在のパイプライン遅延を引いた値、またはまだロールアップされていない最も古いリクエスト - そこから 30 分の安全マージンを引き、時単位に切り下げます。
確定済みのバケットは安定していますが、1 つだけ例外があります:日次の照合ジョブがずれを見つけた場合、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 の重複を除いて数えてください。
- 限定された範囲: cursor で同期する代わりに start/end の範囲を指定した場合、window_final が true のときにのみ完全であると信頼してください(end を指定し、それが safe_until 以前である場合にのみ true になります)。window_final が false の場合は、同じ範囲で後ほど再度呼び出すか、cursor による同期に切り替えてください。期間の開始は safe_until 以前である必要があります。それより後の開始は 400 start_too_recent(Retry-After ヘッダー付き)を返します。
推奨される連携方法
- 夜間の請求処理: 1 日 1 回、granularity=day で /usage を呼び出し、前回の実行で final: false だったバケットは再取得してください。
- リクエスト単位の詳細: 1 時間ごとに、保存済みの直前の next_cursor を cursor に設定して /records を呼び出し、has_more が true の間はページングを続け、受け取った行は record_id で重複排除してください。
- ダッシュボード: 表示中の範囲には /records を自前で集計するのではなく /summary を呼び出してください - 異常リストが既に含まれています。
課金データの読み取りではなく、通常の API キーをプログラムで発行・管理する必要がありますか? Provisioning Keysをご覧ください。