Chat API
ThemisはREST APIを提供しており、外部アプリケーションからメッセージを送信してAIレスポンスを受け取ることができます。APIはWeb・メッセージングチャネルと同じエージェントパイプラインを使用するため、スペースで利用可能なスキル、ツール、MCPサーバーがすべて自動的に機能します。
認証
すべてのリクエストにはスペース単位のAPIキーをBearerトークンとして送信する必要があります:
Authorization: Bearer thm_0c53ab18dad0f404...
APIキーの管理
- スペース設定 > API を開く
- Generate API Key をクリック
- キーをコピー(目のアイコンで表示、Copyボタンでクリップボードにコピー)
- Regenerate でローテーション、Revoke で無効化
APIキーは保存時に暗号化され、単一のスペースに紐づきます。
エンドポイント
メッセージ送信
POST /api/v1/conversations
Content-Type: application/json
Authorization: Bearer <api_key>
リクエストボディ:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
message | string | はい | メッセージテキスト |
conversation_id | integer | いいえ | 既存の会話を継続 |
callback | boolean | いいえ | 完了時にWebhookコールバックを有効化(スペース設定でWebhook URLの設定が必要) |
metadata | object | いいえ | 会話に保存される任意のメタデータ |
例 – 新規会話:
curl -X POST https://your-themis.example.com/api/v1/conversations \
-H "Authorization: Bearer thm_..." \
-H "Content-Type: application/json" \
-d '{"message": "渋谷区神宮前1-1-1の物件を評価してください"}'
例 – 会話の継続:
curl -X POST https://your-themis.example.com/api/v1/conversations \
-H "Authorization: Bearer thm_..." \
-H "Content-Type: application/json" \
-d '{"message": "収益予測はどうですか?", "conversation_id": 325}'
レスポンス (201 Created):
{
"id": 325,
"status": "processing",
"created_at": "2026-03-28T03:12:16Z",
"updated_at": "2026-03-28T03:12:16Z",
"messages": [
{
"id": 1851,
"role": "user",
"content": "渋谷区神宮前1-1-1の物件を評価してください",
"created_at": "2026-03-28T03:12:16Z"
},
{
"id": 1852,
"role": "assistant",
"content": null,
"created_at": "2026-03-28T03:12:16Z",
"processing": true
}
]
}
レスポンスのポーリング
GET /api/v1/conversations/:id
Authorization: Bearer <api_key>
statusが"processing"から"completed"に変わるまでポーリングしてください。
レスポンスフィールド:
| フィールド | 型 | 説明 |
|---|---|---|
id | integer | 会話ID |
status | string | "processing", "completed", "input_requested" |
messages | array | 時系列順のすべてのメッセージ |
messages[].content | string | メッセージテキスト(処理中はnull) |
messages[].images | array | 添付画像(ある場合) |
messages[].files | array | 添付ファイル(filename, content_type, byte_size, url) |
messages[].artifacts | array | 生成されたアーティファクト(HTMLウィジェット、チャート等) |
例:
curl https://your-themis.example.com/api/v1/conversations/325 \
-H "Authorization: Bearer thm_..."
ストリーミング付きメッセージ送信
会話を作成し、レスポンスをSSEストリームとして単一リクエストで受信します。スペース設定 > API > SSE Streaming でスペース単位で有効化が必要です。
POST /api/v1/conversations/stream
Content-Type: application/json
Authorization: Bearer <api_key>
リクエストボディは POST /api/v1/conversations と同じです。JSONの代わりに text/event-stream を返します。
例:
curl -N -X POST https://your-themis.example.com/api/v1/conversations/stream \
-H "Authorization: Bearer thm_..." \
-H "Content-Type: application/json" \
-d '{"message": "渋谷区神宮前1-1-1の物件を評価してください"}'
ストリームへの再接続
SSE接続が切断された場合、既存の会話のストリ��ムに再接続できます。last_event_id を渡すと中断した箇所から再開します。
GET /api/v1/conversations/:id/stream?last_event_id=42
Authorization: Bearer <api_key>
Accept: text/event-stream
イベント:
| イベント | 説明 | データ |
|---|---|---|
message_start | 処理開始 | conversation_id, message_id |
status | ステータス更新 | summary |
thinking | エージェントの思考 | summary |
tool_use | ツール呼び出し | tool(ツール名) |
tool_result | ツール結果 | tool_use_id, summary, is_error |
content_delta | テキストチャンク | delta(500msスロットル) |
ping | キープアライブ(15秒毎) | {} |
message_complete | レスポンス完了 | message_id, content |
error | 処理失敗 | message |
done | ストリーム終了 | {} |
サンプルストリーム:
event: message_start
data: {"conversation_id":325,"message_id":1852}
event: thinking
data: {"summary":"物件の立地を分析し、比較可能な物件を検索しています..."}
event: tool_use
data: {"tool":"mcp__metabase__execute_query"}
event: tool_result
data: {"summary":"渋谷区で12件の比較物件を発見","is_error":false}
event: content_delta
data: {"delta":"分析結果に基づくと、この物件は"}
event: ping
data: {}
event: message_complete
data: {"message_id":1852,"content":"分析結果に基づくと、この物件は82/100点..."}
event: done
data: {}
注意事項:
- ストリームのタイムアウトは3分間です。長時間のタスクには再接続してポーリングで最終結果を取得してください。
- 各ストリームはWebサーバースレッドを占有します。バッチ処理にはポーリングを使用してください。
- コンテンツデルタは500ms/20文字最小でスロットルされます。
Webhookコールバック
長時間のタスクには、POSTボディに "callback": true を渡してください。エージェントが完了(または失敗)すると、スペース設定 > API で設定されたWebhook URLに結果がPOSTされます。
設定: スペース設定 > API でWebhook URL(HTTPSのみ)を入力してください。
リクエスト:
curl -X POST https://your-themis.example.com/api/v1/conversations \
-H "Authorization: Bearer thm_..." \
-H "Content-Type: application/json" \
-d '{"message": "この物件を評価してください", "callback": true}'
コールバックペイロード(Webhook URLにPOST):
{
"id": 325,
"status": "completed",
"created_at": "2026-03-28T03:12:16Z",
"updated_at": "2026-03-28T03:15:42Z",
"messages": [
{ "id": 1851, "role": "user", "content": "この物件を評価してください" },
{ "id": 1852, "role": "assistant", "content": "分析結果に基づくと..." }
]
}
検証: 各コールバックには X-Themis-Signature ヘッダー(スペースAPIキーを秘密鍵としたHMAC-SHA256署名)が含まれます:
import hmac, hashlib
expected = hmac.new(api_key.encode(), body, hashlib.sha256).hexdigest()
assert signature == f"sha256={expected}"
注意事項:
- Webhook URLはHTTPS必須です。
- ネットワークエラー時は3回リトライ(30秒間隔)。
completedとfailedの両方のステータスでコールバックが発火します。- デフォルトは無効。リクエストに
"callback": trueがある場合のみ発火します。
エラーレスポンス
| ステータス | ボディ | 原因 |
|---|---|---|
| 400 | {"error": "param is missing..."} | 必須フィールドの欠落 |
| 401 | {"error": "Unauthorized"} | APIキーの欠落または無効 |
| 404 | {"error": "Not found"} | 会話が見つからない |
| 422 | {"error": "..."} | バリデーションエラー |
標準的な統合フロー
1. POST /api/v1/conversations { message: "..." }
→ 201 { id: 325, status: "processing" }
2. GET /api/v1/conversations/325 をポーリング
→ 200 { status: "processing", messages: [...] }
3. 再度ポーリング...
→ 200 { status: "completed", messages: [..., { role: "assistant", content: "..." }] }
4. (オプション) conversation_idで会話を継続
POST /api/v1/conversations { message: "続きの質問", conversation_id: 325 }
リアルタイムのフィードバックが必要な場合はストリーミングエンドポイントを使用:
1. POST /api/v1/conversations/stream { message: "..." }
→ text/event-stream でリアルタイムイベントを受信
長時間のタスク(物件評価など)にはWebhookコールバックを使用:
1. POST /api/v1/conversations { message: "...", callback: true }
→ 201 { id: 325, status: "processing" }
2. Webhook URLへのコールバックPOSTを待機
→ { id: 325, status: "completed", messages: [...] }