{
  "openapi": "3.0.3",
  "info": {
    "title": "网页监控中心 API",
    "version": "2.0.0",
    "description": "定时打开网页，按关键词/状态码/价格/变化判断命中，状态变化时通知（邮件 + Discord/Telegram）。免认证。说明见 https://monitor.kunled.com/docs ；MCP：https://monitor.kunled.com/mcp 。通知邮箱只能是 bikun526@gmail.com。写操作请带 actor（例 \"muse\"）方便看操作记录。"
  },
  "servers": [
    {
      "url": "https://monitor.kunled.com/api",
      "description": "主地址"
    },
    {
      "url": "https://kkmail.bikun526.workers.dev/monitor/api",
      "description": "备用（workers.dev）"
    },
    {
      "url": "https://mail.kunled.com/monitor/api",
      "description": "备用"
    }
  ],
  "paths": {
    "/monitors": {
      "get": {
        "operationId": "listMonitors",
        "summary": "列出监控（分页、搜索，不含回收站）",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "搜 名称/网址/备注/关键词"
          },
          {
            "name": "url",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "网址精确匹配"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "disappear",
                "appear",
                "regex",
                "change",
                "status",
                "price"
              ]
            }
          },
          {
            "name": "enabled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Monitor"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createMonitor",
        "summary": "新增监控（幂等：相同条件已存在则返回已有那条）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/MonitorInput"
                  }
                ],
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "已存在相同条件，未重复新建",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "existed": {
                          "type": "boolean",
                          "example": true
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "已新建",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "existed": {
                          "type": "boolean",
                          "example": false
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/check": {
      "get": {
        "operationId": "checkMonitorSetup",
        "summary": "检查监控设置了没、在不在正常运行",
        "description": "id / url / name / q 四选一；可加 mode / keywords / status_code 比对条件。总是 200，看 data.configured / data.running。",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "url",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "忽略末尾 / 和大小写"
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "名称包含"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "disappear",
                "appear",
                "regex",
                "change",
                "status",
                "price"
              ]
            }
          },
          {
            "name": "keywords",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "多个用 | 隔开"
          },
          {
            "name": "status_code",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "configured": {
                          "type": "boolean"
                        },
                        "running": {
                          "type": "boolean"
                        },
                        "exact_match": {
                          "type": "boolean",
                          "nullable": true
                        },
                        "summary": {
                          "type": "string"
                        },
                        "monitor": {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Monitor"
                            }
                          ],
                          "nullable": true
                        },
                        "matches": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Monitor"
                          }
                        },
                        "service": {
                          "type": "object",
                          "properties": {
                            "monitors_total": {
                              "type": "integer"
                            },
                            "monitors_enabled": {
                              "type": "integer"
                            },
                            "last_check_any_at_iso": {
                              "type": "string",
                              "nullable": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/test": {
      "post": {
        "operationId": "testMonitor",
        "summary": "按条件试检测一次，不保存",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/MonitorInput"
                  }
                ],
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "result": {
                          "$ref": "#/components/schemas/CheckResult"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/trash": {
      "get": {
        "operationId": "listTrash",
        "summary": "回收站（30 天后自动清掉）",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "keep_days": {
                          "type": "integer"
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Monitor"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/monitors/batch_delete": {
      "post": {
        "operationId": "batchDeleteMonitors",
        "summary": "批量删除（默认进回收站）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "ids"
                ],
                "properties": {
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "permanent": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "permanent": {
                          "type": "boolean"
                        },
                        "deleted": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "not_found": {
                          "type": "array",
                          "items": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/test-email": {
      "post": {
        "operationId": "sendTestEmail",
        "summary": "发测试通知",
        "description": "收件人只能白名单（默认 bikun526@gmail.com）。20 秒 1 封、24 小时 30 封，超了 429。",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestEmailInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TestEmailResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "502": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "get": {
        "operationId": "getMonitor",
        "summary": "查看一条",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateMonitor",
        "summary": "修改（只传要改的字段）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "reset": {
                          "type": "boolean"
                        },
                        "changed": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "put": {
        "operationId": "replaceMonitor",
        "summary": "修改（与 PATCH 相同）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "reset": {
                          "type": "boolean"
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteMonitor",
        "summary": "删除（默认进回收站）",
        "parameters": [
          {
            "name": "permanent",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "true=彻底删除"
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "permanent": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/restore": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "post": {
        "operationId": "restoreMonitor",
        "summary": "从回收站恢复",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "restored": {
                          "type": "boolean"
                        },
                        "message": {
                          "type": "string"
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/pause": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "post": {
        "operationId": "pauseMonitor",
        "summary": "暂停",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/resume": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "post": {
        "operationId": "resumeMonitor",
        "summary": "恢复",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/run": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "post": {
        "operationId": "runMonitor",
        "summary": "立刻检测一次",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "result": {
                          "$ref": "#/components/schemas/CheckResult"
                        },
                        "monitor": {
                          "$ref": "#/components/schemas/Monitor"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/logs": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "get": {
        "operationId": "getMonitorLogs",
        "summary": "检测日志",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "logs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Log"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/monitors/{id}/audit": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "get": {
        "operationId": "getMonitorAudit",
        "summary": "这条监控的操作记录",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AuditList"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/monitors/{id}/test-email": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          },
          "description": "监控 id"
        }
      ],
      "post": {
        "operationId": "sendMonitorTestEmail",
        "summary": "按这条监控的收件人和格式发「模拟命中」测试通知",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestEmailInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/TestEmailResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "502": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/settings": {
      "get": {
        "operationId": "getSettings",
        "summary": "查看全局设置（密钥显示 ***）",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "settings": {
                          "$ref": "#/components/schemas/Settings"
                        },
                        "quiet_now": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateSettings",
        "summary": "修改全局设置（只传要改的）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Settings"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "changed": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "settings": {
                          "$ref": "#/components/schemas/Settings"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/settings/test": {
      "post": {
        "operationId": "testChannels",
        "summary": "测试 Discord / Telegram",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "ok_channels": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "502": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/audit": {
      "get": {
        "operationId": "listAudit",
        "summary": "操作记录（最近 90 天）",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "maximum": 500
            }
          },
          {
            "name": "monitor_id",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AuditList"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/export": {
      "get": {
        "operationId": "exportMonitors",
        "summary": "导出全部监控（JSON 备份，请求头的值打码）",
        "parameters": [
          {
            "name": "download",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "导出文件",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "format": {
                      "type": "string"
                    },
                    "version": {
                      "type": "integer"
                    },
                    "monitors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MonitorInput"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/import": {
      "post": {
        "operationId": "importMonitors",
        "summary": "导入（导出文件原样传，重复的跳过）",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "monitors"
                ],
                "properties": {
                  "monitors": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/MonitorInput"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "created": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "existed": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "failed": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "系统状态（异常时 503）",
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "异常",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/report": {
      "get": {
        "operationId": "previewDailyReport",
        "summary": "日报预览（不发送）",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "subject": {
                          "type": "string"
                        },
                        "text": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Error": {
        "description": "失败",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "ok": {
                  "type": "boolean",
                  "example": false
                },
                "code": {
                  "type": "string",
                  "enum": [
                    "INVALID_JSON",
                    "VALIDATION_ERROR",
                    "MISSING_ID",
                    "NOT_FOUND",
                    "METHOD_NOT_ALLOWED",
                    "CONFLICT",
                    "LIMIT_EXCEEDED",
                    "RATE_LIMITED",
                    "SEND_FAILED",
                    "INTERNAL"
                  ]
                },
                "message": {
                  "type": "string"
                },
                "error": {
                  "type": "string",
                  "description": "同 message"
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "MonitorInput": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "要监控的网址，http:// 或 https:// 开头（新增时必填）"
          },
          "name": {
            "type": "string",
            "description": "名称，可省（默认用网址）"
          },
          "mode": {
            "type": "string",
            "enum": [
              "disappear",
              "appear",
              "regex",
              "change",
              "status",
              "price"
            ],
            "default": "appear",
            "description": "检测方式：disappear=关键词「消失」时命中（等维护结束）；appear=关键词「出现」时命中（等到货/开卖）；change=页面文字有变化；status=HTTP 状态码等于 status_code；regex=正则匹配；price=价格监控（配合 price_op / price_value）"
          },
          "keywords": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "disappear/appear/regex 必填；多个用数组或 | 隔开，不分大小写。mode=price 时可选：自定义提取价格的正则（第 1 个括号是数字）"
          },
          "match_logic": {
            "type": "string",
            "enum": [
              "any",
              "all"
            ],
            "default": "any",
            "description": "多个关键词时：any=任意一个就算，all=全部都要有"
          },
          "selector": {
            "type": "string",
            "description": "只在页面这一块里找（CSS 选择器，例 #stock、.price、div.item-status）。避开广告/推荐栏误报；选不到元素算检测失败，不会误报"
          },
          "status_code": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599,
            "description": "mode=status 必填，例 200"
          },
          "price_op": {
            "type": "string",
            "enum": [
              "below",
              "above",
              "drop",
              "rise",
              "change"
            ],
            "default": "below",
            "description": "mode=price 的条件：below=价格 ≤ price_value；above=价格 ≥ price_value；drop=比上次降价；rise=比上次涨价；change=价格有变化"
          },
          "price_value": {
            "type": "number",
            "description": "mode=price 且 price_op 是 below/above 时必填（目标价格）"
          },
          "interval_min": {
            "type": "integer",
            "default": 10,
            "minimum": 1,
            "maximum": 1440,
            "description": "检测频率（分钟），1～1440。也可以传 check_interval（秒）"
          },
          "notify_on": {
            "type": "string",
            "enum": [
              "hit",
              "both",
              "none"
            ],
            "default": "hit",
            "description": "何时通知：hit=只在命中时；both=命中和变回未命中都发；none=不发只记录"
          },
          "notify_email": {
            "type": "string",
            "default": "bikun526@gmail.com",
            "description": "通知邮箱，只能用白名单（默认 bikun526@gmail.com）"
          },
          "auto_pause": {
            "type": "boolean",
            "default": false,
            "description": "true=命中并通知后自动暂停（只想通知一次时用）"
          },
          "confirm_count": {
            "type": "integer",
            "default": 1,
            "minimum": 1,
            "maximum": 10,
            "description": "连续命中几次才算，防偶发误报填 2"
          },
          "require_ok": {
            "type": "boolean",
            "default": true,
            "description": "true=网页没正常打开时不算命中（disappear 一定要保持 true）"
          },
          "error_alert": {
            "type": "boolean",
            "default": false,
            "description": "true=连续 3 次打不开时发提醒"
          },
          "ua": {
            "type": "string",
            "enum": [
              "pc",
              "mobile"
            ],
            "default": "pc",
            "description": "用电脑 / 手机浏览器身份去抓"
          },
          "headers": {
            "type": "string",
            "description": "自定义请求头，每行「名称: 值」，例 Cookie: session=abc。返回时值显示为 ***；修改时某行值原样传 *** 表示不改那一行"
          },
          "render": {
            "type": "boolean",
            "default": false,
            "description": "用真浏览器打开（能看到 JS 生成的内容）。较慢且有每日额度：频率至少 30 分钟，最多 5 条"
          },
          "ignore_quiet": {
            "type": "boolean",
            "default": false,
            "description": "紧急：免打扰时段也立刻通知"
          },
          "hit_label": {
            "type": "string",
            "description": "命中时显示的文字，例「不维护了」"
          },
          "miss_label": {
            "type": "string",
            "description": "未命中时显示的文字，例「维护中」"
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_-]+$",
            "description": "公开状态代号（不能重复），设了就能读 https://monitor.kunled.com/m/{slug}.txt"
          },
          "note": {
            "type": "string",
            "description": "备注"
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "是否启用"
          },
          "check_interval": {
            "type": "integer",
            "description": "检测频率（秒），会换算成 interval_min"
          },
          "allow_duplicate": {
            "type": "boolean",
            "default": false,
            "description": "仅新增：true=已有相同条件也新建"
          },
          "actor": {
            "type": "string",
            "description": "操作者名字（写进操作日志，例 muse）"
          }
        }
      },
      "Settings": {
        "type": "object",
        "properties": {
          "daily_report": {
            "type": "boolean",
            "default": true,
            "description": "每天发一封日报（各监控状态、24 小时检测/命中/失败/通知次数）"
          },
          "daily_hour": {
            "type": "integer",
            "default": 9,
            "minimum": 0,
            "maximum": 23,
            "description": "日报发送时间（日本时间，几点）"
          },
          "report_email": {
            "type": "string",
            "default": "bikun526@gmail.com",
            "description": "日报和系统告警发到哪（只能白名单）"
          },
          "system_alert": {
            "type": "boolean",
            "default": true,
            "description": "系统告警：定时任务中断后恢复、有监控超时没检测、大量监控同时失败时发邮件"
          },
          "quiet_start": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23,
            "nullable": true,
            "description": "免打扰开始（日本时间，几点），null=关闭。免打扰期间的通知会在结束后汇总成一封发"
          },
          "quiet_end": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23,
            "nullable": true,
            "description": "免打扰结束（日本时间，几点），例 quiet_start=23、quiet_end=8"
          },
          "max_mails_per_hour": {
            "type": "integer",
            "default": 6,
            "minimum": 0,
            "maximum": 60,
            "description": "单条监控 1 小时最多通知几次，0=不限（防网站抖动刷屏）"
          },
          "discord_webhook": {
            "type": "string",
            "description": "Discord Webhook 网址（https://discord.com/api/webhooks/...），设了通知会同时发到 Discord；返回时显示 ***"
          },
          "telegram_bot_token": {
            "type": "string",
            "description": "Telegram 机器人 token（123456:ABC...），返回时显示 ***"
          },
          "telegram_chat_id": {
            "type": "string",
            "description": "Telegram 接收的 chat_id（数字或 @频道名）"
          },
          "render_daily_minutes": {
            "type": "integer",
            "default": 8,
            "minimum": 1,
            "maximum": 600,
            "description": "浏览器渲染（render）每天最多用几分钟（免费版每天 10 分钟），用完当天改用普通抓取"
          }
        }
      },
      "Monitor": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MonitorInput"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "keywords": {
                "type": "string",
                "description": "换行分隔"
              },
              "keywords_list": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "condition_text": {
                "type": "string"
              },
              "enabled": {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              "state": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "HIT",
                  "MISS",
                  null
                ]
              },
              "state_label": {
                "type": "string"
              },
              "health": {
                "type": "string",
                "enum": [
                  "ok",
                  "pending",
                  "error",
                  "paused",
                  "stale",
                  "trash"
                ]
              },
              "health_text": {
                "type": "string"
              },
              "last_result": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "HIT",
                  "MISS",
                  "ERROR",
                  null
                ]
              },
              "last_http": {
                "type": "integer",
                "nullable": true
              },
              "last_detail": {
                "type": "string",
                "nullable": true
              },
              "last_value": {
                "type": "number",
                "nullable": true,
                "description": "price 模式的当前价格"
              },
              "recent": {
                "type": "string",
                "nullable": true,
                "description": "最近检测结果 H/M/E"
              },
              "recent_ok_rate": {
                "type": "integer",
                "nullable": true,
                "description": "最近检测成功率 %"
              },
              "last_checked_at": {
                "type": "integer",
                "nullable": true
              },
              "last_checked_at_iso": {
                "type": "string",
                "nullable": true,
                "format": "date-time"
              },
              "next_check_at_iso": {
                "type": "string",
                "nullable": true,
                "format": "date-time"
              },
              "last_changed_at_iso": {
                "type": "string",
                "nullable": true,
                "format": "date-time"
              },
              "status_url": {
                "type": "string",
                "nullable": true
              },
              "deleted_at_iso": {
                "type": "string",
                "nullable": true,
                "format": "date-time"
              },
              "purge_at_iso": {
                "type": "string",
                "nullable": true,
                "format": "date-time"
              }
            }
          }
        ]
      },
      "CheckResult": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "HIT",
              "MISS",
              "ERROR"
            ]
          },
          "label": {
            "type": "string"
          },
          "http": {
            "type": "integer",
            "nullable": true
          },
          "ms": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "value": {
            "type": "number",
            "nullable": true
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Log": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "monitor_id": {
            "type": "integer"
          },
          "at": {
            "type": "integer"
          },
          "at_iso": {
            "type": "string",
            "format": "date-time"
          },
          "result": {
            "type": "string"
          },
          "http": {
            "type": "integer",
            "nullable": true
          },
          "ms": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "event": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AuditList": {
        "type": "object",
        "properties": {
          "keep_days": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "at_iso": {
                  "type": "string",
                  "format": "date-time"
                },
                "monitor_id": {
                  "type": "integer",
                  "nullable": true
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "create",
                    "update",
                    "delete",
                    "purge",
                    "restore",
                    "pause",
                    "resume",
                    "settings",
                    "import",
                    "test_email",
                    "test_channels"
                  ]
                },
                "actor": {
                  "type": "string"
                },
                "ip": {
                  "type": "string"
                },
                "summary": {
                  "type": "string"
                },
                "changes": {
                  "type": "object",
                  "nullable": true,
                  "description": "字段: [旧值, 新值]"
                }
              }
            }
          }
        }
      },
      "TestEmailInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "bikun526@gmail.com"
          },
          "subject": {
            "type": "string",
            "maxLength": 80
          },
          "message": {
            "type": "string",
            "maxLength": 2000
          },
          "id": {
            "type": "integer",
            "description": "按这条监控的格式发样例"
          },
          "channels": {
            "type": "boolean",
            "default": false,
            "description": "true=同时发 Discord/Telegram"
          }
        }
      },
      "TestEmailResult": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "monitor_id": {
            "type": "integer",
            "nullable": true
          },
          "sent_at_iso": {
            "type": "string",
            "format": "date-time"
          },
          "resend_id": {
            "type": "string",
            "nullable": true
          },
          "mail_ok": {
            "type": "boolean"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "remaining_today": {
            "type": "integer"
          }
        }
      }
    }
  }
}