{
  "openapi": "3.0.3",
  "info": {
    "title": "Academia Beauty CEO Public API",
    "version": "1.0.0",
    "description": "Read-only public API for Academia Beauty CEO. Currently exposes a single scoped resource: the active tools/courses catalog also shown on /herramientas. No transactional, account, payment, or appointment operations are exposed. Versioning policy: this API is versioned in the URL path (/api/v1/...). Breaking changes ship under a new /api/v2/... path; a version scheduled for removal is announced at least 6 months in advance and returns `Deprecation` and `Sunset` response headers during that window. See /developers for the current policy statement. Zero-signup sandbox: request a token with client_id=public-demo and client_secret=public-demo-read-catalog (read:catalog scope only, no signup required) from POST /api/oauth/token."
  },
  "servers": [
    { "url": "https://www.academiabeautyceo.com" }
  ],
  "paths": {
    "/api/oauth/token": {
      "post": {
        "operationId": "issueAccessToken",
        "summary": "Issue an OAuth 2.0 access token",
        "description": "Exchanges client credentials for a short-lived Bearer token using the client_credentials grant (RFC 6749 section 4.4). Rate-limited to 30 requests per 60 seconds per client_id.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/TokenRequest" }
            },
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TokenRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access token issued.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TokenResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid grant type or scope.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } }
          },
          "401": {
            "description": "Client authentication failed.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } }
          },
          "429": {
            "description": "Too many token requests.",
            "headers": {
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OAuthError" } } }
          }
        }
      }
    },
    "/api/v1/public/catalog": {
      "get": {
        "operationId": "listCatalog",
        "summary": "List the active public tools and courses catalog",
        "description": "Returns the same active-product catalog shown on /herramientas as typed JSON. Requires a Bearer token with the read:catalog scope. Rate-limited to 120 requests per 60 seconds per token. Path-versioned as v1; see info.description for the deprecation policy.",
        "parameters": [],
        "security": [{ "oauth2ClientCredentials": ["read:catalog"] }],
        "responses": {
          "200": {
            "description": "Catalog returned.",
            "headers": {
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CatalogResponse" }
              }
            }
          },
          "401": {
            "description": "Missing or invalid access token.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "403": {
            "description": "Token lacks the read:catalog scope.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          },
          "429": {
            "description": "Too many requests for this token.",
            "headers": {
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2ClientCredentials": {
        "type": "oauth2",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://www.academiabeautyceo.com/api/oauth/token",
            "scopes": {
              "read:catalog": "Read-only access to the public tools and courses catalog."
            }
          }
        }
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Requests allowed in the current window.",
        "schema": { "type": "integer" }
      },
      "RateLimitRemaining": {
        "description": "Requests remaining in the current window.",
        "schema": { "type": "integer" }
      },
      "RateLimitReset": {
        "description": "Unix timestamp (seconds) when the current window resets.",
        "schema": { "type": "integer" }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": { "type": "integer" }
      }
    },
    "schemas": {
      "TokenRequest": {
        "type": "object",
        "required": ["grant_type", "client_id", "client_secret"],
        "properties": {
          "grant_type": { "type": "string", "enum": ["client_credentials"] },
          "client_id": { "type": "string" },
          "client_secret": { "type": "string" },
          "scope": { "type": "string", "example": "read:catalog" }
        }
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": { "type": "string" },
          "token_type": { "type": "string", "example": "Bearer" },
          "expires_in": { "type": "integer", "example": 3600 },
          "scope": { "type": "string", "example": "read:catalog" }
        }
      },
      "OAuthError": {
        "type": "object",
        "description": "RFC 6749 section 5.2 error response.",
        "properties": {
          "error": { "type": "string", "example": "invalid_client" },
          "error_description": { "type": "string" }
        }
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "example": "invalid_token" },
              "message": { "type": "string" },
              "hint": { "type": "string" }
            }
          }
        }
      },
      "CatalogItem": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "slug": { "type": "string" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "price_usd": { "type": "string" },
          "price_mxn": { "type": "string", "nullable": true },
          "url": { "type": "string", "format": "uri" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "CatalogResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/CatalogItem" }
          }
        }
      }
    }
  }
}
