# API キーと REST API

ダッシュボードで API キーを作り、REST API で登録済みのサーバーの採点を CI から保存し、評価を動かす方法と、エンドポイント、上限、誤りを説明します。

`https://api.forecall.dev` の REST API で、[ダッシュボードに登録した](https://forecall.dev/ja/docs/dashboard)サーバーの採点を保存して読み、評価を動かせます。OpenAPI の仕様書は [api.forecall.dev/v1/openapi.json](https://api.forecall.dev/v1/openapi.json) にあります。

## API キー

キーは、組織の owner と admin がダッシュボードの **API キー**で作ります。キーには用途が 1 つあります。

- **CI 用**: ビルドから採点を保存します。ほかのことはできません。
- **スクリプト用**: 自分のスクリプトから使います。採点の保存もでき、[評価](#evaluations)にはこのキーを使います。
- **エージェント用**: 自分の AI エージェントが `mcp.forecall.dev` で Failure KB を使うためのキーです。失敗の照会と投稿だけができ、この REST API は呼べません。

キーは作ったときに一度だけ表示し、Forecall はハッシュしか残しません。なくしたら失効させて作り直します。キーは要求のたびに送ります。`GET /v1/me` は、キーの組織と用途を返します。

```sh
curl -H "Authorization: Bearer $FORECALL_API_KEY" https://api.forecall.dev/v1/me
```

## CI から採点を保存する

`POST /v1/servers/{id}/lint` は、本文にサーバーの `tools/list` を受け取ります（[受け付ける形](https://forecall.dev/ja/docs/tools-list#formats)のどれでも、1 MiB、200 ツールまで）。`{id}` はサーバーの ID で、ダッシュボードのサーバーの画面の URL（`/servers/{id}`）の最後の部分です。`?label=` で版の名前を付けられます（50 文字まで）。

ダッシュボードと同じく、版を足すのはツールが最新の版と違うときだけで、採点は呼ぶたびに保存します。応答には、リンターと同じ結果と、前の版との違い（`changes`。採点した前の版がなければ `null`）が入ります。

GitHub Actions では、キーを secret に入れて次のようにします。

```yaml
- run: npx forecall@0.2 dump -o tools.json -- node dist/server.js
- run: >
    curl -fsS -X POST --data-binary @tools.json
    -H "Authorization: Bearer ${{ secrets.FORECALL_API_KEY }}"
    "https://api.forecall.dev/v1/servers/${{ vars.FORECALL_SERVER_ID }}/lint?label=${{ github.sha }}"
```

`GET /v1/servers/{id}/lint/latest` で、最新の版の最新の採点を読めます。

## 評価

評価は、ツールごとに作った発話（ケース）について、モデルがサーバーのどのツールを呼ぶかを聞き、引数も確かめます。Pro と Team のプランで使え、**スクリプト用**のキーが要ります。ケース、指標、単位と、ダッシュボードでの動かし方は「[モデルでサーバーを評価する](https://forecall.dev/ja/docs/evaluations)」で説明します。

`POST /v1/servers/{id}/evaluations/estimate` は、サーバーの最新の版を評価するのに使う単位を返します。単位は使いません。本文は省ける JSON です。

| 項目 | 内容 | 既定 |
|---|---|---|
| `models` | モデル（`vendor/name`）: `anthropic/claude-opus-5-5`、`anthropic/claude-sonnet-5-5`、`openai/gpt-6-astra`、`openai/gpt-6.1-sol`（`google/gemini-3.8-flash` はいまは止めています） | `anthropic/claude-sonnet-5-5`、`openai/gpt-6.1-sol` |
| `distractors` | モデルに一緒に見せる、同梱の公開サーバーのツール: `bhived`、`context7`、`debugbase`、`filesystem`、`firecrawl`、`memory`、`notion`、`playwright` | なし |
| `lang` | 発話の言語: `en`、Team なら `ja` も | `en` |

ケースはツールごとに Pro で 8、Team で 20 で、どのツールも呼ぶべきでない発話と、取り違えやすいツールを狙った発話も少し入ります。同じ版と設定の評価がケースを持っていなければ、ケースを作る分も数えます。組織がすでに持っているモデルの結果は、数え直しません。応答には、今月の残りの単位とクレジット（`balance`）も入ります。

`POST /v1/servers/{id}/evaluations` は、同じ本文（と省ける `name`）を受け取り、見積もりの単位を使って評価を始めます。応答は `202` で、評価の `id`、モデルごとの実行の単位、進み具合を読む `Location` が入ります。今月の枠とクレジットが足りなければ `402` を返し、何も始めません。評価が失敗したら、終わらなかったケースの分の単位をクレジット（有効期間 6 か月）で返します。

```sh
curl -fsS -X POST -H "Authorization: Bearer $FORECALL_API_KEY" \
  -d '{"models": ["anthropic/claude-sonnet-5-5", "openai/gpt-6.1-sol"]}' \
  "https://api.forecall.dev/v1/servers/$SERVER_ID/evaluations"
```

`GET /v1/evaluations/{id}` は評価の状態（`queued`、`running`、`done`、`failed`）、ケースの数、モデルごとの答えたケースの数と、実行が終わったら指標を返します。指標は `selectionAcc`（期待するツールを呼んだ割合）、`argValidity`（そのときの引数が正しかった割合）、`falseCallRate`（呼ぶべきでないのに呼んだ割合）、`confusion`（代わりに呼んだツール）です。

## 上限

キーごとに、1 分あたりの要求の数に上限があります（組織のプランで決まります）。超えると `429` と `Retry-After` を返します。採点の保存は、組織の月（UTC）の枠から 1 単位を使い、キーの用途ごとに数えます。枠と組織のクレジットを使い切ると、保存は `402` を返し、何も保存しません。評価は、見積もりの単位をスクリプト用のキーの枠から使います。読むだけ、見積もるだけなら単位は使いません。今月の使用量は、ダッシュボードの **API キー**の画面で見られます。

## 誤り

誤りはすべて同じ形（`{"error": {"code": "…", "message": "…"}}`）で、入力の誤りには場所を示す `detail`（パス、直すキー、重なった名前）が付きます。

| 状態 | code |
|---|---|
| 401 | `unauthorized`: キーがない、違う、失効している |
| 402 | `quota_exceeded`、`plan_has_no_evaluations`、`payment_failed`（組織の直前の支払いに失敗している間。ダッシュボードの「プランと請求」でカードを直す） |
| 404 | `not_found`: キーの組織にそのサーバーか評価がない、まだ版か採点がない |
| 413 | `input_too_large` |
| 422 | `invalid_json`、`unrecognized_shape`、`invalid_tool`、`too_many_tools`、`snake_case_keys`、`duplicate_names`、`invalid_label`、`invalid_request`、`unknown_models`、`unknown_distractors`、`lang_not_in_plan` |
| 429 | `rate_limited` |
