openapi: "3.1.0"
info:
  title: CloudYali Public API
  summary: Public, unauthenticated endpoints published by the CloudYali website.
  description: "CloudYali is a FinOps platform for cloud cost visibility and management across AWS, Azure and GCP.\n\nThis document describes the public, unauthenticated endpoints served by www.cloudyali.io.\nThey let agents and integrations discover what CloudYali does, read published content,\nand submit a demo request without scraping HTML.\n\nAll responses are JSON. Successful responses use the envelope `{ \"success\": true, \"data\": ... }`.\nErrors use `{ \"success\": false, \"error\": { \"code\", \"message\", \"hint\", \"documentation_url\", \"request_id\" } }`\nand the `code` field is stable and safe to branch on.\n\nNo authentication is required for any operation in this document. Rate limits are not currently enforced.\nThe authenticated CloudYali platform API used by the console is documented separately at https://docs.cloudyali.io."
  version: "1.0.0"
  termsOfService: https://www.cloudyali.io/terms-of-service
  contact:
    name: CloudYali Support
    email: support@cloudyali.io
    url: https://www.cloudyali.io/developers
  license:
    name: CloudYali API Terms
    url: https://www.cloudyali.io/terms-of-service
servers:
  - url: https://www.cloudyali.io
    description: CloudYali production website
externalDocs:
  description: CloudYali developer resources
  url: https://www.cloudyali.io/developers
tags:
  - name: Discovery
    description: Endpoint discovery and service health.
  - name: Product
    description: CloudYali product capability catalog.
  - name: Content
    description: Published CloudYali blog content.
  - name: Sales
    description: Demo requests and sales contact.
