{
  "openapi": "3.1.0",
  "info": {
    "title": "EvoLink Moderation 1.0 전체 API 레퍼런스",
    "description": "EvoLink 콘텐츠 모더레이션 API는 텍스트 및 이미지에 대한 유해 콘텐츠 탐지를 수행하며, `evolink_summary` 필드를 통해 통합된 리스크 요약을 반환하여 비즈니스 측에서 위험 등급을 한눈에 판단할 수 있도록 합니다.",
    "license": {
      "name": "MIT"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://direct.evolink.ai",
      "description": "프로덕션 (권장)"
    },
    {
      "url": "https://api.evolink.ai",
      "description": "폴백 엔드포인트"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/moderations": {
      "post": {
        "summary": "EvoLink Moderation 콘텐츠 모더레이션 API",
        "description": "- 동기식 API로, 입력된 **텍스트** 및/또는 **이미지**에 대해 13가지 항목의 유해 콘텐츠 탐지를 수행합니다\n- 응답에서 `evolink_summary` 필드를 통해 `risk_level` / `flagged` / `violations` / `max_score` / `max_category` 5가지 통합 요약을 반환합니다\n\n**핵심 기능**:\n- **멀티모달 모더레이션**: 텍스트만, 이미지만, 텍스트+이미지 조합 입력을 지원합니다\n- **13개 카테고리**: harassment, hate, sexual, violence, self-harm, illicit, sexual/minors 등\n- **리스크 등급 분류**: 각 카테고리마다 medium / high 임계값을 독립적으로 설정하며, 민감도 차이에 따라 차등적으로 판정합니다 (레드라인 항목인 sexual/minors는 가장 엄격한 임계값을 가집니다)\n- **설명 가능성**: 응답에서 카테고리별 `category_scores`와 단순화된 `evolink_summary`를 동시에 반환하므로, 비즈니스에서 둘 중 하나를 선택해 사용할 수 있습니다\n\n**입력 제한**:\n- 단일 요청당 최대 1장의 이미지 (여러 이미지를 모더레이션해야 하는 경우 동시 요청으로 분할하세요)\n- 이미지는 HTTPS URL 입력만 지원합니다\n\n**일반적인 사용 예**: 아래 예시를 참고하세요. 텍스트만, 텍스트+이미지, 이미지만 3가지 일반적인 시나리오를 다룹니다.",
        "operationId": "createModeration",
        "tags": [
          "콘텐츠 모더레이션"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModerationRequest"
              },
              "examples": {
                "moderate_text": {
                  "summary": "텍스트 전용 모더레이션",
                  "value": {
                    "model": "evolink-moderation-1.0",
                    "input": [
                      {
                        "type": "text",
                        "text": "I want to kill them."
                      }
                    ]
                  }
                },
                "moderate_image_url": {
                  "summary": "이미지 전용 모더레이션",
                  "value": {
                    "model": "evolink-moderation-1.0",
                    "input": [
                      {
                        "type": "image_url",
                        "image_url": {
                          "url": "https://example.com/image.png"
                        }
                      }
                    ]
                  }
                },
                "moderate_text_and_image": {
                  "summary": "텍스트 + 이미지 결합 모더레이션 (권장)",
                  "value": {
                    "model": "evolink-moderation-1.0",
                    "input": [
                      {
                        "type": "text",
                        "text": "이 이미지에 무엇이 있는지 설명해 주세요."
                      },
                      {
                        "type": "image_url",
                        "image_url": {
                          "url": "https://example.com/image.png"
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "모더레이션 성공",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModerationResponse"
                },
                "example": {
                  "evolink_summary": {
                    "risk_level": "medium",
                    "flagged": false,
                    "violations": [],
                    "max_score": 0.5973832720,
                    "max_category": "sexual"
                  },
                  "id": "modr-0d9740456c391e43c445bf0f010940c7",
                  "model": "evolink-moderation-1.0",
                  "results": [
                    {
                      "flagged": false,
                      "categories": {
                        "harassment": false,
                        "harassment/threatening": false,
                        "hate": false,
                        "hate/threatening": false,
                        "illicit": false,
                        "illicit/violent": false,
                        "self-harm": false,
                        "self-harm/intent": false,
                        "self-harm/instructions": false,
                        "sexual": false,
                        "sexual/minors": false,
                        "violence": false,
                        "violence/graphic": false
                      },
                      "category_scores": {
                        "harassment": 0.0006,
                        "harassment/threatening": 0.0007,
                        "hate": 0.00003,
                        "hate/threatening": 0.0000025,
                        "illicit": 0.000013,
                        "illicit/violent": 0.0000096,
                        "self-harm": 0.0000166,
                        "self-harm/intent": 0.000004,
                        "self-harm/instructions": 0.0000031,
                        "sexual": 0.5973832720,
                        "sexual/minors": 0.000004,
                        "violence": 0.0231,
                        "violence/graphic": 0.0089
                      },
                      "category_applied_input_types": {
                        "harassment": ["text"],
                        "harassment/threatening": ["text"],
                        "hate": ["text"],
                        "hate/threatening": ["text"],
                        "illicit": ["text"],
                        "illicit/violent": ["text"],
                        "self-harm": ["text"],
                        "self-harm/intent": ["text"],
                        "self-harm/instructions": ["text"],
                        "sexual": ["text"],
                        "sexual/minors": ["text"],
                        "violence": ["text"],
                        "violence/graphic": ["text"]
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "잘못된 요청 파라미터",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 400,
                    "message": "field input is required",
                    "type": "invalid_request_error",
                    "param": "input"
                  }
                }
              }
            }
          },
          "401": {
            "description": "인증 실패, 토큰이 유효하지 않거나 만료됨",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 401,
                    "message": "Invalid or expired token",
                    "type": "authentication_error"
                  }
                }
              }
            }
          },
          "402": {
            "description": "할당량 부족, 충전이 필요함",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 402,
                    "message": "Insufficient quota",
                    "type": "insufficient_quota_error",
                    "fallback_suggestion": "https://evolink.ai/dashboard/billing"
                  }
                }
              }
            }
          },
          "403": {
            "description": "해당 모델에 접근 권한이 없음",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 403,
                    "message": "Access denied for this model",
                    "type": "permission_error",
                    "param": "model"
                  }
                }
              }
            }
          },
          "404": {
            "description": "리소스를 찾을 수 없음",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 404,
                    "message": "Specified model not found",
                    "type": "not_found_error",
                    "param": "model",
                    "fallback_suggestion": "evolink-moderation-1.0"
                  }
                }
              }
            }
          },
          "413": {
            "description": "요청 본문이 너무 큼 (이미지 파일이 제한을 초과함)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 413,
                    "message": "Image file too large",
                    "type": "request_too_large_error",
                    "param": "input",
                    "fallback_suggestion": "compress image to under 20MB"
                  }
                }
              }
            }
          },
          "429": {
            "description": "요청 빈도가 제한을 초과함",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 429,
                    "message": "Rate limit exceeded",
                    "type": "rate_limit_error",
                    "fallback_suggestion": "retry after 60 seconds"
                  }
                }
              }
            }
          },
          "500": {
            "description": "서버 내부 오류",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 500,
                    "message": "Internal server error",
                    "type": "internal_server_error",
                    "fallback_suggestion": "try again later"
                  }
                }
              }
            }
          },
          "502": {
            "description": "게이트웨이 오류",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 502,
                    "message": "Bad gateway",
                    "type": "bad_gateway_error",
                    "fallback_suggestion": "try again later"
                  }
                }
              }
            }
          },
          "503": {
            "description": "서비스를 일시적으로 사용할 수 없음",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "code": 503,
                    "message": "Service temporarily unavailable",
                    "type": "service_unavailable_error",
                    "fallback_suggestion": "retry after 30 seconds"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ModerationRequest": {
        "type": "object",
        "required": [
          "model",
          "input"
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "모더레이션 모델 이름. 고정값 `evolink-moderation-1.0`",
            "enum": [
              "evolink-moderation-1.0"
            ],
            "example": "evolink-moderation-1.0"
          },
          "input": {
            "type": "array",
            "description": "모더레이션 대상 콘텐츠. 객체 배열 형식으로 통일되어 있으며, 각 요소는 `text` 또는 `image_url` 객체입니다.\n\n```json\n\"input\": [\n  {\"type\": \"text\", \"text\": \"모더레이션할 텍스트\"},\n  {\"type\": \"image_url\", \"image_url\": {\"url\": \"https://...\"}}\n]\n```\n\n**제한사항**:\n- 배열 내 `type=image_url` 객체는 **최대 1개**까지 허용됩니다. 여러 이미지를 모더레이션해야 하는 경우 동시 요청으로 분할하세요\n- `type=text` 객체의 개수에는 제한이 없습니다",
            "items": {
              "$ref": "#/components/schemas/ModerationContentItem"
            }
          }
        }
      },
      "ModerationContentItem": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/TextInputItem"
          },
          {
            "$ref": "#/components/schemas/ImageInputItem"
          }
        ]
      },
      "TextInputItem": {
        "title": "텍스트 입력 항목",
        "type": "object",
        "required": [
          "type",
          "text"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "text"
            ],
            "description": "콘텐츠 타입은 `text`로 고정됩니다"
          },
          "text": {
            "type": "string",
            "description": "모더레이션할 텍스트",
            "example": "이 이미지에 무엇이 있는지 설명해 주세요."
          }
        }
      },
      "ImageInputItem": {
        "title": "이미지 입력 항목",
        "type": "object",
        "required": [
          "type",
          "image_url"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "image_url"
            ],
            "description": "콘텐츠 타입은 `image_url`로 고정됩니다"
          },
          "image_url": {
            "type": "object",
            "required": [
              "url"
            ],
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "이미지의 HTTPS URL. 예: `https://example.com/image.png`\n\n**지원 포맷**: `.jpeg` / `.jpg` / `.png` / `.webp`\n\n**크기 제한**: 단일 이미지당 ≤ 20MB 권장 (초과 시 413 오류가 발생할 수 있음)\n\n**참고**: 단일 요청당 최대 1장의 이미지만 허용되므로, 여러 이미지가 필요한 경우 동시 요청으로 분할하세요",
                "example": "https://example.com/image.png"
              }
            }
          }
        }
      },
      "ModerationResponse": {
        "type": "object",
        "description": "모더레이션 응답. 최상위의 `evolink_summary`는 비즈니스 측에서 사용을 권장하는 통합 리스크 요약이며, `results`는 카테고리별 상세 점수를 제공합니다.",
        "properties": {
          "evolink_summary": {
            "$ref": "#/components/schemas/EvolinkSummary"
          },
          "id": {
            "type": "string",
            "description": "이번 모더레이션 요청의 고유 식별자",
            "example": "modr-0d9740456c391e43c445bf0f010940c7"
          },
          "model": {
            "type": "string",
            "description": "실제로 사용된 모델 이름. 고정값 `evolink-moderation-1.0`",
            "example": "evolink-moderation-1.0"
          },
          "results": {
            "type": "array",
            "description": "모더레이션 결과 목록. 항상 **1개**의 result를 반환합니다 (배열 형식의 입력은 단일 평가로 통합되어 점수가 매겨집니다).\n\n## 멀티모달 평가 범위\n\n13개 카테고리 중 일부 카테고리는 **텍스트만 평가**하며, 이미지에 대해서는 평가하지 않습니다:\n\n| 카테고리 | 평가 범위 |\n|------|----------|\n| `harassment` / `harassment/threatening` | 텍스트만 |\n| `hate` / `hate/threatening` | 텍스트만 |\n| `illicit` / `illicit/violent` | 텍스트만 |\n| `sexual/minors` | **텍스트만 (레드라인 항목 — 주의)** |\n| `self-harm` / `self-harm/intent` / `self-harm/instructions` | 텍스트 + 이미지 |\n| `sexual` | 텍스트 + 이미지 |\n| `violence` / `violence/graphic` | 텍스트 + 이미지 |\n\n**핵심 사항**:\n- 이미지만 전달한 경우, 위 7개의 텍스트 전용 카테고리의 점수는 항상 `0`이며 `category_applied_input_types`는 빈 배열이 됩니다 — **이는 콘텐츠가 안전함을 의미하는 것이 아니라, 평가되지 않았음을 의미합니다**\n- 미성년자 관련 리스크(`sexual/minors` 레드라인 항목)와 관련된 비즈니스라면 **반드시 텍스트 컨텍스트와 함께 모더레이션해야 하며**, 이미지 점수에만 의존해서는 안 됩니다",
            "items": {
              "$ref": "#/components/schemas/ModerationResult"
            }
          }
        }
      },
      "ModerationResult": {
        "type": "object",
        "description": "단일 입력에 대한 모더레이션 결과",
        "properties": {
          "flagged": {
            "type": "boolean",
            "description": "전역 위반 플래그: `categories` 내 어느 카테고리든 true이면 이 필드는 true가 됩니다.\n\n**비즈니스 측에서는 `evolink_summary.flagged`를 우선 사용하는 것을 권장합니다** — EvoLink 플랫폼의 등급별 임계값을 기반으로 판정하므로 로직이 더 세분화되고 통제가 용이합니다. 이 필드는 보조 참고용으로 더 적합합니다.",
            "example": false
          },
          "categories": {
            "$ref": "#/components/schemas/ModerationCategories"
          },
          "category_scores": {
            "$ref": "#/components/schemas/ModerationCategoryScores"
          },
          "category_applied_input_types": {
            "$ref": "#/components/schemas/ModerationCategoryAppliedInputTypes"
          }
        }
      },
      "ModerationCategories": {
        "type": "object",
        "description": "13개 카테고리의 위반 여부를 나타내는 불리언 플래그",
        "properties": {
          "harassment": {
            "type": "boolean",
            "description": "괴롭힘: 모든 대상에 대한 괴롭힘성 표현, 선동 또는 조장하는 언어"
          },
          "harassment/threatening": {
            "type": "boolean",
            "description": "위협적 괴롭힘: 폭력 또는 심각한 위해를 포함하는 괴롭힘 콘텐츠"
          },
          "hate": {
            "type": "boolean",
            "description": "혐오: 인종, 성별, 민족, 종교, 국적, 성적 지향, 장애 또는 카스트에 기반한 혐오 콘텐츠"
          },
          "hate/threatening": {
            "type": "boolean",
            "description": "위협적 혐오: 표적 집단에 대한 폭력 또는 심각한 위해를 동반한 혐오 콘텐츠"
          },
          "illicit": {
            "type": "boolean",
            "description": "불법 행위: 불법 행위에 대한 지침이나 조언을 제공함 (예: '도둑질하는 방법')"
          },
          "illicit/violent": {
            "type": "boolean",
            "description": "폭력적 불법: 폭력 또는 무기 입수에 관한 조언을 포함한 불법 콘텐츠"
          },
          "self-harm": {
            "type": "boolean",
            "description": "자해: 자해 행위(자살, 자상, 식이 장애 등)를 홍보, 권장 또는 묘사함"
          },
          "self-harm/instructions": {
            "type": "boolean",
            "description": "자해 지침: 자해를 실행하는 방법을 권장하거나 안내하는 콘텐츠"
          },
          "self-harm/intent": {
            "type": "boolean",
            "description": "자해 의도: 자신이 현재 자해를 하고 있거나 의도가 있음을 표현하는 콘텐츠"
          },
          "sexual": {
            "type": "boolean",
            "description": "성적: 성적 흥분을 유발하는 콘텐츠 (성교육 및 건강 관련 콘텐츠 제외)"
          },
          "sexual/minors": {
            "type": "boolean",
            "description": "미성년자 성적 콘텐츠 (**레드라인 항목**): 18세 미만 개인이 등장하는 성적 콘텐츠"
          },
          "violence": {
            "type": "boolean",
            "description": "폭력: 죽음, 폭력 또는 신체적 위해를 묘사함"
          },
          "violence/graphic": {
            "type": "boolean",
            "description": "잔인한 폭력: 죽음, 폭력 또는 신체적 위해를 시각적으로 자세히 묘사함"
          }
        }
      },
      "ModerationCategoryScores": {
        "type": "object",
        "description": "13개 카테고리의 신뢰도 점수 (0~1, 높을수록 위반 가능성이 큼)",
        "properties": {
          "harassment": {
            "type": "number",
            "description": "harassment 신뢰도",
            "example": 0.0006
          },
          "harassment/threatening": {
            "type": "number",
            "description": "harassment/threatening 신뢰도",
            "example": 0.0007
          },
          "hate": {
            "type": "number",
            "description": "hate 신뢰도",
            "example": 0.00003
          },
          "hate/threatening": {
            "type": "number",
            "description": "hate/threatening 신뢰도",
            "example": 0.0000025
          },
          "illicit": {
            "type": "number",
            "description": "illicit 신뢰도",
            "example": 0.000013
          },
          "illicit/violent": {
            "type": "number",
            "description": "illicit/violent 신뢰도",
            "example": 0.0000096
          },
          "self-harm": {
            "type": "number",
            "description": "self-harm 신뢰도",
            "example": 0.0000166
          },
          "self-harm/instructions": {
            "type": "number",
            "description": "self-harm/instructions 신뢰도",
            "example": 0.0000031
          },
          "self-harm/intent": {
            "type": "number",
            "description": "self-harm/intent 신뢰도",
            "example": 0.000004
          },
          "sexual": {
            "type": "number",
            "description": "sexual 신뢰도",
            "example": 0.5973
          },
          "sexual/minors": {
            "type": "number",
            "description": "sexual/minors 신뢰도",
            "example": 0.000004
          },
          "violence": {
            "type": "number",
            "description": "violence 신뢰도",
            "example": 0.0231
          },
          "violence/graphic": {
            "type": "number",
            "description": "violence/graphic 신뢰도",
            "example": 0.0089
          }
        }
      },
      "ModerationCategoryAppliedInputTypes": {
        "type": "object",
        "description": "각 카테고리가 **실제로 어떤 입력 타입을 평가했는지** 나타냅니다. 값은 배열이며, 요소는 `text` 또는 `image`입니다.\n\n각 카테고리의 평가 범위(텍스트만 / 텍스트+이미지)는 `results` 필드 설명에 매핑 표로 제공되어 있습니다. 이 필드의 배열은 이번 요청에서 **실제로 적용된** 입력 타입을 나타냅니다.",
        "properties": {
          "harassment": {
            "type": "array",
            "description": "harassment에 적용된 입력 타입 (text만)",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "harassment/threatening": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "hate": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "hate/threatening": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "illicit": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "illicit/violent": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "self-harm": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          },
          "self-harm/instructions": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          },
          "self-harm/intent": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          },
          "sexual": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          },
          "sexual/minors": {
            "type": "array",
            "description": "sexual/minors는 text만 지원합니다",
            "items": {
              "type": "string",
              "enum": [
                "text"
              ]
            }
          },
          "violence": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          },
          "violence/graphic": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "text",
                "image"
              ]
            }
          }
        }
      },
      "EvolinkSummary": {
        "type": "object",
        "description": "**EvoLink 리스크 요약**: 13개 카테고리의 `category_scores`를 기반으로 각 카테고리의 민감도에 따라 차등 적용된 임계값으로 산출된 통합 요약입니다. 비즈니스에서는 이 정보만으로도 허용/거부/검토 송부 판단이 가능합니다.\n\n## 리스크 등급 임계값 표\n\n| 카테고리 | medium 임계값 | high 임계값 | 비고 |\n|------|-----------|----------|------|\n| `sexual/minors` | 0.05 | 0.20 | **레드라인 항목**, 가장 엄격한 임계값 |\n| `self-harm` / `self-harm/intent` / `self-harm/instructions` | 0.30 | 0.60 | 인명 관련, 엄격함 |\n| `violence/graphic` | 0.40 | 0.70 | 잔인한 폭력 |\n| `illicit/violent` | 0.40 | 0.70 | 폭력적 불법 |\n| `sexual` | 0.50 | 0.80 | 일반 성적 콘텐츠 |\n| `violence` | 0.50 | 0.80 | 일반 폭력 |\n| `harassment/threatening` | 0.50 | 0.80 | 위협적 괴롭힘 |\n| `hate/threatening` | 0.50 | 0.80 | 위협적 혐오 |\n| `harassment` | 0.60 | 0.85 | 일반 괴롭힘 |\n| `hate` | 0.60 | 0.85 | 일반 혐오 |\n| `illicit` | 0.60 | 0.85 | 일반 불법 안내 |\n\n## 판정 규칙\n\n```\n어느 한 카테고리라도 score >= 해당 카테고리 high 임계값   → risk_level = \"high\",   flagged = true,  violations에 추가\n어느 한 카테고리라도 score >= 해당 카테고리 medium 임계값 → risk_level = \"medium\", flagged = false\n그 외                                                    → risk_level = \"low\",    flagged = false\n```\n\n## 비즈니스 측 사용 가이드\n\n```python\nsummary = response[\"evolink_summary\"]\n\nif summary[\"flagged\"]:                         # high → 즉시 거부\n    reject(reason=summary[\"violations\"])\nelif summary[\"risk_level\"] == \"medium\":        # 회색 영역\n    log_for_review(summary)                    # 로그 기록, 수동 검토\n    proceed()\nelse:                                          # low → 허용\n    proceed()\n```",
        "properties": {
          "risk_level": {
            "type": "string",
            "description": "리스크 등급\n\n- `low`: 모든 카테고리가 medium 임계값 미만\n- `medium`: 적어도 한 카테고리가 medium 임계값을 넘었지만 high 임계값은 넘지 않음\n- `high`: 적어도 한 카테고리가 high 임계값을 넘음 (레드라인)",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "example": "medium"
          },
          "flagged": {
            "type": "boolean",
            "description": "거부 권고 발동 여부.\n\n`risk_level == \"high\"`와 동등합니다. **비즈니스에서는 이 필드를 기준으로 허용/거부 판단을 하는 것을 권장합니다**.\n\n참고: 이 필드는 `results[].flagged`와 다릅니다 — `results[].flagged`는 어느 카테고리든 임계선을 넘으면 true가 되는 전역 불리언이고, 이 필드는 EvoLink 등급별 임계값을 기반으로 민감도에 따라 차등 판정하므로 더 통제가 용이합니다.",
            "example": false
          },
          "violations": {
            "type": "array",
            "description": "**high 임계값을 넘긴 카테고리 목록**.\n\n- `risk_level == \"high\"`일 때, 이 배열에는 high 임계값을 초과한 모든 카테고리 이름이 나열됩니다 (예: `[\"sexual/minors\", \"violence\"]`)\n- `risk_level == \"medium\"` 또는 `\"low\"`일 때, 이 배열은 빈 `[]`입니다",
            "items": {
              "type": "string"
            },
            "example": [
              "sexual/minors"
            ]
          },
          "max_score": {
            "type": "number",
            "description": "13개 카테고리 중 최대 점수 (0~1). 비즈니스 모니터링 및 임계값 튜닝에 사용할 수 있습니다.",
            "minimum": 0,
            "maximum": 1,
            "example": 0.5973832720
          },
          "max_category": {
            "type": "string",
            "description": "최대 점수에 해당하는 카테고리 이름 (13개 카테고리 중 하나)",
            "example": "sexual"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer",
                "description": "HTTP 상태 오류 코드"
              },
              "message": {
                "type": "string",
                "description": "오류 설명 메시지"
              },
              "type": {
                "type": "string",
                "description": "오류 타입"
              },
              "param": {
                "type": "string",
                "description": "관련 파라미터 이름"
              },
              "fallback_suggestion": {
                "type": "string",
                "description": "오류 발생 시의 권장 조치"
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "##모든 엔드포인트는 Bearer Token 인증이 필요합니다##\n\n**API 키 발급:**\n\n[API 키 관리 페이지](https://evolink.ai/dashboard/keys)에서 API 키를 발급받으세요.\n\n**요청 헤더에 추가:**\n```\nAuthorization: Bearer YOUR_API_KEY\n```"
      }
    }
  },
  "tags": [
    {
      "name": "콘텐츠 모더레이션",
      "description": "EvoLink 콘텐츠 모더레이션 API (텍스트 + 이미지)"
    }
  ]
}
