# サーバーREST API

> 自分のサーバーからチャットルームの状態を取得し、プラグインチャンネルにデータを送るREST API（v2）の認証、エンドポイント、レスポンス、エラーコードと、以前のv1方式です。

サーバーREST APIを使うと、自分のサーバーからチャットルームの状態（接続者数・接続者一覧・最近のチャット）を取得し、プラグインチャンネルにデータを送れます。このページは、リクエスト形式・レスポンス・エラーコードの正式なリファレンスです。手順に沿って試すには[サーバーからチャットルームに通知を送る](/ja/doc/2.5)を参照してください。

## 準備: APIキーとチャットルームID {#keys}

管理ページの **API** メニューで2つの値を確認します。

| 値 | 形式 | 説明 |
| --- | --- | --- |
| APIチャットルームID | `room_` + 英小文字・数字16文字 | URLの `{id}` の位置に入れます。チャットルームIDと違って変わらず、URLにそのまま使えます |
| APIキー | `uchat_` + 英小文字・数字32文字 | 発行時に**一度だけ**表示されます。紛失した場合は、そのキーを再発行するか、無効化して新しく発行します |

- キーごとに名前と権限を決めます。**取得**（`read`）はGETエンドポイント、**イベント**（`events`）はイベント送信に必要です。権限と名前は後から変更でき、変更した権限は次の呼び出しから適用されます。
- **値を再発行**は、名前・権限・利用履歴をそのまま残し、キーの値だけを変えます。古い値はすぐに使えなくなります。
- チャットルームごとに使用中のキーは20個までです。
- APIキーはサーバーにだけ置いてください。ブラウザから呼ぶとキーが露出し、誰でもチャットルームにデータを送れるようになります。
- 呼び出しはキーごとに **API** メニューの使用量・呼び出し履歴に30日間残ります（リクエスト本文の先頭1KBとIPを含む）。個人情報・決済情報をそのまま送らないでください。
- **API** メニューの **試す** で、キーなしでエンドポイントを実行して実際のレスポンスを確認できます（呼び出し回数には数えません）。

## リクエスト形式 {#request}

