{
  "openapi" : "3.1.0",
  "info" : {
    "title" : "L2 MOG API",
    "description" : "API pública do servidor L2 MOG — status, rankings, notícias, clãs, castelos, bosses, votos; endpoints de conta/dashboard/loja exigem JWT.\n\n## Base URL\n`https://api.l2mog.com/api/v1` é a forma canônica. `/api/*` (sem versão) continua funcionando como alias do v1, por compatibilidade.\n\n## Versionamento\nA versão vai no path (`/api/v{n}`). O header `API-Version` é opcional na requisição (só rejeitado com 400 se vier com um valor diferente de `1`) e sempre vem na resposta. Uma versão nova só é introduzida quando há mudança incompatível.\n\n## Deprecação\nAviso mínimo de 90 dias antes de remover um endpoint. Um endpoint deprecado responde com os headers `Deprecation` (RFC 9745) e `Sunset` (RFC 8594), além de `Link rel=\"deprecation\"` apontando para o changelog. Política completa (prazo, headers, changelog) em https://l2mog.com/deprecation-policy.\n\n## Rate limit\n600 requisições por minuto por IP (padrão). Toda resposta traz `RateLimit` e `RateLimit-Policy` (Structured Fields, draft-ietf-httpapi-ratelimit-headers) e os headers legados `RateLimit-Limit`/`RateLimit-Remaining`/`RateLimit-Reset`. Ao exceder, responde `429` com `Retry-After`.\n\n## Erros\nTodo `4xx`/`5xx` retorna o corpo `ApiError` (`timestamp`, `status`, `code`, `message`, `hint`, `path`). O campo `code` é estável e pensado para automação — não faça parsing de `message`.\n\n## Autenticação\nJWT: autentique em `POST /api/v1/auth/login` e envie `Authorization: Bearer <token>` nos endpoints protegidos. `X-Game-Key` é reservado para integrações do próprio servidor de jogo.\n\n## Conteúdo para agentes\nhttps://l2mog.com/llms.txt, https://l2mog.com/agents.md e https://l2mog.com/developers têm a documentação estruturada para LLMs e ferramentas automatizadas.\n",
    "termsOfService" : "https://l2mog.com/privacy",
    "contact" : {
      "name" : "L2 MOG",
      "url" : "https://discord.gg/XmcGYJgMUF"
    },
    "version" : "1.0.0"
  },
  "externalDocs" : {
    "description" : "Documentação para desenvolvedores",
    "url" : "https://l2mog.com/developers"
  },
  "servers" : [ {
    "url" : "https://api.l2mog.com",
    "description" : "Produção"
  } ],
  "tags" : [ {
    "name" : "Raid Bosses",
    "description" : "Status público dos raid bosses (vivo/morto, respawn)"
  }, {
    "name" : "Store",
    "description" : "Catálogo e checkout de packs da loja, para a conta logada"
  }, {
    "name" : "Client Logs",
    "description" : "Sync rotineiro do log do cliente (system/l2.log), sem contexto de crash"
  }, {
    "name" : "Payment",
    "description" : "Checkout de coins (PayPal/Mercado Pago) e webhooks de pagamento"
  }, {
    "name" : "Clans",
    "description" : "Ranking público de clãs"
  }, {
    "name" : "Home",
    "description" : "Resumo público da home (status do servidor + últimas notícias)"
  }, {
    "name" : "NPC Respawn",
    "description" : "Janela de respawn pública de grand bosses/NPCs especiais"
  }, {
    "name" : "Referral",
    "description" : "Programa de indicação (Convide um amigo) do mundo PvP (Mid PvP)"
  }, {
    "name" : "Auth",
    "description" : "Login, registro, recuperação de senha e campanhas de e-mail. Rotas públicas (permitAll)"
  }, {
    "name" : "Community",
    "description" : "Links de comunidade (Discord, redes sociais, etc.)"
  }, {
    "name" : "Crash",
    "description" : "Telemetria de crash do cliente (tail de log e bundle completo)"
  }, {
    "name" : "News",
    "description" : "Notícias públicas; escrita (POST/PUT/DELETE) exige X-Game-Key"
  }, {
    "name" : "Game",
    "description" : "Ações da conta logada sobre o servidor de jogo"
  }, {
    "name" : "Players",
    "description" : "Rankings públicos de personagens"
  }, {
    "name" : "Dashboard",
    "description" : "Dados e ações da conta logada (mundo craft)"
  }, {
    "name" : "Diagnostic",
    "description" : "Snapshots de CharInfo do gameserver, para reconstruir crashes de outros clientes"
  }, {
    "name" : "Events",
    "description" : "Rankings públicos de eventos (5v5, 2v2, FFA, heróis, TVT semanal)"
  }, {
    "name" : "Castles",
    "description" : "Estado público dos castelos (dono, cerco, etc.)"
  }, {
    "name" : "PvP Worlds",
    "description" : "Dados públicos do mundo 2 (Mid PvP)"
  }, {
    "name" : "AntiCheat",
    "description" : "Telemetria do launcher: eventos de detecção/diagnóstico do anticheat"
  }, {
    "name" : "Game Packs",
    "description" : "Entrega de packs comprados na loja para o gameserver"
  }, {
    "name" : "Server",
    "description" : "Status e configuração pública do servidor"
  }, {
    "name" : "Vote",
    "description" : "Postback de votos de sites de ranking (ex.: Top100Arena)"
  } ],
  "paths" : {
    "/api/v1/news/{id}" : {
      "get" : {
        "tags" : [ "News" ],
        "summary" : "Busca uma notícia por id",
        "description" : "Busca uma notícia pelo id, filtrando pelo mundo informado (\"craft\"/\"pvp\") se presente, ou sem filtro de mundo se omitido/valor desconhecido. Notícia não encontrada: 404. Rota pública, sem autenticação.",
        "operationId" : "byId",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "description" : "Id da notícia",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int64"
          }
        }, {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = sem filtro de mundo",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/News"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "put" : {
        "tags" : [ "News" ],
        "summary" : "Atualiza uma notícia existente",
        "description" : "Atualiza a notícia de id informado no mundo indicado (padrão sem filtro, ver NewsWorld#fromParam); se o corpo não trouxer world, mantém o mundo atual da notícia. Notícia não encontrada: 404. Trocar o mundo craft<->pvp não é suportado (a notícia vive num banco físico por mundo) e retorna 400 com {error: \"news.world.change.unsupported\"}. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401.",
        "operationId" : "update",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "id",
          "in" : "path",
          "description" : "Id da notícia",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int64"
          }
        }, {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = sem filtro de mundo",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/News"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      },
      "delete" : {
        "tags" : [ "News" ],
        "summary" : "Apaga uma notícia",
        "description" : "Apaga a notícia de id informado, filtrando pelo mundo se presente (ver NewsWorld#fromParam). Retorna 204 sem corpo. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401.",
        "operationId" : "delete",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "id",
          "in" : "path",
          "description" : "Id da notícia",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int64"
          }
        }, {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = sem filtro de mundo",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/store/packs/paypal/checkout" : {
      "post" : {
        "tags" : [ "Store" ],
        "summary" : "Cria checkout PayPal para compra de um pack",
        "description" : "Cria uma ordem PayPal para o pack e mundo (\"craft\"/\"pvp\") informados em PackCheckoutRequestDTO, extraindo a conta do JWT. Retorna {checkoutUrl} com a URL de aprovação do PayPal.",
        "operationId" : "checkoutPackPaypal",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/PackCheckoutRequestDTO"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "string"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/store/packs/mercadopago/checkout" : {
      "post" : {
        "tags" : [ "Store" ],
        "summary" : "Cria checkout Mercado Pago para compra de um pack",
        "description" : "Cria uma preferência de pagamento no Mercado Pago para o pack e mundo (\"craft\"/\"pvp\") informados em PackCheckoutRequestDTO, extraindo a conta do JWT. Retorna {checkoutUrl} com a URL do checkout do Mercado Pago.",
        "operationId" : "checkoutPackMercadoPago",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/PackCheckoutRequestDTO"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "string"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/referral/apply" : {
      "post" : {
        "tags" : [ "Referral" ],
        "summary" : "Aplica um código de indicação à conta logada",
        "description" : "Fallback para quem não usou ?ref= no cadastro (ou cujo registro falhou com a stage fora). Aplica o código se a conta ainda não tiver indicação vinculada e for um indicado elegível (conta nova, sem personagem no mundo PvP). Retorna {ok, message} — nunca lança. Token inválido: 401 com {error: \"Invalid token or internal error\"}.",
        "operationId" : "apply",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/ApplyReferralRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/prelaunch" : {
      "post" : {
        "tags" : [ "pre-launch-controller" ],
        "summary" : "Pré-registro por e-mail (PvP Worlds)",
        "description" : "Captura o e-mail de quem não pode jogar agora (ex.: acessou pelo celular) pra mandar o link de download e avisar na abertura em 25/09/2026. Idempotente: e-mail já cadastrado retorna success=true sem regravar nem reenviar e-mail. Limitado a 5 requisições por hora por IP; ao exceder, retorna 200 com success=false e message=\"auth.errorTooManyRequests\".",
        "operationId" : "prelaunch",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/PreLaunchRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/PreLaunchResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/payment/paypal/webhook" : {
      "post" : {
        "tags" : [ "Payment" ],
        "summary" : "Webhook de eventos do PayPal",
        "description" : "Recebe eventos assíncronos do PayPal (compra aprovada, etc.), valida a assinatura via PayPalService#verifySignature e processa o evento de forma idempotente. Assinatura inválida: 401 (o PayPal não deve reenviar esse caso). Qualquer outro erro no processamento ainda responde 200 \"OK\" de propósito, pois a assinatura já foi validada e um reenvio do PayPal não ajudaria. Rota pública (sem JWT/X-Game-Key), autenticada só pela assinatura PayPal no corpo/headers.",
        "operationId" : "handleWebhook",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "string"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/payment/paypal/checkout" : {
      "post" : {
        "tags" : [ "Payment" ],
        "summary" : "Cria checkout PayPal para compra de coins",
        "description" : "Cria uma ordem PayPal para a quantidade de coins e mundo (\"craft\"/\"pvp\") informados em CheckoutRequestDTO, extraindo a conta do JWT. Retorna {checkoutUrl} com a URL de aprovação do PayPal para redirecionar o usuário.",
        "operationId" : "createCheckoutPaypal",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/CheckoutRequestDTO"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "string"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/payment/paypal/capture" : {
      "post" : {
        "tags" : [ "Payment" ],
        "summary" : "Captura (finaliza) uma ordem PayPal",
        "description" : "Captura no PayPal a ordem indicada pelo campo orderId do corpo, autenticando a conta via JWT. orderId ausente: 400 com o texto \"orderId obrigatório\". Retorna 200 sem corpo em sucesso.",
        "operationId" : "capturePaypalOrder",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "object",
                "additionalProperties" : {
                  "type" : "string"
                }
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/payment/mercadopago/webhook" : {
      "post" : {
        "tags" : [ "Payment" ],
        "summary" : "Webhook de eventos do Mercado Pago",
        "description" : "Recebe a notificação do Mercado Pago, valida a assinatura HMAC-SHA256 do header x-signature (ts/v1) contra o manifest \"id:<paymentId>;request-id:<x-request-id>;ts:<ts>;\" usando mercadopago.webhook.secret, e então processa o evento via MercadoPagoService#processWebhook. x-signature ausente/malformado: 400. Assinatura divergente: 401. Erro ao processar: 400 com a mensagem da exceção. Rota pública (sem JWT/X-Game-Key), autenticada só pela assinatura HMAC.",
        "operationId" : "handleWebhook_2",
        "parameters" : [ {
          "name" : "x-signature",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "x-request-id",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "string"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/payment/mercadopago/checkout" : {
      "post" : {
        "tags" : [ "Payment" ],
        "summary" : "Cria checkout Mercado Pago para compra de coins",
        "description" : "Cria uma preferência de pagamento no Mercado Pago para a quantidade de coins e mundo (\"craft\"/\"pvp\") informados em CheckoutRequestDTO, extraindo a conta do JWT. Retorna {checkoutUrl} com a URL do checkout do Mercado Pago.",
        "operationId" : "createCheckoutMercadoPago",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/CheckoutRequestDTO"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "string"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/news" : {
      "get" : {
        "tags" : [ "News" ],
        "summary" : "Lista notícias de um mundo (ou de todos, se omitido)",
        "description" : "Retorna todas as notícias do mundo informado (\"craft\"/\"pvp\", via NewsWorld.fromParam) ou de todos os mundos se o parâmetro for omitido. Se o banco do mundo estiver indisponível, retorna 503 com {error: \"news.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "all",
        "parameters" : [ {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = todos os mundos",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post" : {
        "tags" : [ "News" ],
        "summary" : "Cria uma notícia",
        "description" : "Salva uma nova notícia (corpo News, incluindo seu campo world). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com {error: \"invalid game key\"}.",
        "operationId" : "create",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/News"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/game/send-coins" : {
      "post" : {
        "tags" : [ "Game" ],
        "summary" : "Envia coins do saldo da conta para um personagem",
        "description" : "Extrai o username do JWT (header Authorization) e credita item id 6673 (quantidade de SendCoinsRequest.amount) no inventário de um personagem OFFLINE da própria conta logada (SendCoinsRequest.charName), debitando o mesmo valor do saldo (balance) da conta. O personagem precisa já ter esse item no inventário (não cria linha nova). Erros tratados pelo GlobalExceptionHandler: personagem/conta inexistente = 404 (NOT_FOUND); saldo insuficiente = 400 (INSUFFICIENT_BALANCE); personagem online = 406 (CHAR_ONLINE); item não encontrado no inventário do personagem = 410 (INVENTORY_ITEM_NOT_FOUND, e o débito do saldo é revertido); quantidade <= 0 não tem handler dedicado e cai como 500 (SERVER_ERROR). Retorna 200 com o texto \"Coins sent successfully\" em sucesso.",
        "operationId" : "sendCoins",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/SendCoinsRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/game/packs/claim" : {
      "post" : {
        "tags" : [ "Game Packs" ],
        "summary" : "Confirma entrega de um pack (gameserver)",
        "description" : "Marca o entitlement (username + entitlementId + charId de GameClaimPackRequestDTO) como entregue e retorna os dados que o gameserver precisa para conceder os itens: {entitlementId, packType, diamondDays, randomHair, randomSkin, items[{itemId, quantity}]}. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, lança IllegalArgumentException (ou IllegalStateException se game.api-key não estiver configurado), sem tratamento específico no GlobalExceptionHandler — cai no handler genérico e responde 500 (SERVER_ERROR).",
        "operationId" : "claim",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/GameClaimPackRequestDTO"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/diagnostic/charinfo" : {
      "post" : {
        "tags" : [ "Diagnostic" ],
        "summary" : "Registra snapshot de CharInfo",
        "description" : "Persiste um snapshot de aparência do personagem (paperdoll, augment, enchant, máscara de abnormal, hero/noble/cw) enviado pelo gameserver quando diagnostic_config.charinfo_dump_enabled=TRUE, para reconstruir como um jogador estava vestido no momento em que outro cliente travou. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401. Payload inválido: 400. Retorna {status, id}.",
        "operationId" : "ingestCharInfo",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "object",
                "additionalProperties" : { }
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/dashboard/change-password" : {
      "post" : {
        "tags" : [ "Dashboard" ],
        "summary" : "Troca a senha da conta logada",
        "description" : "Extrai o username do JWT (header Authorization) e troca a senha da conta a partir do corpo (payload livre, validado por DashboardService#changePassword). Retorna {message: \"dashboard.successPasswordChanged\"} em sucesso. Payload inválido: 400 com a mensagem da validação; falha de autorização (ex.: senha atual incorreta): 401.",
        "operationId" : "changePassword",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "object",
                "additionalProperties" : {
                  "type" : "string"
                }
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/crash/report" : {
      "post" : {
        "tags" : [ "Crash" ],
        "summary" : "Registra tail de log de um crash",
        "description" : "Persiste o tail de system/l2.log (campo logTail, cortado nos últimos 200000 caracteres) enviado após um fechamento anormal do cliente, além de dados de HWID/IP. Extrai automaticamente o \"culpritAsset\" (última linha \"Loading:\"/\"NotifyLoad\" antes do crash). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401. logTail ausente/vazio ou payload inválido: 400. Authorization é opcional, para vincular o evento a uma conta. Retorna {status, id, culprit}.",
        "operationId" : "report",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "Authorization",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "object",
                "additionalProperties" : { }
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/crash/bundle" : {
      "post" : {
        "tags" : [ "Crash" ],
        "summary" : "Recebe bundle completo de crash",
        "description" : "Recebe um zip (multipart, campo \"bundle\") com system/l2.log + contexto do crash e o salva em disco, em dumpDir/<identificador>/crash_<timestamp>_exit<exitCode>.zip. Não grava linha no banco (CrashReport), de propósito: fica isolado do pipeline leve de /report. O identificador vem do JWT (se Authorization presente e válido) ou do HWID (hwidCpu/hwidHdd/hwidMac). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401. Bundle ausente/vazio ou payload inválido: 400. Retorna {status, path}.",
        "operationId" : "bundle",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "Authorization",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "exitCode",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 0
          }
        }, {
          "name" : "pid",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        }, {
          "name" : "hwidCpu",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "hwidHdd",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "hwidMac",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "wine",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "boolean",
            "default" : false
          }
        }, {
          "name" : "markerHit",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "timestamp",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "multipart/form-data" : {
              "schema" : {
                "type" : "object",
                "properties" : {
                  "bundle" : {
                    "type" : "string",
                    "format" : "binary",
                    "description" : "Arquivo zip com log + contexto do crash"
                  }
                },
                "required" : [ "bundle" ]
              }
            }
          }
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/craft/prelaunch" : {
      "post" : {
        "tags" : [ "craft-pre-launch-controller" ],
        "summary" : "Pré-registro por e-mail (Nova Season do Craft Retail)",
        "description" : "Captura o e-mail de quem quer ser avisado da abertura da Nova Season (16/10/2026, 19h de Brasília). Idempotente: e-mail já cadastrado retorna success=true sem regravar nem reenviar e-mail. Limitado a 5 requisições por hora por IP; ao exceder, retorna 200 com success=false e message=\"auth.errorTooManyRequests\".",
        "operationId" : "prelaunch_2",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/PreLaunchRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/PreLaunchResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/client-logs/sync" : {
      "post" : {
        "tags" : [ "Client Logs" ],
        "summary" : "Sincroniza delta do log do cliente",
        "description" : "Recebe um zip (multipart, campo \"bundle\") com o delta de system/l2.log desde o último sync e o salva em disco, em syncDir/<identificador>/<dia UTC>/sync_<timestamp>.zip. O identificador é resolvido a partir do JWT (se Authorization presente e válido) ou do HWID (hwidCpu/hwidHdd/hwidMac); sem eles, é rejeitado. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, 401. Bundle ausente/vazio ou payload inválido: 400. Retorna {status, path} em caso de sucesso.",
        "operationId" : "sync",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "Authorization",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "reason",
          "in" : "query",
          "description" : "Motivo do sync (ex.: \"periodic\", \"startup\")",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "periodic"
          }
        }, {
          "name" : "hwidCpu",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "hwidHdd",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "hwidMac",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "wine",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "boolean",
            "default" : false
          }
        }, {
          "name" : "sessionId",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "timestamp",
          "in" : "query",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "multipart/form-data" : {
              "schema" : {
                "type" : "object",
                "properties" : {
                  "bundle" : {
                    "type" : "string",
                    "format" : "binary",
                    "description" : "Arquivo zip com o delta do log"
                  }
                },
                "required" : [ "bundle" ]
              }
            }
          }
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/unsubscribe" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Cancela e-mails de campanha",
        "description" : "Remove o e-mail informado da lista de campanhas de marketing (e-mails transacionais de conta/senha continuam sendo enviados). Retorna uma página HTML de confirmação ou de erro (text/html), conforme o e-mail exista ou não na base.",
        "operationId" : "unsubscribe",
        "parameters" : [ {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail a remover da lista de campanhas",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "text/html;charset=UTF-8" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post" : {
        "tags" : [ "Auth" ],
        "summary" : "Cancela e-mails de campanha (One-Click, RFC 8058)",
        "description" : "Operação unsubscribeOneClick em /api/auth/unsubscribe. Consulte https://l2mog.com/developers.",
        "operationId" : "unsubscribeOneClick",
        "parameters" : [ {
          "name" : "email",
          "in" : "query",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "text/plain;charset=UTF-8" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/register" : {
      "post" : {
        "tags" : [ "Auth" ],
        "summary" : "Cria uma nova conta",
        "description" : "Registra login+senha (AuthRequest) e dispara um e-mail de boas-vindas. Limitado a 5 requisições por hora por IP para evitar spam do relay de e-mail; ao exceder, retorna 200 com success=false e message=\"auth.errorTooManyRequests\" em vez do registro real.",
        "operationId" : "register",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/AuthRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/login" : {
      "post" : {
        "tags" : [ "Auth" ],
        "summary" : "Login com usuário e senha",
        "description" : "Autentica login+senha e retorna um AuthResponse com o token JWT em caso de sucesso. Se o launcher estiver desatualizado, responde 403 com error=\"outdated_launcher\" para o launcher exibir o diálogo de download; demais falhas retornam 200 com success=false, por compatibilidade com clientes existentes.",
        "operationId" : "login",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/AuthRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/forgot-password" : {
      "post" : {
        "tags" : [ "Auth" ],
        "summary" : "Recupera senha por login",
        "description" : "Busca a conta pelo campo login do corpo (não pelo e-mail — um mesmo e-mail pode estar vinculado a vários logins), gera uma nova senha e a envia ao e-mail cadastrado naquela conta. Throttle de 8 req/15min por IP e 3 req/15min por login; ao exceder, retorna 200 com success=false e message=\"auth.errorTooManyRequests\".",
        "operationId" : "forgotPassword",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/AuthRequest"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/anticheat/report" : {
      "post" : {
        "tags" : [ "AntiCheat" ],
        "summary" : "Registra evento de anticheat/diagnóstico",
        "description" : "Persiste um evento vindo do launcher: diagnóstico de estado (reason prefixado com \"[DIAG]\", salvo com severity=diag) ou detecção real de cheat (severity=detect). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. O header Authorization é opcional — quando presente e válido, o login do JWT é gravado no evento para vincular a um jogador; se ausente/inválido, o evento é gravado sem account_login. Retorna {status, id} em caso de sucesso.",
        "operationId" : "report_2",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "Authorization",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "type" : "object",
                "additionalProperties" : { }
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/vote/top100arena" : {
      "get" : {
        "tags" : [ "Vote" ],
        "summary" : "Recebe postback de voto do Top100Arena",
        "description" : "Registra um voto para o playerId extraído de postback (prefixo \"P\" = mundo pvp, numérico puro = mundo craft), com o mundo explícito no parâmetro world (se presente) tendo prioridade sobre o prefixo. Exige secret igual a vote.top100arena.secret; sem ele ou incorreto, retorna 403 com o texto \"Invalid secret key\" (não usa X-Game-Key/JWT). postback ausente/formato inválido: 400. Retorna 200 com texto de confirmação em sucesso, ou 500 se o registro do voto falhar.",
        "operationId" : "receiveVote",
        "parameters" : [ {
          "name" : "postback",
          "in" : "query",
          "description" : "Id do jogador; prefixo \"P\" = mundo pvp, numérico puro = mundo craft",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "secret",
          "in" : "query",
          "description" : "Chave secreta compartilhada com o Top100Arena",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); tem prioridade sobre o prefixo de postback",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/store/packs" : {
      "get" : {
        "tags" : [ "Store" ],
        "summary" : "Lista o catálogo de packs da loja",
        "description" : "Retorna o catálogo de packs disponíveis para a conta do JWT, no mundo pedido: \"pvp\" usa PvpStorePackService; qualquer outro valor (inclusive omitido) cai no craft (StorePackService), comportamento pré-existente antes do suporte a múltiplos mundos.",
        "operationId" : "listPacks",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = craft",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/StorePackDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/server/status" : {
      "get" : {
        "tags" : [ "Server" ],
        "summary" : "Status do servidor (online/offline, players, rates)",
        "description" : "Retorna o status público do servidor (nome, status online/offline, quantidade de players conectados), via ServerService#status. Rota pública, sem autenticação.",
        "operationId" : "status",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ServerStatusDTO"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/server/config-summary" : {
      "get" : {
        "tags" : [ "Server" ],
        "summary" : "Resumo público das configurações do servidor",
        "description" : "Retorna um resumo público das configurações do servidor (ex.: rates de XP/SP/drop, versão do cliente), via ServerConfigSummaryService#getSummary. Rota pública, sem autenticação.",
        "operationId" : "configSummary",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ServerConfigSummaryDTO"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/raidbosses" : {
      "get" : {
        "tags" : [ "Raid Bosses" ],
        "summary" : "Lista status dos raid bosses, com filtro por vivo/morto e busca por nome",
        "description" : "Retorna o status público dos raid bosses do mundo craft (vivo/morto, horário estimado de respawn), filtrando por filter (\"all\"/\"alive\"/\"dead\") e busca opcional por nome (q). Rota pública, sem autenticação.",
        "operationId" : "list",
        "parameters" : [ {
          "name" : "filter",
          "in" : "query",
          "description" : "Filtro: \"all\", \"alive\" ou \"dead\"",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "all"
          }
        }, {
          "name" : "q",
          "in" : "query",
          "description" : "Busca por nome do boss",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/RaidBossStatusDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/status" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Status do mundo PvP (online/offline, players)",
        "description" : "Consulta via JDBC direto no MariaDB da l2mog-stage (PvpWorldQueryService) o status do mundo 2 (Mid PvP). Banco indisponível: 503 com {error: \"pvp.status.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "status_2",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/referral/validate" : {
      "get" : {
        "tags" : [ "Referral" ],
        "summary" : "Valida um código de indicação",
        "description" : "Consulta se o código existe e retorna o nome de exibição (personagem de maior level) do dono do código — NUNCA o login. Rota pública, com rate limit de 20 req/min por IP; ao exceder, retorna 429 com {valid: false, referrerName: null}.",
        "operationId" : "validate",
        "parameters" : [ {
          "name" : "code",
          "in" : "query",
          "description" : "Código de 8 caracteres do link de indicação",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/referral/ranking" : {
      "get" : {
        "tags" : [ "Referral" ],
        "summary" : "Ranking do programa de indicação",
        "description" : "Top 20 indicadores do mundo PvP, ordenado por conversões (marco M2) e depois por indicados, com o nome de exibição (personagem de maior level) de cada um. Rota pública, sem autenticação.",
        "operationId" : "ranking",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/referral/me" : {
      "get" : {
        "tags" : [ "Referral" ],
        "summary" : "Dados de indicação da conta logada",
        "description" : "Extrai o login do JWT e retorna o código de indicação (gerado na primeira chamada), link, elegibilidade do indicador e contadores/últimas indicações. Se o banco do mundo PvP estiver indisponível, retorna eligible=false e contadores zero em vez de 500. Token inválido: 401 com {error: \"Invalid token or internal error\"}.",
        "operationId" : "me",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/ranking" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Ranking geral do mundo PvP",
        "description" : "Retorna o ranking geral de personagens do mundo 2 (Mid PvP), via PvpWorldQueryService#getRanking. Banco indisponível: 503 com {error: \"pvp.ranking.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "ranking_2",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/ranking/power" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Ranking de poder do mundo PvP",
        "description" : "Retorna o ranking de \"poder\" do mundo 2 (Mid PvP), via PvpWorldRankingService#getPowerRanking. Banco indisponível: 503 com {error: \"pvp.ranking.power.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "rankingPower",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/ranking/heroes" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Lista heróis do mundo PvP",
        "description" : "Retorna os heróis atuais do mundo 2 (Mid PvP), via PvpWorldRankingService#getHeroes. Banco indisponível: 503 com {error: \"pvp.ranking.heroes.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "rankingHeroes",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/ranking/clans" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Ranking de clãs do mundo PvP",
        "description" : "Retorna o ranking de clãs do mundo 2 (Mid PvP), via PvpWorldRankingService#getClanRankings. Banco indisponível: 503 com {error: \"pvp.ranking.clans.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "rankingClans",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/raidbosses" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Lista raid bosses do mundo PvP",
        "description" : "Retorna os raid bosses do mundo 2 (Mid PvP), com filtro por vivo/morto (filter: \"all\"/\"alive\"/\"dead\"), busca por nome (q) e grade (grade), via PvpRaidBossService#list. Banco indisponível: 503 com {error: \"pvp.raidbosses.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "raidBosses",
        "parameters" : [ {
          "name" : "filter",
          "in" : "query",
          "description" : "Filtro: \"all\", \"alive\" ou \"dead\"",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "all"
          }
        }, {
          "name" : "q",
          "in" : "query",
          "description" : "Busca por nome do boss",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "grade",
          "in" : "query",
          "description" : "Filtra por grade do boss",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/prelaunch/send-opening" : {
      "get" : {
        "tags" : [ "pre-launch-controller" ],
        "summary" : "Dispara campanha de abertura para leads de pré-registro (admin)",
        "description" : "Envia, em background (thread separada), o e-mail de abertura (25/09/2026, 19h de Brasília) para leads de pré-registro que ainda não o receberam (fila separada da confirmação — ver PreLaunchLeadRepository). Por padrão respeita o teto diário sorteado em l2mog.prelaunch.opening-daily-limit-min/max; o parâmetro opcional limit substitui esse teto só para este disparo — o lote deve respeitar o teto do provedor (Brevo free tier = 300/dia, compartilhado com as outras campanhas). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendOpeningEmails",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Substitui o teto diário sorteado por esse valor exato só neste disparo (respeitar o teto do provedor, 300/dia no Brevo free)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/prelaunch/send-opening-test" : {
      "get" : {
        "tags" : [ "pre-launch-controller" ],
        "summary" : "Testa e-mail de abertura para pré-registro (admin)",
        "description" : "Envia o e-mail de abertura (25/09/2026, 19h de Brasília) de forma síncrona para um único endereço (email, lang), para teste manual antes de disparar a campanha em massa. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendOpeningEmailTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, es)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/prelaunch/grants" : {
      "get" : {
        "tags" : [ "pre-launch-controller" ],
        "summary" : "Conferência do bônus de pré-registro (admin)",
        "description" : "Quantos direitos de premium do bônus \"200 primeiros\" foram concedidos (pvpw_prelaunch_grant, banco do mundo 2), quantos já foram entregues pelo gameserver (granted_at não nulo) e quantas vagas restam do limite configurado (l2mog.prelaunch.grant-limit). É como o dono confere no dia 25/09/2026. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401.",
        "operationId" : "grants",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/prelaunch/grants/sync" : {
      "get" : {
        "tags" : [ "pre-launch-controller" ],
        "summary" : "Sincroniza retroativamente o bônus de pré-registro (admin)",
        "description" : "Cruza os leads de pré-registro mais antigos (limite l2mog.prelaunch.grant-limit) com contas JÁ EXISTENTES cujo e-mail bate (case-insensitive) e concede o direito que faltar — para contas criadas antes desta feature existir. Idempotente, pode rodar quantas vezes precisar antes da abertura. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401.",
        "operationId" : "syncGrants",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/events/tvt/weeks" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Semanas com ranking TVT disponível no mundo PvP",
        "description" : "Retorna as semanas com ranking de TVT disponível no mundo 2 (Mid PvP), via PvpWorldRankingService#getTvtWeeks. Banco indisponível: 503 com {error: \"pvp.events.tvt.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "tvtWeeks",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/events/tvt/weekly" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Top 20 de kills do TVT semanal no mundo PvP",
        "description" : "Retorna o top 20 de kills do TVT na semana informada (weekStart), no mundo 2 (Mid PvP), via PvpWorldRankingService#getTvtTop20. Banco indisponível: 503 com {error: \"pvp.events.tvt.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "tvtWeekly",
        "parameters" : [ {
          "name" : "weekStart",
          "in" : "query",
          "description" : "Data de início da semana (ver GET /pvp/events/tvt/weeks)",
          "required" : true,
          "schema" : {
            "type" : "string",
            "format" : "date"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pvp/dashboard" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Dashboard da conta no mundo PvP",
        "description" : "Extrai o username do JWT (header Authorization) e retorna o dashboard da conta no mundo 2 (Mid PvP), via PvpWorldQueryService#getDashboardForAccount. Token inválido ou erro interno: 401 com {error: \"Invalid token or internal error\"}.",
        "operationId" : "dashboard",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/pvp/castles" : {
      "get" : {
        "tags" : [ "PvP Worlds" ],
        "summary" : "Estado dos castelos no mundo PvP",
        "description" : "Retorna o estado dos castelos do mundo 2 (Mid PvP), via PvpWorldRankingService#getCastles. Banco indisponível: 503 com {error: \"pvp.castles.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "castles",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/players/ranking" : {
      "get" : {
        "tags" : [ "Players" ],
        "summary" : "Todos os rankings de personagens (PvP, PK, nível, etc.)",
        "description" : "Retorna, num único mapa, os rankings públicos de personagens do mundo craft em 5 categorias: \"pvp\" (mais PvP), \"pk\" (mais PK), \"exp\" (maior nível/experiência), \"adena\" (mais adena) e \"coin\" (mais MOG Coins). Rota pública, sem autenticação.",
        "operationId" : "getAllRankings",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : { }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/npc-respawn" : {
      "get" : {
        "tags" : [ "NPC Respawn" ],
        "summary" : "Resumo de respawn de grand bosses",
        "description" : "Retorna {\"all\": [...]} com todos os registros de respawn de grand bosses/NPCs especiais monitorados (GrandBossRespawnTimeRepository#findAllRespawns). Rota pública, sem autenticação.",
        "operationId" : "getRespawnData",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : { }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/news/latest" : {
      "get" : {
        "tags" : [ "News" ],
        "summary" : "As últimas notícias de um mundo (ou de todos, se omitido)",
        "description" : "Retorna as notícias mais recentes do mundo informado (\"craft\"/\"pvp\") ou de todos os mundos se omitido. Se o banco do mundo estiver indisponível, retorna 503 com {error: \"news.unavailable\"}. Rota pública, sem autenticação.",
        "operationId" : "latest",
        "parameters" : [ {
          "name" : "world",
          "in" : "query",
          "description" : "Mundo (\"craft\" ou \"pvp\"); omitido = todos os mundos",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/home" : {
      "get" : {
        "tags" : [ "Home" ],
        "summary" : "Status do servidor + últimas notícias, num único payload",
        "description" : "Combina, numa única chamada, ServerService#status() (serverStatus, ex.: {status, version}) e NewsService#latest() (latestNews, as últimas 5 notícias do banco). Pensado para reduzir round-trips da home do site. Rota pública, sem autenticação.",
        "operationId" : "home",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/HomeResponse"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/game/packs/pending" : {
      "get" : {
        "tags" : [ "Game Packs" ],
        "summary" : "Lista packs pendentes de entrega (gameserver)",
        "description" : "Retorna os pack entitlements da conta ainda não entregues (pendentes), cada um com {id, packType, packCode, packName}, para o gameserver entregar os itens ao personagem. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, lança IllegalArgumentException (ou IllegalStateException se game.api-key não estiver configurado), sem tratamento específico no GlobalExceptionHandler — cai no handler genérico e responde 500 (SERVER_ERROR).",
        "operationId" : "pending",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "username",
          "in" : "query",
          "description" : "Login da conta",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "type" : "object",
                    "additionalProperties" : { }
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/events/tvt/weeks" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Semanas com ranking TVT disponível",
        "description" : "Retorna as datas (início de semana) para as quais existe ranking semanal de kills de TVT registrado, para popular um seletor de semana no site. Rota pública, sem autenticação.",
        "operationId" : "getTvtWeeks",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "type" : "string",
                    "format" : "date"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/tvt/weekly" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Top 20 de kills do TVT semanal",
        "description" : "Retorna o top 20 de kills do evento TVT na semana informada (weekStart = data de início da semana, uma das datas de GET /events/tvt/weeks). Rota pública, sem autenticação.",
        "operationId" : "getTvtWeeklyRanking",
        "parameters" : [ {
          "name" : "weekStart",
          "in" : "query",
          "description" : "Data de início da semana (ver GET /events/tvt/weeks)",
          "required" : true,
          "schema" : {
            "type" : "string",
            "format" : "date"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/TvtWeeklyRankingDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/pvp5v5" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Ranking global do evento 5v5",
        "description" : "Retorna o ranking global (todos os tempos) do evento PvP 5v5. Rota pública, sem autenticação.",
        "operationId" : "getRanking1v1",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/Event5v5RankingDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/pvp2v2" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Ranking global do evento 2v2",
        "description" : "Retorna o ranking global (todos os tempos) do evento PvP 2v2. Rota pública, sem autenticação.",
        "operationId" : "getRanking2v2",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/Event2v2RankingDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/heroes" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Lista heróis ativos",
        "description" : "Retorna os personagens que estão como Hero ativo no ciclo atual (Seven Signs / Olympiad hero). Rota pública, sem autenticação.",
        "operationId" : "getHeroes",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/HeroDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events/ffa" : {
      "get" : {
        "tags" : [ "Events" ],
        "summary" : "Ranking global do evento Free-for-All",
        "description" : "Retorna o ranking global (todos os tempos) do evento Free-for-All. Rota pública, sem autenticação.",
        "operationId" : "getRankingFfa",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/FreeForAllRankingDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/diagnostic/charinfo/recent" : {
      "get" : {
        "tags" : [ "Diagnostic" ],
        "summary" : "Lista snapshots recentes de CharInfo (admin)",
        "description" : "Retorna os snapshots de CharInfo mais recentes, com filtro opcional por objId (tem prioridade) ou name. Restrito a contas GM (access_level > 0); sem isso, 403. Requer Authorization: Bearer <JWT>.",
        "operationId" : "recent",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "name",
          "in" : "query",
          "description" : "Filtra por nome do personagem (omitido = todos)",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "objId",
          "in" : "query",
          "description" : "Filtra por object_id do personagem (tem prioridade sobre name)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Máximo de registros (capado em 1000)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 100
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/dashboard" : {
      "get" : {
        "tags" : [ "Dashboard" ],
        "summary" : "Dados do dashboard da conta",
        "description" : "Extrai o username do JWT (header Authorization) e retorna os dados de dashboard da conta (DashboardService#getDashboardData). Token inválido ou erro interno: 401 com {error: \"Invalid token or internal error\"}.",
        "operationId" : "getDashboardInfo",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/crash/top-culprits" : {
      "get" : {
        "tags" : [ "Crash" ],
        "summary" : "Top culpritAsset por nº de crashes (admin)",
        "description" : "Retorna os assets (mesh/textura/som) que mais aparecem como culpritAsset em CrashReport, agregados por contagem de ocorrências e ordenados decrescente. Cada item traz {asset, hits}. Restrito a contas GM (access_level > 0); sem isso, 403. Requer Authorization: Bearer <JWT>.",
        "operationId" : "topCulprits",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Máximo de assets retornados (capado em 200)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 20
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/crash/recent" : {
      "get" : {
        "tags" : [ "Crash" ],
        "summary" : "Lista crash reports recentes (admin)",
        "description" : "Retorna os CrashReport mais recentes, com filtro opcional por culpritAsset. Restrito a contas GM (access_level > 0); sem isso, 403. Requer Authorization: Bearer <JWT>.",
        "operationId" : "recent_2",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "culprit",
          "in" : "query",
          "description" : "Filtra por culpritAsset (omitido = todos)",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Máximo de registros (capado em 500)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 100
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/craft/prelaunch/send-opening" : {
      "get" : {
        "tags" : [ "craft-pre-launch-controller" ],
        "summary" : "Dispara campanha de abertura para leads de pré-registro do Craft (admin)",
        "description" : "Envia, em background (thread separada), o e-mail de abertura (16/10/2026, 19h de Brasília) para leads de pré-registro do Craft que ainda não o receberam (fila separada da confirmação — ver CraftPreLaunchLeadRepository). Por padrão respeita o teto diário sorteado em l2mog.craft-prelaunch.opening-daily-limit-min/max; o parâmetro opcional limit substitui esse teto só para este disparo — o lote deve respeitar o teto do provedor (Brevo free tier = 300/dia, compartilhado com as outras campanhas, inclusive a do PvP Worlds). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendOpeningEmails_2",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Substitui o teto diário sorteado por esse valor exato só neste disparo (respeitar o teto do provedor, 300/dia no Brevo free)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/craft/prelaunch/send-opening-test" : {
      "get" : {
        "tags" : [ "craft-pre-launch-controller" ],
        "summary" : "Testa e-mail de abertura para pré-registro do Craft (admin)",
        "description" : "Envia o e-mail de abertura (16/10/2026, 19h de Brasília) de forma síncrona para um único endereço (email, lang), para teste manual antes de disparar a campanha em massa. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendOpeningEmailTest_2",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, es)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/craft/prelaunch/grants" : {
      "get" : {
        "tags" : [ "craft-pre-launch-controller" ],
        "summary" : "Conferência do bônus de pré-registro do Craft (admin)",
        "description" : "Quantos direitos de premium do bônus \"200 primeiros\" foram concedidos (craft_prelaunch_grant, banco do craft), quantos já foram entregues pelo gameserver (granted_at não nulo) e quantas vagas restam do limite configurado (l2mog.craft-prelaunch.grant-limit). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401.",
        "operationId" : "grants_2",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/craft/prelaunch/grants/sync" : {
      "get" : {
        "tags" : [ "craft-pre-launch-controller" ],
        "summary" : "Sincroniza retroativamente o bônus de pré-registro do Craft (admin)",
        "description" : "Reconcede aos leads de pré-registro do Craft mais antigos (limite l2mog.craft-prelaunch.grant-limit) que ainda não têm linha em craft_prelaunch_grant — útil se o limite mudar de valor depois que leads antigos já se registraram. Idempotente, pode rodar quantas vezes precisar. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401.",
        "operationId" : "syncGrants_2",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/community" : {
      "get" : {
        "tags" : [ "Community" ],
        "summary" : "Lista links de comunidade",
        "description" : "Retorna a lista de links de comunidade (cada item um mapa chave/valor, ex.: label + url). \"/api/community\" não está na lista permitAll da SecurityConfig, então esta rota exige Authorization: Bearer <JWT> válido (a Spring Security autentica antes do controller, que não usa o token além de exigir sua presença).",
        "operationId" : "links",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "type" : "object",
                    "additionalProperties" : {
                      "type" : "string"
                    }
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/clans/ranking" : {
      "get" : {
        "tags" : [ "Clans" ],
        "summary" : "Ranking de clãs",
        "description" : "Retorna o ranking público de clãs em 4 categorias, cada chave com sua lista de ClanRankingDTO: \"pvp\" (mais PvP), \"pk\" (mais PK), \"active\" (clãs mais ativos, por membros e experiência) e \"level\" (maior nível de clã). Rota pública, sem autenticação.",
        "operationId" : "getClanRankings",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "array",
                    "items" : {
                      "$ref" : "#/components/schemas/ClanRankingDTO"
                    }
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/castles" : {
      "get" : {
        "tags" : [ "Castles" ],
        "summary" : "Lista todos os castelos",
        "description" : "Retorna o estado público de todos os castelos: nome, clã dono (se houver), e se há cerco agendado/em andamento. Rota pública, sem autenticação.",
        "operationId" : "getAll",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "array",
                  "items" : {
                    "$ref" : "#/components/schemas/CastleDTO"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/time" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Hora atual do servidor",
        "description" : "Retorna o horário atual do servidor em segundos Unix ({\"unix\": <epoch>}). Usado pelo launcher para alinhar o timestamp do HWID com o servidor, compensando relógio incorreto do cliente.",
        "operationId" : "time",
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object",
                  "additionalProperties" : {
                    "type" : "integer",
                    "format" : "int64"
                  }
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/send-postlaunch" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Dispara campanha pós-launch (admin)",
        "description" : "Envia, em background (thread separada), e-mail de campanha pós-launch para contas que ainda não a receberam. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendPostLaunchEmails",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-postlaunch-test" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Testa e-mail pós-launch (admin)",
        "description" : "Envia o e-mail de campanha pós-launch de forma síncrona para um único endereço (email, username, lang), para teste manual. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendPostLaunchTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "username",
          "in" : "query",
          "description" : "Nome exibido no template do e-mail",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "Guerreiro"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, ...)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-launch-dates" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Dispara campanha de datas de abertura (admin)",
        "description" : "Envia, em background (thread separada), e-mail de campanha 'datas de abertura' (PvP Worlds 25/09 + Craft Season 3 16/10) para contas que ainda não a receberam, ordenadas por last_active DESC (mais ativas primeiro). Por padrão respeita o teto diário sorteado em l2mog.email.campaigns.daily-limit-min/max; o parâmetro opcional limit substitui esse teto só para este disparo, para o dono escolher o tamanho do lote conscientemente sem mexer no yml — o lote deve respeitar o teto do provedor (Brevo free tier = 300/dia). Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendLaunchDatesEmails",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Substitui o teto diário sorteado por esse valor exato só neste disparo (respeitar o teto do provedor, 300/dia no Brevo free)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-launch-dates-test" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Testa e-mail de datas de abertura (admin)",
        "description" : "Envia o e-mail de campanha 'datas de abertura' (PvP Worlds 25/09 + Craft Season 3 16/10) de forma síncrona para um único endereço (email, username, lang), para teste manual. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendLaunchDatesTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "username",
          "in" : "query",
          "description" : "Nome exibido no template do e-mail",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "Guerreiro"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, ...)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-inauguration" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Dispara campanha de inauguração (admin)",
        "description" : "Envia, em background (thread separada), e-mail de campanha de inauguração para TODAS as contas cadastradas. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendInaugurationEmails",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-inauguration-test" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Testa e-mail de inauguração (admin)",
        "description" : "Envia o e-mail de campanha de inauguração de forma síncrona para um único endereço (email, username, lang), para teste manual. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendInaugurationTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "username",
          "in" : "query",
          "description" : "Nome exibido no template do e-mail",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "Guerreiro"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, ...)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-comeback" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Dispara campanha comeback (admin)",
        "description" : "Envia, em background (thread separada), e-mail de campanha 'comeback' para contas inativas há 7+ dias que ainda não a receberam. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401 com corpo texto \"invalid game key\".",
        "operationId" : "sendComeBackEmails",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-comeback-test" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Testa e-mail de comeback (admin)",
        "description" : "Envia o e-mail de campanha 'comeback' de forma síncrona para um único endereço (email, username, lang), para teste manual. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401. Em erro de envio, retorna 500 com a mensagem da exceção.",
        "operationId" : "sendComebackTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "username",
          "in" : "query",
          "description" : "Nome exibido no template do e-mail",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "Guerreiro"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, en, ...)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-clan-race" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Dispara a campanha Corrida dos Clãs (admin)",
        "description" : "Envia em background o e-mail da Corrida dos Clãs para o público deduplicado por e-mail (pré-registro PvP, contas por last_active DESC, pré-registro Craft), sem quem fez opt-out em qualquer lista e sem quem já recebeu (tabela email_campaign_send). Por padrão respeita o teto sorteado em l2mog.clan-race-email.daily-limit-min/max (30-50); limit substitui o teto só neste disparo. Recusa (409) se já houver disparo em andamento ou depois de l2mog.clan-race-email.send-until (padrão 25/09/2026 19h de Brasília). Exige X-Game-Key.",
        "operationId" : "send",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Tamanho exato do lote deste disparo (respeitar a cota do Brevo)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/send-clan-race-test" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Testa o e-mail da Corrida dos Clãs (admin)",
        "description" : "Envia de forma síncrona para UM endereço (email, lang pt/es/en), sem marcar nada no banco. Exige X-Game-Key; em erro de envio retorna 500 com a mensagem.",
        "operationId" : "sendTest",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "email",
          "in" : "query",
          "description" : "E-mail de destino do teste",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "lang",
          "in" : "query",
          "description" : "Idioma do template (pt, es, en)",
          "required" : false,
          "schema" : {
            "type" : "string",
            "default" : "pt"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/auth/clan-race-audience" : {
      "get" : {
        "tags" : [ "Auth" ],
        "summary" : "Público da campanha Corrida dos Clãs (admin)",
        "description" : "Só conta, não envia: candidatos das três listas (prelaunch_lead, accounts, craft_prelaunch_lead), inválidos, duplicados, opt-out, já enviados e pendentes. Exige X-Game-Key igual a game.api-key; sem ele ou incorreto, retorna 401.",
        "operationId" : "audience",
        "parameters" : [ {
          "name" : "X-Game-Key",
          "in" : "header",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "gameKey" : [ ]
        } ]
      }
    },
    "/api/v1/anticheat/recent" : {
      "get" : {
        "tags" : [ "AntiCheat" ],
        "summary" : "Lista eventos recentes de anticheat (admin)",
        "description" : "Retorna os eventos de anticheat mais recentes (id descendente), com filtro opcional por severity (\"diag\" ou \"detect\"). Restrito a contas GM (access_level > 0); sem isso, retorna 403. Requer Authorization: Bearer <JWT>.",
        "operationId" : "recent_3",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "severity",
          "in" : "query",
          "description" : "Filtro por severity: \"diag\" ou \"detect\" (omitido = todos)",
          "required" : false,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "limit",
          "in" : "query",
          "description" : "Máximo de registros (capado em 500)",
          "required" : false,
          "schema" : {
            "type" : "integer",
            "format" : "int32",
            "default" : 100
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    },
    "/api/v1/diagnostic/charinfo/older-than" : {
      "delete" : {
        "tags" : [ "Diagnostic" ],
        "summary" : "Apaga snapshots antigos de CharInfo (admin)",
        "description" : "Apaga em massa os snapshots de CharInfo criados há mais de \"hours\" horas (capado em 24*30 = 720h). Restrito a contas GM (access_level > 0); sem isso, 403. Requer Authorization: Bearer <JWT>. Retorna {status, deleted} com o total de linhas removidas.",
        "operationId" : "deleteOlderThan",
        "parameters" : [ {
          "name" : "Authorization",
          "in" : "header",
          "required" : true,
          "schema" : {
            "type" : "string"
          }
        }, {
          "name" : "hours",
          "in" : "query",
          "description" : "Idade mínima em horas para apagar (capado em 720)",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "OK",
            "headers" : {
              "API-Version" : {
                "$ref" : "#/components/headers/API-Version"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              },
              "RateLimit-Policy" : {
                "$ref" : "#/components/headers/RateLimit-Policy"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "object"
                }
              }
            }
          },
          "400" : {
            "description" : "Requisição inválida (corpo, parâmetro ou versão de API não suportada).",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401" : {
            "description" : "Autenticação necessária.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403" : {
            "description" : "Sem permissão para o recurso.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404" : {
            "description" : "Recurso ou rota não encontrado.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "405" : {
            "description" : "Método HTTP não suportado para este path.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429" : {
            "description" : "Limite de requisições excedido; veja Retry-After.",
            "headers" : {
              "Retry-After" : {
                "$ref" : "#/components/headers/Retry-After"
              },
              "RateLimit" : {
                "$ref" : "#/components/headers/RateLimit"
              }
            },
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500" : {
            "description" : "Erro inesperado no servidor.",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security" : [ {
          "bearerAuth" : [ ]
        } ]
      }
    }
  },
  "components" : {
    "schemas" : {
      "News" : {
        "type" : "object",
        "properties" : {
          "id" : {
            "type" : "integer",
            "format" : "int64"
          },
          "title" : {
            "type" : "string"
          },
          "content" : {
            "type" : "string"
          },
          "date" : {
            "type" : "string",
            "format" : "date-time"
          },
          "author" : {
            "type" : "string"
          },
          "category" : {
            "type" : "string"
          },
          "world" : {
            "type" : "string",
            "enum" : [ "CRAFT", "PVP" ]
          }
        }
      },
      "PackCheckoutRequestDTO" : {
        "type" : "object",
        "properties" : {
          "packType" : {
            "type" : "string",
            "enum" : [ "BRONZE", "SILVER", "GOLD" ]
          },
          "world" : {
            "type" : "string"
          }
        }
      },
      "ApplyReferralRequest" : {
        "type" : "object",
        "properties" : {
          "code" : {
            "type" : "string"
          }
        }
      },
      "PreLaunchRequest" : {
        "type" : "object",
        "properties" : {
          "email" : {
            "type" : "string"
          },
          "lang" : {
            "type" : "string"
          },
          "device" : {
            "type" : "string"
          },
          "utm_source" : {
            "type" : "string"
          },
          "utm_medium" : {
            "type" : "string"
          },
          "utm_campaign" : {
            "type" : "string"
          },
          "referrer_url" : {
            "type" : "string"
          },
          "landing_path" : {
            "type" : "string"
          }
        }
      },
      "PreLaunchResponse" : {
        "type" : "object",
        "properties" : {
          "success" : {
            "type" : "boolean"
          },
          "message" : {
            "type" : "string"
          }
        }
      },
      "CheckoutRequestDTO" : {
        "type" : "object",
        "properties" : {
          "coins" : {
            "type" : "integer",
            "format" : "int32"
          },
          "world" : {
            "type" : "string"
          }
        }
      },
      "SendCoinsRequest" : {
        "type" : "object",
        "properties" : {
          "charName" : {
            "type" : "string"
          },
          "amount" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "GameClaimPackRequestDTO" : {
        "type" : "object",
        "properties" : {
          "username" : {
            "type" : "string"
          },
          "entitlementId" : {
            "type" : "integer",
            "format" : "int64"
          },
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "AuthRequest" : {
        "type" : "object",
        "properties" : {
          "login" : {
            "type" : "string"
          },
          "password" : {
            "type" : "string"
          },
          "email" : {
            "type" : "string"
          },
          "ref" : {
            "type" : "string"
          },
          "launcher_version" : {
            "type" : "string"
          },
          "utm_source" : {
            "type" : "string"
          },
          "utm_medium" : {
            "type" : "string"
          },
          "utm_campaign" : {
            "type" : "string"
          },
          "utm_content" : {
            "type" : "string"
          },
          "utm_term" : {
            "type" : "string"
          },
          "referrer_url" : {
            "type" : "string"
          },
          "landing_path" : {
            "type" : "string"
          }
        }
      },
      "AuthResponse" : {
        "type" : "object",
        "properties" : {
          "success" : {
            "type" : "boolean"
          },
          "message" : {
            "type" : "string"
          },
          "login" : {
            "type" : "string"
          },
          "accessLevel" : {
            "type" : "integer",
            "format" : "int32"
          },
          "token" : {
            "type" : "string"
          },
          "error" : {
            "type" : "string"
          },
          "download_url" : {
            "type" : "string"
          }
        }
      },
      "Reward" : {
        "type" : "object",
        "properties" : {
          "itemId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "quantity" : {
            "type" : "integer",
            "format" : "int64"
          }
        }
      },
      "StorePackDTO" : {
        "type" : "object",
        "properties" : {
          "code" : {
            "type" : "string"
          },
          "type" : {
            "type" : "string",
            "enum" : [ "BRONZE", "SILVER", "GOLD" ]
          },
          "name" : {
            "type" : "string"
          },
          "priceCoins" : {
            "type" : "integer",
            "format" : "int32"
          },
          "diamondDays" : {
            "type" : "integer",
            "format" : "int32"
          },
          "randomHair" : {
            "type" : "boolean"
          },
          "randomSkin" : {
            "type" : "boolean"
          },
          "active" : {
            "type" : "boolean"
          },
          "alreadyBought" : {
            "type" : "boolean"
          },
          "rewards" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/Reward"
            }
          }
        }
      },
      "Rates" : {
        "type" : "object",
        "properties" : {
          "exp" : {
            "type" : "string"
          },
          "sp" : {
            "type" : "string"
          },
          "adena" : {
            "type" : "string"
          }
        }
      },
      "ServerStatusDTO" : {
        "type" : "object",
        "properties" : {
          "name" : {
            "type" : "string"
          },
          "status" : {
            "type" : "string"
          },
          "launchDate" : {
            "type" : "string"
          },
          "players" : {
            "type" : "integer",
            "format" : "int32"
          },
          "accounts" : {
            "type" : "integer",
            "format" : "int32"
          },
          "characters" : {
            "type" : "integer",
            "format" : "int32"
          },
          "rates" : {
            "$ref" : "#/components/schemas/Rates"
          }
        }
      },
      "Adena" : {
        "type" : "object",
        "properties" : {
          "mode" : {
            "type" : "string"
          },
          "fixedMult" : {
            "type" : "integer",
            "format" : "int32"
          },
          "levels" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/AdenaLevel"
            }
          }
        }
      },
      "AdenaLevel" : {
        "type" : "object",
        "properties" : {
          "minLevel" : {
            "type" : "integer",
            "format" : "int32"
          },
          "maxLevel" : {
            "type" : "integer",
            "format" : "int32"
          },
          "baseMult" : {
            "type" : "integer",
            "format" : "int32"
          },
          "enabled" : {
            "type" : "boolean"
          }
        }
      },
      "Enchant" : {
        "type" : "object",
        "properties" : {
          "safeMax" : {
            "type" : "integer",
            "format" : "int32"
          },
          "safeMaxFull" : {
            "type" : "integer",
            "format" : "int32"
          },
          "maxWeapon" : {
            "type" : "integer",
            "format" : "int32"
          },
          "maxArmor" : {
            "type" : "integer",
            "format" : "int32"
          },
          "chanceMagicWeapon" : {
            "type" : "number",
            "format" : "double"
          },
          "chanceMagicWeapon15Plus" : {
            "type" : "number",
            "format" : "double"
          },
          "chanceNonMagicWeapon" : {
            "type" : "number",
            "format" : "double"
          },
          "chanceNonMagicWeapon15Plus" : {
            "type" : "number",
            "format" : "double"
          },
          "chanceArmor" : {
            "type" : "number",
            "format" : "double"
          },
          "chanceArmorPlus" : {
            "type" : "number",
            "format" : "double"
          }
        }
      },
      "Premium" : {
        "type" : "object",
        "properties" : {
          "bonuses" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/PremiumBonus"
            }
          },
          "featureFlags" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/PremiumFeatureFlag"
            }
          },
          "shopOffers" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/PremiumShopOffer"
            }
          },
          "eventBonuses" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/PremiumEventBonus"
            }
          }
        }
      },
      "PremiumBonus" : {
        "type" : "object",
        "properties" : {
          "tier" : {
            "type" : "string"
          },
          "expMult" : {
            "type" : "number",
            "format" : "double"
          },
          "spMult" : {
            "type" : "number",
            "format" : "double"
          },
          "adenaMult" : {
            "type" : "number",
            "format" : "double"
          },
          "adenaAdd" : {
            "type" : "integer",
            "format" : "int32"
          },
          "dropMult" : {
            "type" : "number",
            "format" : "double"
          },
          "spoilMult" : {
            "type" : "number",
            "format" : "double"
          },
          "questChanceMult" : {
            "type" : "number",
            "format" : "double"
          },
          "questAmountMult" : {
            "type" : "number",
            "format" : "double"
          }
        }
      },
      "PremiumEventBonus" : {
        "type" : "object",
        "properties" : {
          "eventKey" : {
            "type" : "string"
          },
          "tier" : {
            "type" : "string"
          },
          "rewardItemId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "rewardItemName" : {
            "type" : "string"
          },
          "rewardCount" : {
            "type" : "integer",
            "format" : "int32"
          },
          "chance" : {
            "type" : "number",
            "format" : "double"
          },
          "enabled" : {
            "type" : "boolean"
          }
        }
      },
      "PremiumFeatureFlag" : {
        "type" : "object",
        "properties" : {
          "featureKey" : {
            "type" : "string"
          },
          "minTier" : {
            "type" : "string"
          },
          "enabled" : {
            "type" : "boolean"
          }
        }
      },
      "PremiumShopOffer" : {
        "type" : "object",
        "properties" : {
          "source" : {
            "type" : "string"
          },
          "tier" : {
            "type" : "string"
          },
          "days" : {
            "type" : "integer",
            "format" : "int32"
          },
          "currencyItemId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "currencyItemName" : {
            "type" : "string"
          },
          "cost" : {
            "type" : "integer",
            "format" : "int32"
          },
          "enabled" : {
            "type" : "boolean"
          },
          "sortOrder" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "ServerConfigSummaryDTO" : {
        "type" : "object",
        "properties" : {
          "generatedAtUtc" : {
            "type" : "string"
          },
          "rates" : {
            "$ref" : "#/components/schemas/Rates"
          },
          "enchant" : {
            "$ref" : "#/components/schemas/Enchant"
          },
          "adena" : {
            "$ref" : "#/components/schemas/Adena"
          },
          "premium" : {
            "$ref" : "#/components/schemas/Premium"
          }
        }
      },
      "RaidBossStatusDTO" : {
        "type" : "object",
        "properties" : {
          "npcId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "name" : {
            "type" : "string"
          },
          "level" : {
            "type" : "integer",
            "format" : "int32"
          },
          "status" : {
            "type" : "integer",
            "format" : "int32"
          },
          "respawnTime" : {
            "type" : "integer",
            "format" : "int64"
          },
          "locX" : {
            "type" : "integer",
            "format" : "int32"
          },
          "locY" : {
            "type" : "integer",
            "format" : "int32"
          },
          "locZ" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "HomeResponse" : {
        "type" : "object",
        "properties" : {
          "serverStatus" : {
            "$ref" : "#/components/schemas/ServerStatusDTO"
          },
          "latestNews" : {
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/News"
            }
          }
        }
      },
      "TvtWeeklyRankingDTO" : {
        "type" : "object",
        "properties" : {
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "charName" : {
            "type" : "string"
          },
          "weekStart" : {
            "type" : "string",
            "format" : "date"
          },
          "kills" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "Event5v5RankingDTO" : {
        "type" : "object",
        "properties" : {
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "charName" : {
            "type" : "string"
          },
          "totalFights" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalWins" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalPoints" : {
            "type" : "integer",
            "format" : "int64"
          }
        }
      },
      "Event2v2RankingDTO" : {
        "type" : "object",
        "properties" : {
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "charName" : {
            "type" : "string"
          },
          "totalFights" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalWins" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalPoints" : {
            "type" : "integer",
            "format" : "int64"
          }
        }
      },
      "HeroDTO" : {
        "type" : "object",
        "properties" : {
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "charName" : {
            "type" : "string"
          },
          "classId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "className" : {
            "type" : "string"
          }
        }
      },
      "FreeForAllRankingDTO" : {
        "type" : "object",
        "properties" : {
          "charId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "charName" : {
            "type" : "string"
          },
          "totalFights" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalWins" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalPoints" : {
            "type" : "integer",
            "format" : "int64"
          }
        }
      },
      "ClanRankingDTO" : {
        "type" : "object",
        "properties" : {
          "clanId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "clanName" : {
            "type" : "string"
          },
          "clanLevel" : {
            "type" : "integer",
            "format" : "int32"
          },
          "totalPvp" : {
            "type" : "integer",
            "format" : "int64"
          },
          "totalPk" : {
            "type" : "integer",
            "format" : "int64"
          },
          "memberCount" : {
            "type" : "integer",
            "format" : "int32"
          },
          "totalExp" : {
            "type" : "integer",
            "format" : "int64"
          }
        }
      },
      "CastleDTO" : {
        "type" : "object",
        "properties" : {
          "castleId" : {
            "type" : "integer",
            "format" : "int32"
          },
          "castleName" : {
            "type" : "string"
          },
          "ownerClan" : {
            "type" : "string"
          },
          "siegeDate" : {
            "type" : "string",
            "format" : "date-time"
          },
          "currentTaxPercent" : {
            "type" : "integer",
            "format" : "int32"
          },
          "nextTaxPercent" : {
            "type" : "integer",
            "format" : "int32"
          },
          "treasury" : {
            "type" : "integer",
            "format" : "int64"
          },
          "taxRevenue" : {
            "type" : "integer",
            "format" : "int64"
          },
          "seedIncome" : {
            "type" : "integer",
            "format" : "int64"
          },
          "regTimeOver" : {
            "type" : "string"
          },
          "certificates" : {
            "type" : "integer",
            "format" : "int32"
          }
        }
      },
      "ApiError" : {
        "description" : "Corpo padrão de erro de toda resposta 4xx/5xx da API.",
        "example" : {
          "timestamp" : "2026-01-01T00:00:00Z",
          "path" : "/api/v1/server/does-not-exist",
          "hint" : "Confira o caminho e o método HTTP. Spec: https://api.l2mog.com/openapi.json",
          "status" : 404,
          "message" : "Rota não encontrada.",
          "code" : "NOT_FOUND"
        },
        "properties" : {
          "timestamp" : {
            "type" : "string",
            "description" : "Instante do erro, ISO-8601 (Instant#toString), ex.: 2026-01-01T00:00:00Z."
          },
          "status" : {
            "type" : "integer",
            "format" : "int32",
            "description" : "Status HTTP numérico, igual ao da resposta."
          },
          "code" : {
            "type" : "string",
            "description" : "Código estável para automação. Um de: UNAUTHORIZED, FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, BAD_REQUEST, NOT_ACCEPTABLE, UNSUPPORTED_MEDIA_TYPE, UNSUPPORTED_API_VERSION, RATE_LIMITED, INSUFFICIENT_BALANCE, CHAR_ONLINE, INVENTORY_ITEM_NOT_FOUND, SERVER_ERROR."
          },
          "message" : {
            "type" : "string",
            "description" : "Mensagem legível descrevendo o erro."
          },
          "hint" : {
            "type" : "string",
            "description" : "Sugestão de correção ou link para a documentação."
          },
          "path" : {
            "type" : "string",
            "description" : "Path do request que gerou o erro."
          },
          "fields" : {
            "type" : "object",
            "additionalProperties" : {
              "type" : "string"
            },
            "description" : "Presente só na validação de bean (400): mapa campo -> mensagem."
          }
        }
      }
    },
    "headers" : {
      "API-Version" : {
        "description" : "Versão da API efetivamente atendida. Sempre \"1\" hoje.",
        "schema" : {
          "example" : "1"
        }
      },
      "RateLimit" : {
        "description" : "Estado atual do rate limit (Structured Field, draft-ietf-httpapi-ratelimit-headers-09): \"default\";r=<restantes>;t=<segundos até o reset>.",
        "schema" : {
          "example" : "\"default\";r=599;t=42"
        }
      },
      "RateLimit-Policy" : {
        "description" : "Política de rate limit (Structured Field): \"default\";q=<limite>;w=<janela em segundos>.",
        "schema" : {
          "example" : "\"default\";q=600;w=60"
        }
      },
      "Retry-After" : {
        "description" : "Segundos até poder tentar novamente. Presente em respostas 429.",
        "schema" : {
          "example" : 42
        }
      },
      "Deprecation" : {
        "description" : "RFC 9745: @<epoch-seconds> desde quando o endpoint está deprecado. Só presente em endpoints marcados como deprecados.",
        "schema" : {
          "example" : "@1767225600"
        }
      },
      "Sunset" : {
        "description" : "RFC 8594: data (IMF-fixdate) a partir da qual o endpoint pode deixar de existir. Só presente em endpoints marcados como deprecados.",
        "schema" : {
          "example" : "Tue, 30 Jun 2026 23:59:59 GMT"
        }
      }
    },
    "securitySchemes" : {
      "bearerAuth" : {
        "type" : "http",
        "scheme" : "bearer",
        "bearerFormat" : "JWT"
      },
      "gameKey" : {
        "type" : "apiKey",
        "name" : "X-Game-Key",
        "in" : "header"
      }
    }
  },
  "x-api-catalog" : "https://api.l2mog.com/.well-known/api-catalog",
  "x-deprecation-policy" : {
    "url" : "https://l2mog.com/deprecation-policy",
    "changelog" : "https://l2mog.com/deprecation-policy#changelog",
    "minimumNoticeDays" : 90,
    "headers" : [ "Deprecation", "Sunset", "Link rel=deprecation" ]
  }
}