{
  "openapi": "3.1.0",
  "info": {
    "title": "API pública de QuantixTech",
    "version": "1.0.0",
    "description": "La API con la que los programadores de una empresa acceden a sus datos de QuantixTech. Cada empresa emite sus propios tokens desde su panel, con los permisos y, si quiere, la sucursal y las IPs que decida. Envía el token en la cabecera `Authorization: Bearer qx_…`. Un token que no sirve (no existe, está revocado, venció o la IP no está permitida) recibe siempre la misma respuesta 401: la API no dice por qué."
  },
  "servers": [{ "url": "https://api.quantixtech.com.co", "description": "Producción" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/v1/me": {
      "get": {
        "operationId": "obtenerIdentidadDelToken",
        "summary": "Quién es este token",
        "description": "Devuelve la empresa, la sucursal (si el token es de una) y los permisos con los que el token puede actuar. Sirve para comprobar que un token funciona.",
        "tags": ["Token"],
        "responses": {
          "200": {
            "description": "El token es válido.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Identidad" } } }
          },
          "400": { "$ref": "#/components/responses/PeticionInvalida" },
          "401": { "$ref": "#/components/responses/NoAutorizado" },
          "429": { "$ref": "#/components/responses/DemasiadasPeticiones" },
          "503": { "$ref": "#/components/responses/NoDisponible" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "qx_…",
        "description": "Token de API que emite la empresa. Se muestra una sola vez al crearlo."
      }
    },
    "schemas": {
      "Identidad": {
        "type": "object",
        "required": ["token_id", "company_id", "branch_id", "permissions"],
        "properties": {
          "token_id": { "type": "string", "format": "uuid", "description": "Identificador del token." },
          "company_id": { "type": "string", "format": "uuid", "description": "Empresa dueña del token." },
          "branch_id": { "type": ["string", "null"], "format": "uuid", "description": "Sucursal a la que está limitado el token, o null si es de toda la empresa." },
          "permissions": {
            "type": "array",
            "items": { "type": "string", "examples": ["branch.prefixes:view"] },
            "description": "Permisos del token, con la forma `recurso:acción`."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": { "error": { "type": "string" } }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Segundos que faltan para poder volver a intentar.",
        "schema": { "type": "integer", "minimum": 1 }
      }
    },
    "responses": {
      "PeticionInvalida": {
        "description": "No se pudo determinar la IP de origen de la petición.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NoAutorizado": {
        "description": "Falta el token o no sirve. No se indica el motivo.",
        "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Siempre `Bearer realm=\"quantix\"`." } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "DemasiadasPeticiones": {
        "description": "Se pasó del límite de uso por minuto (por IP o por token) o hubo demasiados intentos con un token inválido.",
        "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NoDisponible": {
        "description": "El servicio no puede validar el token en este momento. Reintenta más tarde.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
