> ## Documentation Index
> Fetch the complete documentation index at: https://docs.utage-system.com/llms.txt
> Use this file to discover all available pages before exploring further.

# エラーハンドリング

> APIエラーの種類と対処方法

## エラーレスポンスの形式

APIエラー時は、以下の形式でエラー情報が返されます。

```json theme={null}
{
    "error": {
        "code": "error_code",
        "message": "エラーの詳細メッセージ"
    }
}
```

## HTTPステータスコード

### 400 Bad Request

リクエストの前提条件が満たされていない場合に返されます。フィールドの入力値そのものの不備（必須・型・桁数など）は400ではなく422になります。

| code                                   | 発生例                                                   |
| -------------------------------------- | ----------------------------------------------------- |
| `sms_not_configured` / `sms_no_credit` | SMS配信の設定が未完了、またはSMSクレジット残数が不足している状態でSMSメッセージを予約しようとした |
| `bad_request`                          | 作成後のページで `content_type` を変更しようとした                     |
| `invalid_filetype`                     | メディアアップロードで許可されないファイルタイプを指定した                         |
| `not_uploaded`                         | アップロード完了APIを呼んだがファイルが実際にアップロードされていない                  |
| `folder_not_found`                     | メディアアップロードで存在しないフォルダを指定した                             |

```json theme={null}
{
    "error": {
        "code": "bad_request",
        "message": "content_typeは作成後に変更できません"
    }
}
```

**対処方法:** `error.message` を確認し、設定状態や指定値を修正してから再実行してください。

### 401 Unauthorized

認証に失敗しました。レスポンスの `error.code` は常に `unauthorized` で、失敗の原因は `message` で示されます。

| 原因             | message           |
| -------------- | ----------------- |
| APIキーが未指定      | `APIキーが指定されていません` |
| APIキーが無効       | `APIキーが無効です`      |
| APIキーが無効化されている | `APIキーが無効化されています` |

```json theme={null}
{
    "error": {
        "code": "unauthorized",
        "message": "APIキーが無効です"
    }
}
```

**対処方法:** `Authorization: Bearer {api_key}` ヘッダーが正しく付与されているか、管理画面でAPIキーが有効か確認してください。無効化されている場合は再発行してください。

### 403 Forbidden

リソースへのアクセス権限がありません。

```json theme={null}
{
    "error": {
        "code": "forbidden",
        "message": "You do not have permission to access this resource."
    }
}
```

**対処方法:** ライセンス制のファネルなど、APIからの操作が制限されているリソースの場合に発生します。対象リソースの権限を確認してください。

### 404 Not Found

指定されたリソースが見つかりません。

```json theme={null}
{
    "error": {
        "code": "not_found",
        "message": "Resource not found."
    }
}
```

**対処方法:** URLに含まれるID（funnel\_id, step\_id, page\_id等）が正しいか確認してください。

### 422 Unprocessable Entity

リクエストパラメータのバリデーションに失敗しました。必須項目の未指定、型の誤り、桁数超過などフィールド単位の入力不備で発生します。`error.code` は `validation_error` で、`error.details` に項目ごとのエラー内容が含まれます。

```json theme={null}
{
    "error": {
        "code": "validation_error",
        "message": "入力内容に誤りがあります",
        "details": {
            "name": [
                "管理用タイトルは必須です"
            ]
        }
    }
}
```

**対処方法:** `error.details` の各項目を確認し、該当するリクエストパラメータを修正してください。

### 429 Too Many Requests

レート制限を超過しました。

```json theme={null}
{
    "error": {
        "code": "rate_limit_exceeded",
        "message": "レート制限を超過しました"
    }
}
```

**対処方法:** レスポンスヘッダーの `X-RateLimit-Reset` でリセット時刻を確認し、その時刻まで待ってからリトライしてください。

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700000000
```

<Tip>
  レート制限の詳細は[認証](/authentication#レート制限)を参照してください。
</Tip>

### 500 Internal Server Error

サーバー内部でエラーが発生しました。

```json theme={null}
{
    "error": {
        "code": "internal_error",
        "message": "An internal error occurred."
    }
}
```

**対処方法:** 時間をおいてリトライしてください。繰り返し発生する場合はサポートにお問い合わせください。

## バリデーションエラーの詳細

### 要素構造エラー

elements方式のページでは、要素の階層ルールに違反するとバリデーションエラーになります。

| ルール                         | 説明                                           |
| --------------------------- | -------------------------------------------- |
| `elements` 直下は `section` のみ | elements配列のルートにはsection要素だけを配置可能             |
| `section` の子は `row` のみ      | sectionのchildrenにはrow要素だけを配置可能               |
| `row` の子は `col` のみ          | rowのchildrenにはcol要素だけを配置可能                   |
| `col` の子はコンテンツ要素            | colのchildrenにtext, image, button等のコンテンツ要素を配置 |

```json 正しい構造 theme={null}
{
    "elements": [
        {
            "type": "section",
            "children": [
                {
                    "type": "row",
                    "children": [
                        {
                            "type": "col",
                            "children": [
                                {"type": "text", "content": "<p>テキスト</p>"}
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}
```

```json 誤った構造（エラーになる） theme={null}
{
    "elements": [
        {
            "type": "text",
            "content": "<p>テキスト</p>"
        }
    ]
}
```

<Warning>
  上記の誤った例では、elements直下にtext要素を直接配置しているためエラーになります。必ず `section > row > col` の階層を経由してください。
</Warning>

### content\_type変更不可

ページ作成後に `content_type` を変更することはできません。`elements` で作成したページを `raw_html` に変更（またはその逆）しようとすると400エラーになります。

```json theme={null}
{
    "error": {
        "code": "bad_request",
        "message": "content_typeは作成後に変更できません"
    }
}
```

異なるcontent\_typeのページが必要な場合は、新しいページを作成してください。

### ページ更新は部分更新

ページ更新APIは部分更新です。変更したいフィールドだけを送信すれば、未指定のフィールドは既存の値が維持されます（nullに上書きされることはありません）。

<Note>
  `elements` / `popup_elements` は配列を指定した場合のみ、その内容で全置換されます（指定しない場合は既存の要素が維持されます）。
</Note>

```bash theme={null}
# 変更したいフィールドだけを送信（例: タイトルのみ変更）
curl -X PATCH "https://api.utage-system.com/v1/funnels/{funnel_id}/steps/{step_id}/pages/{page_id}" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "更新後のタイトル"
  }'
```

## リトライ戦略

APIエラー時の推奨リトライ戦略です。

### 429 Too Many Requests

`X-RateLimit-Reset` ヘッダーのUNIXタイムスタンプまで待ってからリトライします。

```
待機時間 = X-RateLimit-Reset - 現在時刻（秒）
```

### 5xx サーバーエラー

指数バックオフでリトライします。

| リトライ回数 | 待機時間 |
| ------ | ---- |
| 1回目    | 1秒   |
| 2回目    | 2秒   |
| 3回目    | 4秒   |
| 4回目    | 8秒   |
| 5回目    | 16秒  |

最大5回程度のリトライを推奨します。それでも解決しない場合はサポートにお問い合わせください。

### リトライ不要なエラー

以下のエラーはリクエスト内容の修正が必要であり、同じリクエストをリトライしても解決しません。

* **400** - リクエストパラメータを修正
* **401** - APIキーを確認・再設定
* **403** - リソースの権限を確認
* **404** - リソースIDを確認

<Note>
  エラー発生時の調査には、レスポンスボディの `error.code` と `error.message` をログに記録しておくことを推奨します。
</Note>