paths:
  /api:
    get:
      operationId: getApiIndex
      summary: List available CloudYali public API endpoints
      description: Returns a discovery document listing every public endpoint, the URL of this OpenAPI specification, and links to CloudYali developer resources. Call this first when exploring the API.
      tags:
        - Discovery
      security: []
      responses:
        "200":
          description: Discovery document.
          content:
            application/json:
              schema:
                type: object
                title: ApiIndexResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    required:
                      - service
                      - openapi_url
                      - endpoints
                    properties:
                      service:
                        type: string
                      description:
                        type: string
                      documentation_url:
                        type: string
                        format: uri
                      openapi_url:
                        type: string
                        format: uri
                      llms_txt_url:
                        type: string
                        format: uri
                      endpoints:
                        type: array
                        items:
                          type: object
                          required:
                            - method
                            - path
                            - operation_id
                            - description
                          properties:
                            method:
                              type: string
                              enum:
                                - GET
                                - POST
                            path:
                              type: string
                            operation_id:
                              type: string
                            description:
                              type: string
        "500":
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/health:
    get:
      operationId: getServiceHealth
      summary: Check CloudYali website API health
      description: Returns the liveness status of the CloudYali public website API. Use this to verify connectivity before issuing other calls. Always returns HTTP 200 when the service is reachable.
      tags:
        - Discovery
      security: []
      responses:
        "200":
          description: Service is healthy.
          content:
            application/json:
              schema:
                type: object
                title: HealthResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    required:
                      - status
                      - service
                      - version
                      - timestamp
                    properties:
                      status:
                        type: string
                        enum:
                          - ok
                      service:
                        type: string
                      version:
                        type: string
                      timestamp:
                        type: string
                        format: date-time
        "500":
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/features:
    get:
      operationId: listProductFeatures
      summary: List CloudYali product capabilities
      description: Returns the full catalog of CloudYali FinOps capabilities — cost visibility, cost savings, budget management, asset inventory, tag governance, AI cost tracking and integrations — including which cloud providers each capability covers. Use this to answer questions about what CloudYali does.
      tags:
        - Product
      security: []
      responses:
        "200":
          description: Product capability catalog.
          content:
            application/json:
              schema:
                type: object
                title: FeatureListResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    required:
                      - features
                      - count
                    properties:
                      count:
                        type: integer
                        minimum: 0
                      features:
                        type: array
                        items:
                          $ref: "#/components/schemas/Feature"
        "500":
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/blogs:
    get:
      operationId: listBlogPosts
      summary: List published CloudYali blog posts
      description: Returns a paginated list of published CloudYali blog posts about FinOps and cloud cost management, newest first. Each item includes a canonical URL and a markdown URL suitable for agent ingestion.
      tags:
        - Content
      security: []
      parameters:
        - name: limit
          in: query
          required: false
          description: Maximum number of posts to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: offset
          in: query
          required: false
          description: Number of posts to skip, for pagination.
          schema:
            type: integer
            minimum: 0
            maximum: 10000
            default: 0
        - name: category
          in: query
          required: false
          description: Filter to a single category slug, for example `finops`.
          schema:
            type: string
            pattern: ^[a-z0-9-]{1,120}$
      responses:
        "200":
          description: Paginated list of blog posts.
          content:
            application/json:
              schema:
                type: object
                title: BlogListResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    required:
                      - posts
                      - total
                      - limit
                      - offset
                    properties:
                      total:
                        type: integer
                        minimum: 0
                        description: Total posts matching the filter, ignoring pagination.
                      limit:
                        type: integer
                      offset:
                        type: integer
                      posts:
                        type: array
                        items:
                          $ref: "#/components/schemas/BlogPostSummary"
        "400":
          description: Malformed request — invalid JSON body or query parameter.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: An upstream dependency of this endpoint failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/v1/blogs/{slug}:
    get:
      operationId: getBlogPostBySlug
      summary: Retrieve one CloudYali blog post
      description: Returns a single published blog post by its slug, including the full body rendered as Markdown. Use `listBlogPosts` to discover valid slugs.
      tags:
        - Content
      security: []
      parameters:
        - name: slug
          in: path
          required: true
          description: URL-safe identifier of the post, as returned by `listBlogPosts`.
          schema:
            type: string
            pattern: ^[a-z0-9-]{1,200}$
      responses:
        "200":
          description: The requested blog post.
          content:
            application/json:
              schema:
                type: object
                title: BlogDetailResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/BlogPostDetail"
        "400":
          description: Malformed request — invalid JSON body or query parameter.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: The requested resource does not exist.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: An upstream dependency of this endpoint failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /api/demo-request:
    get:
      operationId: getDemoRequestStatus
      summary: Check the demo request endpoint
      description: Returns the availability and version of the demo request endpoint without submitting anything.
      tags:
        - Sales
      security: []
      responses:
        "200":
          description: Endpoint is available.
          content:
            application/json:
              schema:
                type: object
                title: DemoRequestStatusResponse
                required:
                  - success
                  - data
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    required:
                      - status
                      - version
                    properties:
                      status:
                        type: string
                        enum:
                          - ok
                      version:
                        type: string
                      message:
                        type: string
        "500":
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      operationId: submitDemoRequest
      summary: Submit a CloudYali demo request
      description: Submits a request for a CloudYali product demo. All listed fields are required. Returns a confirmation id on success. This creates a sales lead — only call it on explicit instruction from a real person who wants to be contacted.
      tags:
        - Sales
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DemoRequest"
      responses:
        "200":
          description: Demo request accepted.
          content:
            application/json:
              schema:
                type: object
                title: DemoRequestResponse
                required:
                  - success
                  - message
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                      email:
                        type: string
                        format: email
        "400":
          description: Malformed request — invalid JSON body or query parameter.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "422":
          description: Request was well-formed but failed field validation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: An upstream dependency of this endpoint failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  securitySchemes: {}
  schemas:
    ErrorResponse:
      type: object
      title: ErrorResponse
      description: Structured error envelope returned by every CloudYali public endpoint. Never HTML.
      required:
        - success
        - error
      additionalProperties: false
      properties:
        success:
          type: boolean
          enum:
            - false
          description: Always false on an error response.
        error:
          type: object
          required:
            - code
            - message
            - hint
            - documentation_url
            - request_id
          properties:
            code:
              type: string
              enum:
                - bad_request
                - validation_error
                - invalid_json
                - not_found
                - method_not_allowed
                - rate_limited
                - upstream_error
                - configuration_error
                - internal_error
              description: Stable machine-readable error code. Safe to branch on.
            message:
              type: string
              description: Human-readable description of what went wrong.
            hint:
              type: string
              description: Suggested resolution step for the caller.
            details:
              description: Optional machine-readable context, such as the offending field.
            documentation_url:
              type: string
              format: uri
              description: Where to read more about this endpoint.
            request_id:
              type: string
              description: Correlation id for this request. Include it in support tickets.
    Feature:
      type: object
      title: Feature
      required:
        - id
        - name
        - summary
        - capabilities
        - providers
        - url
      properties:
        id:
          type: string
          enum:
            - cost-visibility
            - cost-savings
            - budget-management
            - asset-inventory
            - tag-governance
            - ai-cost-tracking
            - integrations
          description: Stable feature identifier, matching the feature page slug.
        name:
          type: string
          description: Human-readable capability name.
        summary:
          type: string
          description: One-sentence description of the capability.
        capabilities:
          type: array
          items:
            type: string
          description: Concrete things this capability lets a team do.
        providers:
          type: array
          items:
            type: string
          description: Cloud providers and services this capability covers.
        url:
          type: string
          format: uri
          description: Canonical feature page URL.
    BlogPostSummary:
      type: object
      title: BlogPostSummary
      required:
        - slug
        - title
        - url
      properties:
        slug:
          type: string
          description: URL-safe unique identifier for the post.
        title:
          type: string
          description: Post title.
        excerpt:
          type: string
          description: Short summary of the post.
        url:
          type: string
          format: uri
          description: Canonical URL of the post.
        markdown_url:
          type: string
          format: uri
          description: Plain-markdown rendering of the post, for agent consumption.
        published_at:
          type: string
          format: date-time
          description: ISO 8601 publication timestamp.
        reading_time_minutes:
          type: integer
          minimum: 0
        author:
          type: string
          description: Author display name.
        categories:
          type: array
          items:
            type: string
        tags:
          type: array
          items:
            type: string
    BlogPostDetail:
      allOf:
        - $ref: "#/components/schemas/BlogPostSummary"
        - type: object
          title: BlogPostDetail
          properties:
            body_markdown:
              type: string
              description: Full post body rendered as Markdown.
    DemoRequest:
      type: object
      title: DemoRequest
      description: Fields required to request a CloudYali product demo.
      required:
        - firstName
        - lastName
        - businessEmail
        - companyName
        - jobTitle
        - cloudBill
        - howDidYouHear
      properties:
        firstName:
          type: string
          minLength: 1
          description: Requester first name.
        lastName:
          type: string
          minLength: 1
          description: Requester last name.
        businessEmail:
          type: string
          format: email
          description: Business email address to send the demo invitation to.
        companyName:
          type: string
          minLength: 1
          description: Company name.
        jobTitle:
          type: string
          minLength: 1
          description: Requester job title.
        cloudBill:
          type: string
          minLength: 1
          description: Approximate annual cloud spend band, for example "$100k - $500k".
        howDidYouHear:
          type: string
          minLength: 1
          description: How the requester heard about CloudYali.
security: []
