openapi: "3.1.0"
info:
  title: "SYNTHOMA Public AI API"
  version: "1"
  description: "Read-only public lore and an isolated stateless Cyklus sandbox. Content 2026-07-14; engine 1.0.0. No account data or production progression."
servers:
  -
    url: "https://www.synthoma.cz"
security:
  []
tags:
  -
    name: "Lore"
    description: "Public and metadata-only canonical content."
  -
    name: "Cards"
    description: "Public Cyklus card registry views."
  -
    name: "Cyklus"
    description: "Anonymous stateless gameplay."
paths:
  "/api/public":
    get:
      tags:
        - "Lore"
      summary: "Discover SYNTHOMA public API"
      operationId: "discover_public_api"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                name: "SYNTHOMA Public API"
                version: "1"
                documentation: "/ai/api"
                openapi: "/api/public/openapi.json"
  "/api/public/v1":
    get:
      tags:
        - "Lore"
      summary: "Discover SYNTHOMA public API v1"
      operationId: "discover_public_api_v1"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                name: "SYNTHOMA Public API v1"
                version: "1"
                resources:
                  site: "/api/public/v1/site"
                  cyklus: "/api/public/v1/cyklus"
  "/api/public/v1/cyklus":
    get:
      tags:
        - "Cyklus"
      summary: "Discover public Cyklus operations"
      operationId: "discover_cyklus"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                name: "SYNTHOMA Cyklus"
                engineVersion: "1.0.0"
                rules: "/api/public/v1/cyklus/rules"
                start:
                  method: "POST"
                  href: "/api/public/v1/cyklus/run"
                choose:
                  method: "POST"
                  href: "/api/public/v1/cyklus/choice"
  "/api/public/v1/site":
    get:
      summary: "Get Synthoma overview"
      operationId: "get_synthoma_overview"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/author":
    get:
      summary: "Get public author profile"
      operationId: "get_public_author_profile"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/books":
    get:
      summary: "List public books"
      operationId: "list_public_books"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/books/{id}":
    get:
      summary: "Get public book"
      operationId: "get_public_book"
      parameters:
        -
          name: "id"
          in: "path"
          required: true
          schema:
            type: "string"
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/chapters":
    get:
      summary: "List chapter metadata"
      operationId: "list_chapter_metadata"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
        -
          name: "limit"
          in: "query"
          schema:
            type: "integer"
            minimum: 1
            maximum: 100
            default: 50
        -
          name: "cursor"
          in: "query"
          schema:
            type: "string"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/chapters/{id}":
    get:
      summary: "Get public chapter"
      operationId: "get_public_chapter"
      parameters:
        -
          name: "id"
          in: "path"
          required: true
          schema:
            type: "string"
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/archive":
    get:
      summary: "List public archive records"
      operationId: "list_public_archive_records"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
        -
          name: "limit"
          in: "query"
          schema:
            type: "integer"
            minimum: 1
            maximum: 100
            default: 50
        -
          name: "cursor"
          in: "query"
          schema:
            type: "string"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/archive/{id}":
    get:
      summary: "Get public archive record"
      operationId: "get_public_archive_record"
      parameters:
        -
          name: "id"
          in: "path"
          required: true
          schema:
            type: "string"
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Lore"
  "/api/public/v1/cards":
    get:
      summary: "List public Cyklus cards"
      operationId: "list_public_cyklus_cards"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
        -
          name: "limit"
          in: "query"
          schema:
            type: "integer"
            minimum: 1
            maximum: 100
            default: 50
        -
          name: "cursor"
          in: "query"
          schema:
            type: "string"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Cards"
  "/api/public/v1/cards/{id}":
    get:
      summary: "Get public Cyklus card"
      operationId: "get_public_cyklus_card"
      parameters:
        -
          name: "id"
          in: "path"
          required: true
          schema:
            type: "string"
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Versioned public response"
          content:
            "application/json":
              schema:
                type: "object"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Cards"
  "/api/public/v1/cyklus/rules":
    get:
      summary: "Get public Cyklus rules"
      operationId: "get_cyklus_rules"
      parameters:
        -
          name: "locale"
          in: "query"
          schema:
            type: "string"
            enum:
              - "cs"
              - "en"
            default: "cs"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                data:
                  maxTurns: 12
                  stats:
                    - "energy"
                    - "memory"
                    - "bond"
                    - "control"
                  choices:
                    - "yes"
                    - "no"
        400:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
      tags:
        - "Cyklus"
  "/api/public/v1/cyklus/run":
    post:
      tags:
        - "Cyklus"
      summary: "Start stateless Cyklus run"
      operationId: "start_cyklus_run"
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/StartRunRequest"
            example:
              locale: "cs"
              seed: "agent-example"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                stateToken: "opaque-state-token"
                run:
                  turn: 1
                  maxTurns: 12
                  status: "active"
                card:
                  id: "restart_0"
                  choices:
                    -
                      id: "yes"
                    -
                      id: "no"
        400:
          "$ref": "#/components/responses/Error"
        413:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
  "/api/public/v1/cyklus/choice":
    post:
      tags:
        - "Cyklus"
      summary: "Choose in stateless Cyklus run"
      operationId: "choose_cyklus"
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              "$ref": "#/components/schemas/ChoiceRequest"
            example:
              stateToken: "opaque-state-token"
              choiceId: "yes"
      responses:
        200:
          description: "Public discovery response"
          content:
            "application/json":
              schema:
                type: "object"
              example:
                stateToken: "next-opaque-state-token"
                result:
                  cardId: "restart_0"
                  choiceId: "yes"
                run:
                  turn: 2
                  maxTurns: 12
                  status: "active"
        400:
          "$ref": "#/components/responses/Error"
        410:
          "$ref": "#/components/responses/Error"
        429:
          "$ref": "#/components/responses/RateLimited"
components:
  schemas:
    StartRunRequest:
      type: "object"
      additionalProperties: false
      properties:
        locale:
          type: "string"
          enum:
            - "cs"
            - "en"
          default: "cs"
        seed:
          type: "string"
          minLength: 1
          maxLength: 128
    ChoiceRequest:
      type: "object"
      additionalProperties: false
      required:
        - "stateToken"
        - "choiceId"
      properties:
        stateToken:
          type: "string"
        choiceId:
          type: "string"
          enum:
            - "yes"
            - "no"
    Error:
      type: "object"
      required:
        - "error"
      properties:
        error:
          type: "object"
          required:
            - "code"
            - "message"
            - "status"
          properties:
            code:
              type: "string"
            message:
              type: "string"
            status:
              type: "integer"
  responses:
    Error:
      description: "JSON error"
      content:
        "application/json":
          schema:
            "$ref": "#/components/schemas/Error"
    RateLimited:
      description: "Rate limited"
      headers:
        Retry-After:
          schema:
            type: "integer"
      content:
        "application/json":
          schema:
            "$ref": "#/components/schemas/Error"
