Chat API

ThemisはREST APIを提供しており、外部アプリケーションからメッセージを送信してAIレスポンスを受け取ることができます。APIはWeb・メッセージングチャネルと同じエージェントパイプラインを使用するため、スペースで利用可能なスキル、ツール、MCPサーバーがすべて自動的に機能します。

認証

すべてのリクエストにはスペース単位のAPIキーをBearerトークンとして送信する必要があります:

Authorization: Bearer thm_0c53ab18dad0f404...

APIキーの管理

  1. スペース設定 > API を開く
  2. Generate API Key をクリック
  3. キーをコピー(目のアイコンで表示、Copyボタンでクリップボードにコピー)
  4. Regenerate でローテーション、Revoke で無効化

APIキーは保存時に暗号化され、単一のスペースに紐づきます。

エンドポイント

メッセージ送信

POST /api/v1/conversations
Content-Type: application/json
Authorization: Bearer <api_key>

リクエストボディ:

フィールド必須説明
messagestringはいメッセージテキスト
conversation_idintegerいいえ既存の会話を継続
callbackbooleanいいえ完了時にWebhookコールバックを有効化(スペース設定でWebhook URLの設定が必要)
metadataobjectいいえ会話に保存される任意のメタデータ

例 – 新規会話:

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"に変わるまでポーリングしてください。

レスポンスフィールド:

フィールド説明
idinteger会話ID
statusstring"processing", "completed", "input_requested"
messagesarray時系列順のすべてのメッセージ
messages[].contentstringメッセージテキスト(処理中はnull
messages[].imagesarray添付画像(ある場合)
messages[].filesarray添付ファイル(filename, content_type, byte_size, url
messages[].artifactsarray生成されたアーティファクト(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秒間隔)。
  • completedfailed の両方のステータスでコールバックが発火します。
  • デフォルトは無効。リクエストに "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: [...] }