{
  "openapi": "3.1.0",
  "info": {
    "title": "もじケア API",
    "summary": "日本語テキストの NG ワード判定 API",
    "description": "日本語テキストを判定し、マスク済みテキストと検出結果を返す API です。\n\n- **認証**: `Authorization: Bearer mc_live_xxxxx` (Enterprise のテストキーは `mc_test_xxxxx`)。キーはダッシュボードで発行します。\n- **サーバーサイド専用**: CORS は許可していません。API キーをブラウザや公開リポジトリに置かないでください。\n- **リクエスト**: `Content-Type: application/json`。ボディは 64KB (65536 バイト) まで、`text` は 5000 文字までです。\n- **エラーの言語**: `Accept-Language` に `ja` を含めると日本語、それ以外は英語になります。\n- **本文は保存しません**: 送信されたテキストは判定に使うだけで、こちら側には保存しません。ただし応答には入力の一部または全体が判定結果として含まれます (`masked` / `matches`、および連結すると原文に戻る `segments`)。応答をログや外部サービスに流す際は、その前提でお取り扱いください。",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.moji-care.com",
      "description": "本番環境"
    }
  ],
  "tags": [
    {
      "name": "Moderation",
      "description": "テキストの判定"
    },
    {
      "name": "Health",
      "description": "死活確認"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/moderations": {
      "post": {
        "operationId": "createModeration",
        "tags": [
          "Moderation"
        ],
        "summary": "テキストを判定する",
        "description": "テキストを判定し、マスク済みテキスト・検出された NG 語・判定単位の分割結果を返します。\n\n判定に成功した呼び出しだけが使用量としてカウントされます (エラー応答はカウントしません)。Enterprise のテストキー (`mc_test_xxxxx`) での呼び出しはカウント対象外です。\n応答の `id` は問い合わせ時の突合に使えるリクエスト識別子で、`X-Request-Id` ヘッダと同じ値です。",
        "parameters": [
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "description": "エラーメッセージの言語。値に `ja` を含めると日本語、それ以外 (ヘッダ自体が無い場合を含む) は英語になります。判定結果そのものはこの値に影響されません。",
            "schema": {
              "type": "string",
              "examples": [
                "ja",
                "en"
              ]
            }
          }
        ],
        "requestBody": {
          "description": "判定対象のテキストとマスクの指定 (JSON・64KB まで)。",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModerationRequest"
              },
              "examples": {
                "default": {
                  "summary": "テキストを判定する",
                  "value": {
                    "text": "これはうんこです",
                    "options": {
                      "mask_char": "*",
                      "mask_mode": "repeat"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "判定結果",
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModerationResponse"
                },
                "examples": {
                  "default": {
                    "summary": "判定結果",
                    "value": {
                      "id": "mod_9f8a7b6c5d4e",
                      "flagged": true,
                      "masked": "これは***です",
                      "matches": [
                        "うんこ"
                      ],
                      "segments": [
                        {
                          "text": "これは",
                          "clean": true,
                          "start": 0,
                          "end": 3
                        },
                        {
                          "text": "うんこ",
                          "clean": false,
                          "start": 3,
                          "end": 6
                        },
                        {
                          "text": "です",
                          "clean": true,
                          "start": 6,
                          "end": 8
                        }
                      ],
                      "usage": {
                        "chars": 8
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `invalid_request` — `text` の欠落・型の誤り、`options` の未知キーや不正な `mask_mode`、または不正な Unicode を含む `text`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "invalid_request": {
                    "summary": "`text` の欠落・型の誤り、`options` の未知キーや不正な `mask_mode`、または不正な Unicode を含む `text`",
                    "value": {
                      "error": {
                        "code": "invalid_request",
                        "message": "リクエストの形式が正しくありません: {detail}"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "401": {
            "description": "- `missing_api_key` — `Authorization` ヘッダが無い、または `Bearer <APIキー>` の形式になっていない\n- `invalid_api_key` — API キーが存在しない、または失効している",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "missing_api_key": {
                    "summary": "`Authorization` ヘッダが無い、または `Bearer <APIキー>` の形式になっていない",
                    "value": {
                      "error": {
                        "code": "missing_api_key",
                        "message": "Authorization ヘッダが必要です (Bearer <APIキー>)"
                      }
                    }
                  },
                  "invalid_api_key": {
                    "summary": "API キーが存在しない、または失効している",
                    "value": {
                      "error": {
                        "code": "invalid_api_key",
                        "message": "APIキーが無効です"
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "- `payment_required` — アカウントにお支払い方法が登録されていない",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "payment_required": {
                    "summary": "アカウントにお支払い方法が登録されていない",
                    "value": {
                      "error": {
                        "code": "payment_required",
                        "message": "お支払い方法が登録されていません。ダッシュボードから登録してください"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "- `account_suspended` — 決済失敗の猶予期間を過ぎた、運営が停止した、または退会済みのアカウント",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "account_suspended": {
                    "summary": "決済失敗の猶予期間を過ぎた、運営が停止した、または退会済みのアカウント",
                    "value": {
                      "error": {
                        "code": "account_suspended",
                        "message": "アカウントが停止されています。ダッシュボードをご確認ください"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              }
            }
          },
          "413": {
            "description": "- `text_too_long` — `text` が 5000 文字 (Unicode コードポイント数) を超えている\n- `body_too_large` — リクエストボディが 65536 バイトを超えている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "text_too_long": {
                    "summary": "`text` が 5000 文字 (Unicode コードポイント数) を超えている",
                    "value": {
                      "error": {
                        "code": "text_too_long",
                        "message": "text が長すぎます ({actual} 文字 / 上限 {limit} 文字)"
                      }
                    }
                  },
                  "body_too_large": {
                    "summary": "リクエストボディが 65536 バイトを超えている",
                    "value": {
                      "error": {
                        "code": "body_too_large",
                        "message": "リクエストボディが大きすぎます (上限 {limit} bytes)"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "429": {
            "description": "- `rate_limit_exceeded` — プランの 1 秒あたりリクエスト数を超えた\n- `monthly_quota_exceeded` — 今サイクルの込みリクエスト数を使い切り、従量課金が無効になっている\n- `spend_cap_reached` — 超過課金が設定した月あたりの上限額に達した",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "rate_limit_exceeded": {
                    "summary": "プランの 1 秒あたりリクエスト数を超えた",
                    "value": {
                      "error": {
                        "code": "rate_limit_exceeded",
                        "message": "リクエストが多すぎます。1秒あたり {limit} リクエストまでです"
                      }
                    }
                  },
                  "monthly_quota_exceeded": {
                    "summary": "今サイクルの込みリクエスト数を使い切り、従量課金が無効になっている",
                    "value": {
                      "error": {
                        "code": "monthly_quota_exceeded",
                        "message": "今月の込みリクエスト数を使い切りました。従量課金を有効にするかプランをアップグレードしてください"
                      }
                    }
                  },
                  "spend_cap_reached": {
                    "summary": "超過課金が設定した月あたりの上限額に達した",
                    "value": {
                      "error": {
                        "code": "spend_cap_reached",
                        "message": "設定された月の超過課金上限額に達しました"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "description": "再試行までの待ち時間 (秒)。すべての 429 応答に付きます。`rate_limit_exceeded` は次の秒まで、クォータ系は次の請求サイクル開始までの秒数です。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "500": {
            "description": "- `internal_error` — ゲートウェイ内部のエラー",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "internal_error": {
                    "summary": "ゲートウェイ内部のエラー",
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "サーバー内部でエラーが発生しました"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "502": {
            "description": "- `upstream_error` — 判定エンジンが 5 秒以内に応答しない、またはエラーを返した",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "upstream_error": {
                    "summary": "判定エンジンが 5 秒以内に応答しない、またはエラーを返した",
                    "value": {
                      "error": {
                        "code": "upstream_error",
                        "message": "判定エンジンが一時的に応答していません。しばらくしてから再試行してください"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "required": true,
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "required": true,
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "- `service_unavailable` — 内部依存が一時的に応答しない (再試行で回復しうる)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "examples": {
                  "service_unavailable": {
                    "summary": "内部依存が一時的に応答しない (再試行で回復しうる)",
                    "value": {
                      "error": {
                        "code": "service_unavailable",
                        "message": "サーバーが一時的に混み合っています。しばらくしてから再試行してください"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "description": "応答本文の `id` と同じリクエスト識別子。API キーの検証に成功した以降の応答 (エラーを含む) に付きます。認証より手前で弾かれた応答には付きません。",
                "schema": {
                  "type": "string",
                  "pattern": "^mod_[0-9A-Za-z]{12}$",
                  "examples": [
                    "mod_9f8a7b6c5d4e"
                  ]
                }
              },
              "X-RateLimit-Limit": {
                "description": "プランの 1 秒あたりリクエスト数の上限 (Enterprise のテストキーは 1)。レート制限を評価した以降の応答にのみ付きます (プランが判明する前の応答には付きません)。",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "X-RateLimit-Remaining": {
                "description": "当該秒バケットの残りリクエスト数 (負にはなりません)。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "次の秒バケットが始まる epoch 秒。付与条件は `X-RateLimit-Limit` と同じです。",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "Health"
        ],
        "summary": "死活確認",
        "description": "認証不要。`{\"status\":\"ok\"}` だけを返します。内部情報は含まず、レート制限ヘッダも付きません。",
        "security": [],
        "parameters": [
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "description": "エラーメッセージの言語。値に `ja` を含めると日本語、それ以外 (ヘッダ自体が無い場合を含む) は英語になります。判定結果そのものはこの値に影響されません。",
            "schema": {
              "type": "string",
              "examples": [
                "ja",
                "en"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ゲートウェイは応答可能",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "examples": {
                  "default": {
                    "summary": "ゲートウェイは応答可能",
                    "value": {
                      "status": "ok"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "ダッシュボードで発行した API キーを `Authorization: Bearer mc_live_xxxxx` の形で送ります。キーは秘密情報として扱ってください。**このページの入力欄にライブキーを貼らないでください** — 試すときはサーバー側で curl を実行するか、Enterprise のテストキー (`mc_test_xxxxx`) を使ってください。"
      }
    },
    "schemas": {
      "ModerationRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "description": "判定対象のテキスト (1〜5000 文字)。文字数は Unicode コードポイント数で数えます (JavaScript の `String.length` とは一致しません)。5000 文字を超えると 413 `text_too_long` になります。"
          },
          "options": {
            "type": "object",
            "properties": {
              "mask_char": {
                "default": "*",
                "type": "string",
                "description": "マスクに使う文字 (既定 `*`)。1〜8 文字 (Unicode コードポイント数) で、範囲外は 400 `invalid_request` になります。この範囲を JSON Schema の `minLength` / `maxLength` では表現していません — それらは UTF-16 単位の長さで、絵文字などコードポイント基準の判定と食い違うためです。"
              },
              "mask_mode": {
                "default": "repeat",
                "type": "string",
                "enum": [
                  "repeat",
                  "fixed"
                ],
                "description": "マスクの方式。`repeat` は NG 語の長さぶんマスク文字を繰り返します (既定)。`fixed` は NG 語 1 つをマスク文字 1 つ分に置き換えるため、複数文字のマスク文字を指定すると `masked` の長さは原文と一致しません。"
              }
            },
            "additionalProperties": false,
            "description": "マスクの指定。ここに未知のキーを含めると 400 `invalid_request` になります (`mask_charr` のような打ち間違いを黙って無視しないため)。"
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "ModerationResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "リクエスト識別子。応答ヘッダ `X-Request-Id` と同じ値で、問い合わせ時の突合に使えます。"
          },
          "flagged": {
            "type": "boolean",
            "description": "NG 語が 1 つでも含まれていれば true。"
          },
          "masked": {
            "type": "string",
            "description": "検出された NG 語をマスクしたテキスト。"
          },
          "matches": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "検出された NG 部分の原文。"
          },
          "segments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "text": {
                  "type": "string",
                  "description": "この区間の文字列。"
                },
                "clean": {
                  "type": "boolean",
                  "description": "この区間に NG 語が含まれない場合 true。"
                },
                "start": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "区間の開始位置 (Unicode コードポイント基準)。JavaScript の `slice` は UTF-16 単位で数えるため、絵文字などを含むテキストではこの値をそのまま渡せません。"
                },
                "end": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "区間の終了位置 (Unicode コードポイント基準・終端は含みません)。"
                }
              },
              "required": [
                "text",
                "clean",
                "start",
                "end"
              ]
            },
            "description": "入力を判定単位に分割した結果。連結すると元のテキストに戻ります。"
          },
          "usage": {
            "type": "object",
            "properties": {
              "chars": {
                "type": "integer",
                "minimum": 0,
                "description": "入力の文字数 (Unicode コードポイント数)。"
              }
            },
            "required": [
              "chars"
            ],
            "description": "この呼び出しの使用量。"
          }
        },
        "required": [
          "id",
          "flagged",
          "masked",
          "matches",
          "segments",
          "usage"
        ]
      },
      "HealthResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "ok",
            "description": "常に `ok`。"
          }
        },
        "required": [
          "status"
        ]
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "missing_api_key",
                  "invalid_api_key",
                  "payment_required",
                  "account_suspended",
                  "text_too_long",
                  "body_too_large",
                  "rate_limit_exceeded",
                  "monthly_quota_exceeded",
                  "spend_cap_reached",
                  "upstream_error",
                  "service_unavailable",
                  "internal_error"
                ],
                "description": "機械判定用のエラーコード。分岐にはこの値を使い、`message` の文面には依存しないでください。"
              },
              "message": {
                "type": "string",
                "description": "人間向けの説明 (`Accept-Language` に追従)。以下の例に含まれる波括弧の部分は、実際の応答では実値に置換されています。"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "description": "エラーの内容。"
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}
