{
  "openapi": "3.1.0",
  "info": {
    "title": "Coinsemiro — API pública",
    "version": "1.0.0",
    "description": "API pública, de solo lectura y sin autenticación, de Coinsemiro (venta de EA FC 26 Coins en LatAm). Expone únicamente la tabla de precios vigente — es la misma información que usa la propia web. Los recursos internos (pedidos, clientes, panel administrativo) no forman parte de esta especificación: requieren autenticación y no están pensados para integraciones de terceros.\n\n**Versionado:** URL path versioning (`/api/v1/...`). `/api/v1/precios` es la versión estable actual; `/api/precios` es un alias sin versionar que siempre apunta a la última versión estable (hoy, v1). Un cambio que rompa el shape de la respuesta se publica en `/api/v2/...` — v1 nunca cambia de forma incompatible. Si algún día se deprecara una versión, se anuncia con los headers `Deprecation` y `Sunset` (RFC 8594) con aviso previo, y quedará documentado acá antes de desactivarse.\n\n**Errores:** todas las respuestas de error usan `application/problem+json` (RFC 9457) — ver `Problem` en components.schemas.\n\n**Rate limit:** 60 solicitudes/minuto por IP, informado en los headers `RateLimit-Limit` / `RateLimit-Remaining` / `RateLimit-Policy` de cada respuesta (draft IETF `RateLimit-Headers`). Al superarlo, `429` con `Retry-After`.",
    "contact": {
      "name": "Coinsemiro",
      "email": "admin@coinsemiro.com",
      "url": "https://coinsemiro.com/contacto"
    }
  },
  "servers": [
    { "url": "https://coinsemiro.com", "description": "Producción" }
  ],
  "paths": {
    "/api/v1/precios": {
      "get": {
        "operationId": "getPreciosV1",
        "summary": "Tabla de precios vigente (v1)",
        "description": "Devuelve las tablas de precios activas de EA FC 26 Coins, agrupadas por producto. Cada fila incluye el precio por cada 100.000 coins en las monedas soportadas. Sin autenticación, sin parámetros, cacheable 5 minutos. Versión estable — no cambia de forma incompatible (ver info.description).",
        "tags": ["Precios"],
        "responses": {
          "200": { "$ref": "#/components/responses/PreciosOk" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "502": { "$ref": "#/components/responses/UpstreamError" }
        }
      }
    },
    "/api/precios": {
      "get": {
        "operationId": "getPreciosLatest",
        "summary": "Tabla de precios vigente (alias a la última versión)",
        "description": "Alias sin versionar de /api/v1/precios — siempre responde con el mismo shape que la última versión estable (hoy, v1). Para integraciones nuevas se recomienda usar /api/v1/precios explícitamente.",
        "tags": ["Precios"],
        "deprecated": false,
        "responses": {
          "200": { "$ref": "#/components/responses/PreciosOk" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "502": { "$ref": "#/components/responses/UpstreamError" }
        }
      }
    }
  },
  "components": {
    "responses": {
      "PreciosOk": {
        "description": "Tablas de precios activas.",
        "headers": {
          "RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Tope de solicitudes por ventana (ver RateLimit-Policy)." },
          "RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Solicitudes restantes en la ventana actual." },
          "RateLimit-Policy": { "schema": { "type": "string" }, "description": "Política aplicada, formato \"límite;w=ventana_en_segundos\" (ej. \"60;w=60\")." }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/PriceTables" },
            "example": {
              "manual_ps_xbox": [
                { "k": 100, "ARG": 2250, "CHI": 1730, "COL": 7000, "EUR": 1.64, "MEX": 31, "USD": 1.92 }
              ],
              "manual_pc": [
                { "k": 100, "ARG": 3650, "CHI": 2280, "COL": 9200, "EUR": 2.16, "MEX": 44, "USD": 2.53 }
              ],
              "comfort_ps_xbox": [],
              "comfort_pc": []
            }
          }
        }
      },
      "RateLimited": {
        "description": "Se superó el límite de solicitudes.",
        "headers": {
          "Retry-After": { "schema": { "type": "integer" }, "description": "Segundos hasta que se libere la próxima ventana." },
          "RateLimit-Limit": { "schema": { "type": "integer" } },
          "RateLimit-Remaining": { "schema": { "type": "integer" } },
          "RateLimit-Policy": { "schema": { "type": "string" } }
        },
        "content": {
          "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } }
        }
      },
      "UpstreamError": {
        "description": "El servicio de precios no respondió correctamente — probar de nuevo en unos minutos.",
        "content": {
          "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } }
        }
      },
      "NotFound": {
        "description": "La ruta pedida no existe dentro de /api/.",
        "content": {
          "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } }
        }
      },
      "MethodNotAllowed": {
        "description": "Método HTTP no soportado en este endpoint (solo GET/HEAD).",
        "headers": {
          "Allow": { "schema": { "type": "string" }, "description": "Métodos permitidos, ej. \"GET, HEAD\"." }
        },
        "content": {
          "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "Error tipado RFC 9457 (application/problem+json). Todas las respuestas 4xx/5xx de esta API usan este shape.",
        "properties": {
          "type": { "type": "string", "format": "uri", "description": "Identificador estable del tipo de error." },
          "title": { "type": "string", "description": "Resumen corto y humano del error, ej. \"Demasiadas solicitudes\"." },
          "status": { "type": "integer", "description": "Código de estado HTTP, repetido acá para que no haga falta leerlo del status line." },
          "detail": { "type": "string", "description": "Explicación específica de esta ocurrencia, con una pista de cómo resolverlo." },
          "instance": { "type": "string", "description": "Path del request que generó el error." }
        },
        "required": ["type", "title", "status", "detail"]
      },
      "PriceTier": {
        "type": "object",
        "description": "Un tramo de precio, por cada 100.000 coins.",
        "properties": {
          "k": { "type": "number", "description": "Cantidad de coins del tramo, en miles (ej. 100 = 100.000 coins)." },
          "ARG": { "type": "number", "description": "Precio en pesos argentinos (ARS)." },
          "CHI": { "type": "number", "description": "Precio en pesos chilenos (CLP)." },
          "COL": { "type": "number", "description": "Precio en pesos colombianos (COP)." },
          "MEX": { "type": "number", "description": "Precio en pesos mexicanos (MXN)." },
          "USD": { "type": "number", "description": "Precio en dólares estadounidenses." },
          "EUR": { "type": "number", "description": "Precio en euros." }
        },
        "required": ["k"]
      },
      "PriceTables": {
        "type": "object",
        "description": "Tablas de precios activas — set fijo de 4 productos (no cambia sin publicar una nueva versión de la API).",
        "properties": {
          "manual_ps_xbox": { "type": "array", "description": "Manual trade, PlayStation/Xbox.", "items": { "$ref": "#/components/schemas/PriceTier" } },
          "manual_pc": { "type": "array", "description": "Manual trade, PC.", "items": { "$ref": "#/components/schemas/PriceTier" } },
          "comfort_ps_xbox": { "type": "array", "description": "Comfort trade, PlayStation/Xbox.", "items": { "$ref": "#/components/schemas/PriceTier" } },
          "comfort_pc": { "type": "array", "description": "Comfort trade, PC.", "items": { "$ref": "#/components/schemas/PriceTier" } }
        },
        "required": ["manual_ps_xbox", "manual_pc", "comfort_ps_xbox", "comfort_pc"]
      }
    }
  }
}