| 項目 | 値 |
| --- | --- |
| URL | `https://api.uchat.io/v2/rooms/{id}/...` |
| `Authorization` ヘッダー | `Bearer {APIキー}` |
| 本文 | `POST` はJSONオブジェクト（下の[イベントを送る](#events)） |

| メソッド | パス | 権限 | プラン | 説明 |
| --- | --- | --- | --- | --- |
| `GET` | `/v2/rooms/{id}` | 取得 | 有料 | [チャットルームの概要](#room) |
| `GET` | `/v2/rooms/{id}/stats` | 取得 | 無料 | [接続者数](#stats) |
| `GET` | `/v2/rooms/{id}/users` | 取得 | 有料 | [接続者一覧](#users) |
| `GET` | `/v2/rooms/{id}/messages` | 取得 | 有料 | [最近のチャット](#messages) |
| `POST` | `/v2/rooms/{id}/events` | イベント | 無料 | [イベントを送る](#events) |

## レスポンスと上限 {#response}

成功すると `data` に結果が入ります（イベントはHTTP 202）。

```json
{ "data": { "online": 15 } }
```

失敗するとHTTPステータスと `error` が返ります。全一覧は[エラーコード](#errors)です。

```json
{ "error": { "code": "invalid_key", "message": "This API key is not valid for this room." } }
```

| プラン | 1分あたり | 1日（UTC） |
| --- | --- | --- |
| 無料のチャットルーム | 60回 | 1,000回 |
| 有料のチャットルーム | 600回 | 制限なし |

- 超えるとHTTP 429（`rate_limited`、`daily_limit`）です。1分あたりの上限では、`Retry-After` ヘッダーで待つ秒数を知らせます。
- 1日の回数はキーが一致した呼び出しだけを数えます。キーが間違ったリクエストには別に1分あたりの上限があるため、他人の誤ったリクエストが自分の上限を消費することはありません。

## チャットルームの概要 {#room}

`GET /v2/rooms/{id}`（有料）

```sh
curl https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx \
  -H "Authorization: Bearer uchat_..."
```

```json
{
	"data": {
		"id": "room_xxxxxxxxxxxxxxxx",
		"room_id": "my-room",
		"name": "マイチャットルーム",
		"channel": false,
		"plan": "paid",
		"paid": true,
		"created_at": "2026-10-11T01:59:53.000Z",
		"online": 15,
		"settings": { "frozen": false, "join_password": false, "chat_length_limit": 100 }
	}
}
```

## 接続者数 {#stats}

`GET /v2/rooms/{id}/stats`（無料）

```json
{
	"data": {
		"online": 15,
		"roles": { "guest": 3, "member": 10, "subadmin": 1, "admin": 1 },
		"devices": { "pc": 9, "mobile": 6 }
	}
}
```

接続者がいなくてもエラーにならず、すべて0です。

## 接続者一覧 {#users}

`GET /v2/rooms/{id}/users`（有料）

```json
{
	"data": [
		{
			"nick": "みなみ",
			"user_id": "minji",
			"role": "member",
			"level": 3,
			"device": "mobile",
			"connected_at": "2026-10-19T03:12:45.000Z"
		}
	]
}
```

- `role` は `guest`・`member`・`subadmin`・`admin` です。`user_id` は会員連携で入室した人にだけあり、それ以外は `null` です。
- IP・セッションと非表示の接続は返しません。

## 最近のチャット {#messages}

`GET /v2/rooms/{id}/messages?limit=50&before={メッセージid}`（有料）

```json
{
	"data": [
		{
			"id": "bfd6a342c0f549beb12f4a1c4e05831c",
			"type": "message",
			"nick": "みなみ",
			"user_id": null,
			"role": "guest",
			"text": "こんにちは",
			"created_at": "2026-10-19T03:15:02.000Z"
		}
	]
}
```

| 値 | 説明 |
| --- | --- |
| `limit` | 1〜100、デフォルト50。新しいものから返ります |
| `before` | このメッセージの `id` より古いものから。次のページを見るときは最後のメッセージの `id` を入れます |
| `type` | `message`（チャット）または `notice`（お知らせ） |
| `id` | Webhook通知のイベントidと同じ値（32文字の16進数） |

- 全員に表示されたチャットとお知らせだけが返ります。ウィスパー、削除したチャット、AIが隠したチャットは含まれません。
- チャットサーバーがまとめて保存するため、直前のチャットは数秒遅れて表示されることがあります。

## イベントを送る {#events}

`POST /v2/rooms/{id}/events`（無料）

```sh
curl -X POST https://api.uchat.io/v2/rooms/room_xxxxxxxxxxxxxxxx/events \
  -H "Authorization: Bearer uchat_..." \
  -H "Content-Type: application/json" \
  -d '{"plugin":"payment","data":["paid","order-1001",15000]}'
```

```json
{ "data": { "sent": true } }
```

| キー | 説明 |
| --- | --- |
| `plugin` | 受け取るチャンネル名（英数字・`_`・`-` 1〜64文字） |
| `data` | 値の配列（20要素、合計2KBまで）。文字列・数値・真偽値だけを使い、受信側にはすべて**文字列**で届きます。改行などの制御文字は入れられません |
| `to` | （任意）ニックネーム。その人にだけ送ります |
| `save` | （任意）`true` なら、そのチャンネルの最後の値として保存し、後から入室する人にも送ります。空の `data` を保存すると削除します |

- 受信側は `room.plugin.add('{plugin}').onReceived` です。`data.user.auth` が `4` で、ニックネームは空です。`data.type` は全員宛てなら `0`、1人宛て・保存値なら `1` です。
- 接続者がいなくても成功です（受け取る人がいないだけです）。`save` はこの場合も保存され、次に入室した人が受け取ります。
- **`save` の上限は[チャンネルの保存](/ja/doc/3.5#save)と同じです。** 無料のチャットルームはチャンネル1つ・1KB、有料のチャットルームはチャンネルごとに4KB・合計60KBです。無料のチャットルームで別のチャンネルを保存すると、前のチャンネルは削除されます。保存値はチャットルームが空になってもサーバーが再起動しても残ります。
- `save` と `to` は同時に使えません。
- 無料のチャットルームでは、ページスクリプトからの送信と同じ1分あたりの上限を共有します。超えると `chat_rate_limited`（429）です。[チャンネルAPIと上限](/ja/doc/3.5#limits)
- uchatのプラグインのうち、イベント通知ウィンドウ・寄付目標バー・配信状態・スコアボード・カウントダウン・ランキングは、このAPIで送った値を表示します。送る形式は各プラグインの案内にあります。

受信側のコード:

```js
U.chat('*').on('after.create#payment', function (room) {
	if (room.id !== 'my-room') return;
	room.plugin.add('payment').onReceived(function (room, data) {
		if (!data.user || data.user.auth !== 4) return; // サーバーが送ったものだけ
		if (data.data[0] === 'paid') room.print('決済が完了しました: ' + data.data[1]);
	});
});
```

## エラーコード {#errors}

| HTTP | `code` | 意味 |
| --- | --- | --- |
| 400 | `invalid_limit`、`invalid_before` | `messages` の値が形式に合わない |
| 400 | `invalid_json`、`invalid_body` | 本文がJSONオブジェクトではない |
| 400 | `invalid_plugin`、`invalid_to`、`invalid_save` | `plugin`・`to`・`save` の値が形式に合わない |
| 400 | `invalid_data`、`data_too_large` | `data` が配列ではない、または値の種類・制御文字・要素数・サイズが合わない |
| 400 | `save_with_to` | `save` と `to` を同時に使った |
| 400 | `state_too_large` | 保存の上限を超えた |
| 401 | `missing_key` | `Authorization: Bearer` ヘッダーがない |
| 401 | `invalid_key` | このチャットルームのキーではない、または無効化したキー |
| 403 | `insufficient_scope` | キーにこのエンドポイントの権限（取得・イベント）がない |
| 403 | `paid_plan_required` | 有料のチャットルーム専用のエンドポイント |
| 404 | `room_not_found` | APIチャットルームIDが存在しない |
| 404 | `target_not_found` | `to` のニックネームがチャットルームにいない |
| 429 | `rate_limited`、`daily_limit` | 1分あたり・1日の呼び出し上限を超えた |
| 429 | `chat_rate_limited` | 無料のチャットルームのチャンネル送信上限を超えた |
| 503 | `chat_server_unavailable` | チャットサーバーが応答しない。しばらくしてから再度お試しください |

## 以前の方式（v1） {#v1}

以前に作った連携のために、v1もそのまま動作します。新しく作る場合はv2を使ってください。v1は同じAPIキーで認証し（以前のAPIトークンは **API** メニューに「v1キー」として移されています）、呼び出し履歴にも残ります。

| 項目 | 値 |
| --- | --- |
| URL | `https://api.uchat.io/rooms/{チャットルームID}/stats`、`.../plugin/{チャンネル}`、`.../plugin/{チャンネル}/{ニックネーム}` |
| `User-Agent` ヘッダー | 正確に `uchat_api_client_v1`（異なる場合はHTTP 404 `{"status":"fail","msg":"unknown_api_version"}`） |
| `X-UCHAT-API-TOKEN` ヘッダー | APIキー |
| `X-UCHAT-API-ROOM` ヘッダー | チャットルームID。URLに `/rooms/{チャットルームID}` を含めない場合だけ |
| 本文 | `POST` はJSON配列 |

- 成功はHTTP 200 `{"success":true,"status":"success","data":...}`、失敗は**常にHTTP 500**と `error_code` です。
- `stats` は接続者がいなければすべて0で、チャンネル送信は接続者がいなくても成功です（1人に送る場合は404）。
- `save` はありません。

| `error_code` | 意味 |
| --- | --- |
| `1` | キーが一致しない、無効化したキー、または存在しないチャットルーム |
| `2` | チャットルームIDがない |
| `4`、`5` | 存在しないパス、サポートしていないメソッド |
| `6` | `X-UCHAT-API-TOKEN` ヘッダーがない |
| `7`、`8`、`10` | チャンネル名がない、本文が空、本文が配列ではない |
| `11` | キーにこのAPIの権限がない（`stats` は取得、`plugin` はイベント） |
| `101` | チャットサーバーとの通信形式エラー |
| `404` | 対象のニックネームがチャットルームにいない |
| `428` | 無料のチャットルームのチャンネル送信上限を超えた |
| `0` | その他のエラー |
