openapi: 3.1.0
info:
  title: OTOBO OpenTicketAI Generic Interface Webservice
  description: |
    REST routes exposed by the Open Ticket AI Connector package on OTOBO 11.
    Base path: `/otobo/nph-genericinterface.pl/Webservice/OpenTicketAI/`.

    OTOBO core does not ship OpenAPI; this spec documents the Softoft connector
    webservice used by [otai-ts-connector](https://github.com/Softoft-Orga/otai-ts-connector).
  version: 0.2.0
  contact:
    name: Softoft / Open Ticket AI
    url: https://www.openticketai.com
servers:
  - url: https://{host}/otobo/nph-genericinterface.pl/Webservice/OpenTicketAI
    variables:
      host:
        default: otobo.example.com
security:
  - giCredentials: []
paths:
  /ticket-create:
    post:
      operationId: ticketCreate
      summary: Create a ticket with an initial article
      tags: [Tickets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TicketCreateRequest'
      responses:
        '200':
          description: Ticket created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TicketMutationResponse'
  /ticket-get:
    post:
      operationId: ticketGet
      summary: Retrieve one ticket by ID
      tags: [Tickets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/AuthFields'
                - type: object
                  required: [TicketID]
                  properties:
                    TicketID:
                      type: integer
                    AllArticles:
                      type: integer
                      enum: [0, 1]
      responses:
        '200':
          description: Ticket payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TicketGetResponse'
  /ticket-search:
    post:
      operationId: ticketSearch
      summary: Search tickets and return matching IDs
      tags: [Tickets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/AuthFields'
                - type: object
                  properties:
                    Title:
                      type: string
                      description: Wildcard title filter, e.g. `%Order%`
                    Queues:
                      type: array
                      items:
                        type: string
                    Limit:
                      type: integer
      responses:
        '200':
          description: Matching ticket IDs
          content:
            application/json:
              schema:
                type: object
                properties:
                  TicketID:
                    type: array
                    items:
                      type: integer
  /ticket-update:
    put:
      operationId: ticketUpdate
      summary: Update ticket fields and optionally add an article
      tags: [Tickets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TicketUpdateRequest'
      responses:
        '200':
          description: Updated ticket
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TicketMutationResponse'
  /queue-list:
    post:
      operationId: queueList
      summary: List queues for routing/catalog sync
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: Queue catalogue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /state-list:
    post:
      operationId: stateList
      summary: List ticket states
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: State catalogue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /priority-list:
    post:
      operationId: priorityList
      summary: List ticket priorities
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: Priority catalogue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /service-list:
    post:
      operationId: serviceList
      summary: List services
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: Service catalogue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /type-list:
    post:
      operationId: typeList
      summary: List ticket types
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: Type catalogue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /dynamic-field-list:
    post:
      operationId: dynamicFieldList
      summary: List dynamic fields
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthFields'
      responses:
        '200':
          description: Dynamic field definitions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /dynamic-field-values:
    post:
      operationId: dynamicFieldValues
      summary: List allowed values for a dropdown dynamic field
      tags: [Catalog]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/AuthFields'
                - type: object
                  required: [Name]
                  properties:
                    Name:
                      type: string
      responses:
        '200':
          description: Dropdown values
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogResponse'
  /faq-search:
    post:
      operationId: faqSearch
      summary: Search FAQ entries visible to the API agent
      tags: [FAQ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/AuthFields'
                - type: object
                  required: [What]
                  properties:
                    What:
                      type: string
                      description: Search query (alias Query)
      responses:
        '200':
          description: FAQ hits
          content:
            application/json:
              schema:
                type: object
                properties:
                  Item:
                    type: array
                    items:
                      type: object
components:
  securitySchemes:
    giCredentials:
      type: apiKey
      in: body
      name: UserLogin
      description: |
        Generic Interface auth is sent in the JSON body as `UserLogin` and
        `Password` (not as an Authorization header). The OpenTicketAI connector
        locks the webservice to the dedicated API agent (`otai-webservice`).
  schemas:
    AuthFields:
      type: object
      required: [UserLogin, Password]
      properties:
        UserLogin:
          type: string
          example: otai-webservice
        Password:
          type: string
          format: password
    TicketCreateRequest:
      allOf:
        - $ref: '#/components/schemas/AuthFields'
        - type: object
          required: [Ticket, Article]
          properties:
            Ticket:
              type: object
              required: [Title, Queue, State, Priority, CustomerUser]
              properties:
                Title:
                  type: string
                Queue:
                  type: string
                State:
                  type: string
                Priority:
                  type: string
                CustomerUser:
                  type: string
            Article:
              type: object
              required: [Subject, Body, ContentType]
              properties:
                Subject:
                  type: string
                Body:
                  type: string
                ContentType:
                  type: string
                  example: text/plain
    TicketUpdateRequest:
      allOf:
        - $ref: '#/components/schemas/AuthFields'
        - type: object
          required: [TicketID]
          properties:
            TicketID:
              type: integer
            Ticket:
              type: object
              properties:
                State:
                  type: string
                Priority:
                  type: string
            Article:
              type: object
              properties:
                Subject:
                  type: string
                Body:
                  type: string
                ContentType:
                  type: string
    TicketMutationResponse:
      type: object
      properties:
        TicketID:
          type: integer
        TicketNumber:
          type: string
        ArticleID:
          type: integer
    TicketGetResponse:
      type: object
      properties:
        Ticket:
          type: array
          items:
            type: object
    CatalogResponse:
      type: object
      properties:
        Item:
          oneOf:
            - type: object
            - type: array
              items:
                type: object
