> For the complete documentation index, see [llms.txt](https://docs.maiagent.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.maiagent.ai/tech/ja/api-integration/api-tool-engineering-guide.md).

# API ツールエンジニアリングガイド

REST API を MaiAgent AI アシスタントのツールとして接続する方法：リクエストの組み立て方、認証の渡し方、タイムアウトとリトライ、モデルへのエラーの返し方、ログの確認方法。

本ページは「AI アシスタントに自社システムを逆呼び出しさせたい」エンジニア向けです。MaiAgent 側が AI アシスタントの決定したパラメータをどのように HTTP リクエストへ組み立てるか、あなたの API がどのような形であればモデルに使いやすいか、失敗時にモデルには何が見えるかを解説します。

管理画面での具体的な操作手順（どの画面でツールを新規作成し、各項目に何を入力するか）については、ユーザーマニュアルの[API ツールの作成](https://docs.maiagent.ai/tools/setup)をご参照ください。本ページでは操作手順は繰り返しません。ツールは REST API でも作成・管理でき、項目は本ページと同じです。詳しくは API ドキュメントの「ツールとコネクタ」をご参照ください。

## 1回の呼び出しのフロー <a href="#call-flow" id="call-flow"></a>

```mermaid
sequenceDiagram
    participant U as ユーザー
    participant A as MaiAgent AI アシスタント
    participant P as MaiAgent プラットフォーム
    participant S as あなたの API

    U->>A: 「注文 A123 のステータスを確認して」
    A->>A: ツールの説明とパラメータ構造に基づき、呼び出すツールと入力するパラメータを決定
    A->>P: tool call（ツール名＋JSON パラメータ）
    P->>P: パラメータのデフォルト値を適用し、ヘッダーと Query パラメータの {{変数}} をレンダリング
    P->>S: HTTP リクエスト（GET は query string 付き／POST は JSON body 付き）
    S-->>P: レスポンス（任意のテキスト、JSON 推奨）
    P->>P: 機密値をマスキングし、context window に応じて切り詰め、ツール実行ログに記録
    P-->>A: レスポンスの原文（またはエラーメッセージ）
    A-->>U: 自然言語で結果を整理して回答
```

AI アシスタントは「呼び出しとパラメータの決定」のみを担当し、実際の HTTP リクエストはプラットフォームが送信します。あなたの API はモデルに関することを何も知る必要はなく、パブリックネットワークからアクセス可能な HTTP エンドポイントであればよいのです。

## ツール定義の対応 <a href="#tool-definition" id="tool-definition"></a>

1つの API ツールは**1つのエンドポイント＋1つの HTTP メソッド**に対応します。プラットフォームは現在 OpenAPI ドキュメントのインポートに対応していません。あなたの API に OpenAPI 仕様がある場合は、アシスタントに公開したい operation ごとに1つのツールを作成し、requestBody または query の schema を「パラメータ構造」に貼り付ければ対応できます。

| フィールド（管理画面名／API フィールド）             | 対象       | 説明                                                                                                                                                                                                  |
| ---------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ツール名 `name`                        | モデル      | モデルが呼び出す際に使う識別子です。英字、数字、アンダースコア、ハイフンのみ使用可能です。モデルに送る前に `^[a-zA-Z][a-zA-Z0-9_]*$` に正規化され、最大 64 文字、ハイフンはアンダースコアに変換され、超過分は切り詰められてハッシュのサフィックスが付加されます。最初から `snake_case` を使うことを推奨します。例：`get_order_status`。 |
| 表示名 `displayName`                  | 人        | 管理画面の一覧やツール実行ログの表示に使用します。形式の制限はありません。                                                                                                                                                               |
| ツール説明 `description`、プロンプト `prompt` | モデル      | モデルが「いつこのツールを使うべきか」を判断する唯一の根拠です。`prompt` に値がある場合は `prompt` が使われ、なければ `description` が使われます。何をするか、どのような場合に使うか、何を返すかを明確に記述してください。                                                                      |
| API URL `apiUrl`                   | プラットフォーム | `https://` を含む完全な URL です。パスは固定で、パラメータに応じて変化する値は query string または body に置きます。                                                                                                                        |
| HTTP メソッド `httpMethod`             | プラットフォーム | `get`、`post`、`put`、`patch`、`delete`。モデルのパラメータが query string になるか JSON body になるかを決定します。次節を参照してください。                                                                                                  |
| ヘッダー `rawHeaders`                  | プラットフォーム | JSON オブジェクトで、毎回のリクエストに付与されます。値には `{{変数}}` が使用できます。                                                                                                                                                  |
| Query パラメータ `rawQueryParams`       | プラットフォーム | JSON オブジェクトで、毎回のリクエストで query string に付与されます。値には `{{変数}}` が使用できます。モデルのパラメータと同名の場合は**こちらの値が優先されます**。                                                                                                  |
| パラメータ構造 `rawParametersSchema`      | モデル      | JSON Schema で、モデルが提供できる（または必須の）パラメータを宣言します。                                                                                                                                                         |

## パラメータ構造（JSON Schema） <a href="#parameters-schema" id="parameters-schema"></a>

プラットフォームはパラメータ構造をモデルの function-calling schema に変換し、モデルが返したパラメータはこれに基づいて検証されます。

```json
{
  "type": "object",
  "properties": {
    "order_id": {
      "type": "string",
      "description": "注文番号。形式例：A123456"
    },
    "include_items": {
      "type": "boolean",
      "description": "商品明細も一緒に返すかどうか",
      "default": false
    },
    "status": {
      "type": "string",
      "enum": ["pending", "shipped", "delivered"],
      "description": "特定のステータスのみ検索する場合に指定"
    }
  },
  "required": ["order_id"]
}
```

規則と制限：

* トップレベルは `type: "object"` である必要があります。`properties`、`required`、`default`、`enum`、ネストされた `object` と `array` に対応しています。
* パラメータ名は英字、数字、アンダースコア、ピリオド、ハイフン、中国語のみ使用可能で、長さは 1〜64 文字です。これに合わない名前は保存時に拒否されます。
* **`default` はプラットフォームが補完します**：モデルがそのパラメータを提供しなかった場合、プラットフォームが `default` の値を入れて送信します。ある値を固定で渡したいが、モデルに決めさせたくない場合は、`default` を使うか、直接 Query パラメータに記述してください。
* すべてのパラメータに `description` を記述してください。モデルがパラメータを入力する品質はほぼこの文章次第です。型だけを書くより、形式の例（「形式例：A123456」）を書くほうがはるかに効果的です。
* パラメータ名 `timeout` は予約された意味を持ちます。モデルがこれを指定した場合、プラットフォームはそれを今回のリクエストのタイムアウト秒数として使用し、あなたの API には**送信しません**。この名前をビジネスパラメータとして使わないでください。

{% hint style="warning" %}
API キーをパラメータとして宣言し `default` で渡すことはしないでください。モデルはパラメータ構造を見ることができるため、キーがモデルのコンテキストに入ってしまいます。キーはヘッダーまたは Query パラメータに置いてください。詳しくは次節を参照してください。
{% endhint %}

## リクエストの組み立て方 <a href="#request-assembly" id="request-assembly"></a>

プラットフォームは HTTP メソッドに応じてモデルパラメータの配置先を決定します：

| メソッド                 | モデルパラメータの配置先                                | 「Query パラメータ」欄                              | Body                  |
| -------------------- | ------------------------------------------- | ------------------------------------------- | --------------------- |
| `GET`                | query string                                | query string にまとめて付与、**同名の場合はモデルパラメータを上書き** | なし                    |
| `POST`、`PUT`、`PATCH` | JSON body（`Content-Type: application/json`） | query string                                | モデルパラメータの JSON オブジェクト |
| `DELETE`             | 送信しない                                       | query string                                | なし                    |

要点：

* `DELETE` はモデルパラメータを送信しません。削除対象を指定する必要がある場合は、`POST` を使うか、対象を Query パラメータの `{{変数}}` に入れてください。
* Body は常に JSON オブジェクトです。form-data、ファイルアップロード、XML には対応していません。これらの形式が必要な API は、あなたの側で JSON インターフェースをラップしてください。
* モデルパラメータと「Query パラメータ」が同名の場合は設定値が優先されます。これは意図的な設計です。query string で渡す必要があるキーを Query パラメータに置くことで、モデルがそれを上書きできないようにしています。

### ヘッダーと Query パラメータ内の `{{変数}}` <a href="#template-variables" id="template-variables"></a>

ヘッダーと Query パラメータの値は2種類の変数を参照でき、プラットフォームが呼び出しごとに代入します：

| 変数                    | 内容                                                          |
| --------------------- | ----------------------------------------------------------- |
| `{{contact_id}}`      | 現在の会話のコンタクト ID（MaiAgent 内部 ID）                              |
| `{{source_id}}`       | コンタクトの外部 ID。つまり Web Chat の埋め込みやコンタクト同期の際に指定した `sourceId` です |
| `{{contact_name}}`    | コンタクト名                                                      |
| `{{conversation_id}}` | 会話 ID                                                       |
| `{{inbox_id}}`        | 受信ボックス ID                                                   |
| `{{organization_id}}` | 組織 ID                                                       |
| `{{パラメータ名}}`          | パラメータ構造内の同名パラメータの値（モデルが入力）                                  |

`{{source_id}}` は ISV が最もよく使う変数です。あなたのシステムは自身のユーザー ID しか認識しないため、これをヘッダー（例：`X-User-Id: {{source_id}}`）または query string に入れることで、あなたの API はそのユーザーの身元でデータを検索できます。パラメータ構造の中でモデルに「ユーザーが誰かを推測させる」必要はありません。

代入は文字列としてそのまま行われ、型変換は行われません。モデルが参照先のパラメータを提供しなかった場合、その呼び出しはエラーで中止され、`{{パラメータ名}}` がそのまま送信されることはありません。変数は会話コンテキストがある場合のみ利用可能で、管理画面の「ツールテスト」のような会話のない呼び出しではコンテキスト変数をレンダリングできません。

## 認証方式 <a href="#authentication" id="authentication"></a>

3つの方式は併用可能で、優先順位は低いものから高いものへ並んでいます：

1. **ツール層の固定クレデンシャル**：`Authorization: Bearer ...` や `X-API-Key: ...` をヘッダーに記述するか、キーを Query パラメータに記述します。「組織全体」としてあなたの API を呼び出すことを表します。保存後は管理画面上で `****` にマスキング表示され、ツール実行ログと API リクエストログの Query パラメータ値もマスキングされます。
2. **コンテキスト変数**：前節のとおり、`{{source_id}}` などを使って「誰が質問しているか」をあなたの API に伝え、認可はあなたの側で行います。クレデンシャル自体はツール層のものです。
3. **コンタクト層クレデンシャル（API Credential）**：特定のコンタクトに1組のヘッダーを紐付け、呼び出し時に**同名のツール層ヘッダーを上書き**します。エンドユーザーごとに個別の token を持つシナリオ（統合アカウントではなく、ユーザー本人の身元で呼び出す必要がある場合）に適しています。

コンタクト層クレデンシャルは、あなたのバックエンドがユーザーのログイン後に書き込みます：

```http
POST /api/contacts/{contact_id}/api-credentials/
Authorization: Api-Key <組織の API キー>
Content-Type: application/json

{
  "tool": "<ツール ID>",
  "headers": {
    "Authorization": "Bearer <このユーザーのあなたのシステムでの token>"
  }
}
```

同じコンタクトが同じツールに対して再送すると、既存のクレデンシャルが更新されます。token が期限切れになった場合は、再度呼び出すだけで済みます。クレデンシャルは「そのコンタクトの会話」内でのみ有効で、他のコンタクトが同じツールを呼び出す場合は依然としてツール層のクレデンシャルが使われます。

{% hint style="info" %}
token をコンタクトクレデンシャルに書き込むタイミングは、通常 Web Chat 埋め込み時の身元同期フローです。詳しくは[コンタクト身元同期と Token 更新](/tech/ja/authorization-integration/contact-credentials-sync.md)をご参照ください。
{% endhint %}

## タイムアウト、リトライと TLS <a href="#timeout-retry-tls" id="timeout-retry-tls"></a>

| 項目     | 動作                                                                                                                                                                   |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| タイムアウト | 各 HTTP リクエストのタイムアウト設定はデフォルト 30 秒です（プラットフォーム層の設定で、オンプレミス環境では調整可能）。これはツール呼び出し全体の合計時間ではありません。タイムアウトした呼び出しは `timeout` として記録され、モデルには「API リクエストがタイムアウトしました」と通知されます。        |
| リトライ   | 最初のリクエストに加えて最大 3 回までリトライし、合計最大 4 回の試行を行います。バックオフ待機時間は 1、2、4 秒です。タイムアウトを含むリクエストエラーおよび `408`、`409`、`429`、`500`、`502`、`503`、`504` に対してリトライします。その他の 4xx はリトライしません。       |
| TLS    | 証明書チェーンとホスト名は常に検証されます。証明書チェーンに Subject Key Identifier を持たない旧式のルート証明書（一部のローカル CA）を使用している場合は、ツール設定で「Relax RFC 5280 strict」を有効にすることで、その項目のみ検証を緩和できます。自己署名証明書には対応していません。 |

あなたの API にとっての意味：

* 書き込み系エンドポイントは**冪等**にしてください。リトライによって同じ `POST` が2回送信されることがあります。パラメータ内のビジネスキー（注文番号、外部 ID）で重複を除去するか、`409` を返して同じレコードに対するリトライだと分かるようにしてください。
* ツール呼び出し全体では、各リクエストとバックオフの待機時間が積み重なります。連続してタイムアウトすると 120 秒を超える可能性があり、30 秒をモデルが待つ合計の上限と考えることはできません。検索系エンドポイントは数秒以内に収めてください。時間のかかる処理は「タスクを作成してタスク ID を返す」方式にし、別途照会用のツールを用意してください。
* `429` に対して `Retry-After` を返しても効果はありません。プラットフォームは固定のバックオフを使用します。レート制限は3回のリトライ分を想定して見積もってください。

## レスポンスをモデルにどう返すか <a href="#response-to-model" id="response-to-model"></a>

モデルが見るのはあなたの**レスポンス body の原文**であり、構造の解析は行いません：

| 状況               | モデルに見えるもの                                                  |
| ---------------- | ---------------------------------------------------------- |
| 2xx              | body の原文（`response.text`）。空の body は文字列 `None` になります。       |
| 2xx 以外（リトライ後も失敗） | `API リクエストが失敗しました` で始まり、続けて `HTTP <ステータスコード>: <body の原文>`。 |
| タイムアウト           | `API リクエストがタイムアウトしました` で始まり、続けてエラーの説明。                     |
| 接続エラー、DNS、TLS 失敗 | `API リクエストが失敗しました` で始まり、続けて例外メッセージ。                        |
| 組織の Credits 不足   | 呼び出しは送信されず、モデルにはクレジット不足の説明が返されます。                          |

レスポンスがモデルの context window の一定割合（デフォルト 80%）を超える場合、プラットフォームは先頭と末尾の2つの部分を保持し、先頭に「切り詰め済み」のヒントを追加します。切り詰められるのは中間部分です。

そのため、あなたの API 設計には以下を推奨します：

* **簡潔な JSON を返してください**。モデルが必要とするフィールドのみを返し、ORM オブジェクトをそのまま返すことは避けてください。一覧は一度に数十件以内に収め、それ以上はページネーションパラメータを提供してモデルが再度検索できるようにしてください。
* **エラーは読みやすいメッセージで**返し、エラーコードだけを返さないようにしてください。`{"error": "注文番号 A123 が存在しません。番号をご確認ください"}` のようなメッセージは、`{"code": 40401}` よりもモデルがパラメータを修正したりユーザーに説明したりするのに役立ちます。
* **4xx はモデルへのフィードバックです**：パラメータの不足や形式エラーの場合は `400` を返し、どのフィールドが問題かを説明してください。モデルはパラメータを再入力して再度呼び出す機会を得られます。エラーを `200` で包まないでください。モデルはそれを成功結果として扱い、ユーザーに整理して伝えてしまいます。
* レスポンスに query string がそのまま反映される場合（一部のフレームワークのエラーページはこれを行います）、プラットフォームはツール設定の Query パラメータ値をマスキングしてからモデルに渡しますが、ヘッダーが body に反映されないのは、あなたの API 自身がそれを出力しない場合に限られます。
* モデルがユーザーに「データが見つかりません」と伝えられるようにするには、`200` の空配列ではなく、明確に `404` と説明を返してください。

## ログとデバッグ <a href="#records-and-debugging" id="records-and-debugging"></a>

呼び出しごとに1件の**ツール実行ログ**が記録されます。管理画面では「AgentOps → ツール実行ログ」にあり、API で照会することもできます：

```http
GET /api/tool-execution-records/?tool=<ツール ID>&status=failure&start_date=2026-09-01&end_date=2026-09-11
Authorization: Api-Key <組織の API キー>
X-Organization-Id: <組織 ID>
```

使用可能なフィルター：`tool`、`tool_type=api`、`status`（`success`、`failure`、`pending`、`timeout`）、`chatbot`、`start_date`、`end_date`、`query`（全文検索）。各レコードには以下が含まれます：

* モデルが入力したパラメータ `inputParameters`、およびプラットフォームが実際に送信した `requestMethod`、`requestHeaders`（機密値はマスキング）、`requestBody`。
* レスポンスの原文 `outputResult`（切り詰め後のバージョン）または `errorMessage`。
* 実行時間とステータス、関連するメッセージと AI アシスタント。

この API を読み取るには、メンバーが AgentOps の「ツール実行ログ」権限を持っている必要があります。組織の owner はこの制限を受けません。

デバッグの手順の推奨：

1. ログ内の `requestHeaders`／`requestBody` が想定した形になっているか確認します。`{{変数}}` が代入されていない場合は、通常は変数名のスペルミス、またはパラメータ構造に同名のパラメータがないことが原因です。
2. `errorMessage` が `HTTP <コード>` で始まっている場合は、あなたの API が返したエラーであり、body の原文がその後に続きます。
3. `status=timeout` なのにあなたのログでは応答済みと表示されている場合、応答時間が 30 秒を超えていたことを意味します。まずあなたの側の p95 を確認してください。
4. モデルが「ツールを呼び出さなかった」場合はログが生成されません。この場合に修正すべきはツールの説明とパラメータの `description` であり、API ではありません。

## 課金 <a href="#billing" id="billing"></a>

送信に成功した API ツールの呼び出しごとに、「API ツール呼び出し」の Credits が1回消費されます。クレジットが不足している場合、呼び出しは送信されません。呼び出しの失敗やタイムアウトによるリトライは追加で計算されません。詳細な単価は組織のプランによって異なります。ユーザーマニュアルの Credits の説明をご参照ください。

## 公開前チェックリスト <a href="#checklist" id="checklist"></a>

* [ ] エンドポイントがパブリックネットワークから HTTPS でアクセス可能で、証明書チェーンが完全であること。
* [ ] 検索系エンドポイントの p95 が数秒以内であること。書き込み系エンドポイントが冪等であること。
* [ ] パラメータ構造の各パラメータに `description` と形式の例があること。`required` には本当に必須のものだけを列挙していること。
* [ ] キーがヘッダーまたは Query パラメータに置かれており、パラメータ構造の中にないこと。
* [ ] 「ユーザーの身元」で呼び出す必要がある場合、`{{source_id}}` を使うかコンタクト層クレデンシャルを使うかを決定し、あなたのバックエンドで認可を完成させていること。
* [ ] エラーレスポンスが読みやすいメッセージであり、`4xx` で何が不足しているかを説明し、`200` でエラーを包んでいないこと。
* [ ] レスポンスが簡潔であり、一覧にページネーションがあること。
* [ ] 実際の会話で一度通しで実行し、ツール実行ログで送信されたリクエストとレスポンスが期待通りであることを確認していること。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.maiagent.ai/tech/ja/api-integration/api-tool-engineering-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
