openapi: 3.0.3
info:
  title: CareWay API
  version: 1.0.0
  description: >
    Public CareWay AI API v1. Chats, subscription state, streaming events and
    answer feedback use the same account, tariff and limits as the CareWay cabinet.
servers:
  - url: https://api.carewayrussia.ru/api/v1
security:
  - BearerApiKey: []
  - ApiKeyHeader: []
paths:
  /subscription:
    get:
      operationId: getSubscription
      summary: Current tariff, quota and expiration warning
      responses:
        "200":
          description: Subscription state
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionEnvelope"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /chats:
    get:
      operationId: listChats
      summary: List account chats
      responses:
        "200":
          description: Chat list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Chat"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
    post:
      operationId: createChat
      summary: Create a chat
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Created or reusable empty chat
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Chat"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
  /chats/{chatId}:
    parameters:
      - $ref: "#/components/parameters/ChatId"
    get:
      operationId: getChat
      summary: Read a chat and its messages
      responses:
        "200":
          description: Chat details
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/ChatDetails"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      operationId: deleteChat
      summary: Delete an account chat
      responses:
        "200":
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: object
                    required: [deleted]
                    properties:
                      deleted:
                        type: boolean
                        example: true
        "401":
          $ref: "#/components/responses/InvalidApiKey"
        "404":
          $ref: "#/components/responses/NotFound"
  /chats/{chatId}/messages:
    parameters:
      - $ref: "#/components/parameters/ChatId"
    post:
      operationId: sendMessage
      summary: Send a message and receive the final JSON response
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SendMessageRequest"
      responses:
        "200":
          description: Completed turn
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendResponseEnvelope"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
        "402":
          $ref: "#/components/responses/SubscriptionRequired"
        "403":
          $ref: "#/components/responses/AccessRestricted"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimitExceeded"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /chats/{chatId}/messages/stream:
    parameters:
      - $ref: "#/components/parameters/ChatId"
    post:
      operationId: streamMessage
      summary: Send a message over Server-Sent Events
      description: >
        Events: subscription, progress, sources, heartbeat, completed, error and done.
        API-level failures are delivered as error followed by done.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SendMessageRequest"
      responses:
        "200":
          description: Server-Sent Events stream
          headers:
            X-Accel-Buffering:
              schema:
                type: string
                example: "no"
          content:
            text/event-stream:
              schema:
                type: string
  /chats/{chatId}/messages/{messageId}/feedback:
    parameters:
      - $ref: "#/components/parameters/ChatId"
      - $ref: "#/components/parameters/MessageId"
    post:
      operationId: saveFeedback
      summary: Save or replace correct/incorrect feedback
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rating]
              properties:
                rating:
                  type: string
                  enum: [correct, incorrect]
                actualCause:
                  type: string
                  maxLength: 500
                  nullable: true
      responses:
        "200":
          description: Feedback saved
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: object
                    required: [ok, rating]
                    properties:
                      ok:
                        type: boolean
                      rating:
                        type: string
                        enum: [correct, incorrect]
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/InvalidApiKey"
        "404":
          $ref: "#/components/responses/NotFound"
components:
  securitySchemes:
    BearerApiKey:
      type: http
      scheme: bearer
      bearerFormat: cw_v1
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
  parameters:
    ChatId:
      name: chatId
      in: path
      required: true
      schema:
        type: string
        format: uuid
    MessageId:
      name: messageId
      in: path
      required: true
      schema:
        type: string
        format: uuid
  schemas:
    SendMessageRequest:
      type: object
      required: [text, idempotencyKey]
      properties:
        text:
          type: string
          minLength: 1
        idempotencyKey:
          type: string
          minLength: 1
          maxLength: 128
    Chat:
      type: object
      required: [id, title, createdAt, updatedAt]
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        lastMessagePreview:
          type: string
          nullable: true
        lastMessageRole:
          type: string
          nullable: true
          enum: [user, assistant, null]
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lastMessageAt:
          type: string
          format: date-time
          nullable: true
    Message:
      type: object
      required: [id, role, content, status, createdAt, sources, suggestedReplies]
      properties:
        id:
          type: string
          format: uuid
        role:
          type: string
          enum: [user, assistant]
        content:
          type: string
        status:
          type: string
          enum: [processing, completed, rejected, failed]
        feedback:
          type: string
          nullable: true
          enum: [correct, incorrect, null]
        kind:
          type: string
          nullable: true
          enum: [reference, diagnostic, null]
        createdAt:
          type: string
          format: date-time
        sources:
          type: array
          items:
            $ref: "#/components/schemas/Source"
        suggestedReplies:
          type: array
          items:
            type: string
    Source:
      type: object
      properties:
        title:
          type: string
          nullable: true
        domain:
          type: string
          nullable: true
        url:
          type: string
          format: uri
        snippet:
          type: string
          nullable: true
    Subscription:
      type: object
      required: [plan, status, autoRenew, isExpiringSoon, usage, limits, manageUrl]
      properties:
        plan:
          type: string
        planTitle:
          type: string
        status:
          type: string
        expiresAt:
          type: string
          format: date-time
          nullable: true
        autoRenew:
          type: boolean
        isExpiringSoon:
          type: boolean
        daysRemaining:
          type: integer
          nullable: true
        warning:
          type: string
          nullable: true
        manageUrl:
          type: string
          format: uri
        usage:
          $ref: "#/components/schemas/Quota"
        limits:
          $ref: "#/components/schemas/Quota"
    Quota:
      type: object
      required: [liteMonthly, deepMonthly]
      properties:
        liteMonthly:
          type: integer
          minimum: 0
        deepMonthly:
          type: integer
          minimum: 0
    ChatDetails:
      type: object
      required: [chat, messages, subscription]
      properties:
        chat:
          $ref: "#/components/schemas/Chat"
        messages:
          type: array
          items:
            $ref: "#/components/schemas/Message"
        subscription:
          $ref: "#/components/schemas/Subscription"
    SendResponse:
      type: object
      required: [chat, userMessage, assistantMessage, subscription]
      properties:
        chat:
          $ref: "#/components/schemas/Chat"
        userMessage:
          $ref: "#/components/schemas/Message"
        assistantMessage:
          $ref: "#/components/schemas/Message"
        subscription:
          $ref: "#/components/schemas/Subscription"
    SubscriptionEnvelope:
      type: object
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/Subscription"
    SendResponseEnvelope:
      type: object
      required: [data]
      properties:
        data:
          $ref: "#/components/schemas/SendResponse"
    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
            message:
              type: string
  responses:
    InvalidRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    InvalidApiKey:
      description: API key is missing, invalid or revoked
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    SubscriptionRequired:
      description: Active tariff required
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    AccessRestricted:
      description: AI access restricted
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Chat or message not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    RateLimitExceeded:
      description: Tariff quota exhausted
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    ServiceUnavailable:
      description: Temporary service failure
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
