openapi: 3.0.0
info:
  version: '0.0'
  title: Qomon
  description: |-
    This is Qomon's API definition.

    To get an authorization go to [Qomon's setting page](https://qomon.app/settings/extensions/connect) and create an API key.
servers:
  - description: Qomon local
    url: http://localhost:8101/api
  - description: Qomon integration
    url: https://test.quorumapps.com/api
  - description: Qomon production
    url: https://qomon.app/api

tags:
  - name: SMS
    description: Send sms to contacts

paths:
  /getbalancemessagebird:
    get:
      tags:
        - SMS
      summary: Get balance
      description: Get balance
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "success"
                  data:
                    type: object
                    properties:
                      balance:
                        type: number
                        example: 439.661
                      balance_mms:
                        type: number
                        example: 121.714
  /sendsmss:
    post:
      tags:
        - SMS
      summary: Send SMS/MMS to one or more contacts
      description: Send SMS/MMS to one or more contacts based on search query and files given
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                message:
                  type: string
                  example: "Hello world"
                messagewithoutstop:
                  type: boolean
                  example: false
                search:
                  type: object
                  properties:
                    Search:
                      $ref: "#/components/schemas/ClassicSearch"
                files:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        description: ID of the file
                        example: 2045
                      url:
                        type: string
                        description: url of the file stored in S3 bucket
                        example: "https://s3.aws/my-hash-directory/my-hash-file"
            examples:
              SendSmsExampleRequest:
                summary: Example request body for sending SMS
                value:
                  data:
                    message: "Yes"
                    messagewithoutstop: false
                    search:
                      Search:
                        fields:
                          - "1"
                          - "fullname"
                          - "1"
                          - "0"
                          - ""
                          - ""
                          - ""
                          - "surname"
                          - "true"
                          - ""
                          - ""
                          - ""
                        polygon: []
                        query: "Testingauto"
                        tags: []
                        address_included: []
                        polling_station_included: []
                        polling_station_included_missing: false
                        contact_ids:
                          - 4118849
                        advanced_search:
                          query:
                            $all:
                              - $all: []
                              - $all:
                                  - $at_least_one:
                                      - $condition:
                                          attr: "firstname"
                                          ope: "eql"
                                          value: "Testingauto"
                                      - $condition:
                                          attr: "surname"
                                          ope: "eql"
                                          value: "Testingauto"
                                      - $condition:
                                          attr: "married_name"
                                          ope: "eql"
                                          value: "Testingauto"
                          sort_attr: "surname"
                          sort_asc: true
                          page: 0
                          per_page: 1
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "success"
                  data:
                    type: object
                    example: {}
              examples:
                SendSmsExampleResponse:
                  summary: Example response for successful SMS sending
                  value:
                    status: "success"
                    data: {}
  /sendtestsmss:
    post:
      tags:
        - SMS
      summary: Send a test SMS/MMS to specified users with optional attached files
      description: Sends a test SMS/MMS message to specified users with optional file attachments.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: object
                  properties:
                    message:
                      type: string
                      description: The message content to be sent
                      example: "Hi John Doe"
                    users:
                      type: array
                      items:
                        type: integer
                      description: A list of user IDs to whom the message will be sent
                      example: [20005]
                    files:
                      type: array
                      description: List of files to be attached with the message
                      items:
                        type: object
                        properties:
                          id:
                            type: integer
                            description: File ID
                            example: 2782
                          url:
                            type: string
                            description: URL of the file (optional)
                            example: "https://s3.aws/my-hash-directory/my-hash-file"
            examples:
              SendTestSmsExampleRequest:
                summary: Example request for sending a test SMS
                value:
                  data:
                    message: "Test sms to user"
                    users:
                      - 20017
      responses:
        '200':
          description: SMS sent successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "success"
                  data:
                    type: object
                    description: Details of the operation result
                    example: {}
              examples:
                SendTestSmsExampleResponse:
                  summary: Example response for successful SMS sending
                  value:
                    status: "success"
                    data: {}
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/UnexpectedError'
  /getusagesmsdb:
    get:
      tags:
       - SMS
      summary: Get usage
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                    status:
                      type: string
                    data:
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: integer
                          created:
                            type: string
                          from:
                            type: string
                          message:
                            type: string
                          group_id:
                            type: integer
                          Contacts:
                            type: array
                            nullable: true
                            items:
                              type: object
                              properties:
                                id:
                                  type: integer
                                CreatedAt:
                                  type: string
                                UpdatedAt:
                                  type: string
                                firstname:
                                  type: string
                                surname:
                                  type: string
                                gender:
                                  type: string
                                birthdate:
                                  type: string
                                  format: date-time
                                mail:
                                  type: string
                                  format: email
                                phone:
                                  type: string
                                action_ids:
                                  nullable: true
                                  type: string
                                  format: nullable
                                lastchange:
                                  type: string
                                  format: date-time
                                group_id:
                                  type: integer
                                user_id:
                                  type: integer
                                nationbuilderid:
                                  type: integer
                          Users:
                            type: array
                            nullable: true
                            items:
                              type: object
                          error:
                            type: string
                          status:
                            type: string
                          campainid:
                            type: string
                          messageuuid:
                            type: string
                          number_of_credit_needed:
                            type: integer
                          to:
                            type: string
                          type:
                            type: string
                          message_id_for_consent_url:
                            type: string
                          received_optin_or_optout:
                            type: boolean
  
  /telnyx/messagingprofiles:
    get:
      tags:
        - Telnyx
      summary: Retrieve messaging profiles
      description: Fetches a list of messaging profiles from Telnyx.
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "success"
                  data:
                    type: object
                    properties:
                      Profiles:
                        type: array
                        items:
                          $ref: "#/components/schemas/MessagingProfile"

  /unsubscribe:
    post:
      tags:
        - SMS
      summary: Unsubscribe contacts
      description: Unsubscribes contacts based on search criteria.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: object
                  properties:
                    search:
                      $ref: "#/components/schemas/Search"
            example:
              UnsubscribeExampleRequest:
                $ref: "#/components/examples/UnsubscribeExampleRequest"
      responses:
        '200':
          description: Contacts unsubscribed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchReply"
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: object
                    additionalProperties: true
              examples:
                BadRequestExample:
                  summary: Example of a bad request error
                  value:
                    errors:
                      contact: "Invalid contact ID"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "Internal server error occurred"
  /unsubscribe/{message_id}:
    get:
      tags:
        - SMS
      summary: Get unsubscribe status via GDPR page
      description: Fetches and displays GDPR-related unsubscribe status for a given message ID.
      parameters:
        - name: message_id
          in: path
          required: true
          description: The ID of the message for which to fetch GDPR unsubscribe status.
          schema:
            type: string
      responses:
        '200':
          description: GDPR page rendered successfully
          content:
            text/html:
              schema:
                type: string
                example: "<html><body><h1>GDPR Page</h1><p>Details about the GDPR unsubscribe status.</p></body></html>"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "Internal server error occurred"
  /doubleoptinsms:
    post:
      tags:
        - SMS
      summary: Handle double opt-in via SMS
      description: Processes a double opt-in via SMS for a given search query and sends a double opt-in SMS if applicable.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: object
                  properties:
                    search:
                      $ref: "#/components/schemas/Search"
            example:
              DoubleOptinExampleRequest:
                $ref: "#/components/examples/UnsubscribeExampleRequest"
      responses:
        '200':
          description: Double opt-in processed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SmsReply"
              examples:
                DoubleOptinSuccessExample:
                  summary: Example response for successful double opt-in processing
                  value:
                    usage: []
                    list_messages: []
                    invalid_number: []
                    smss:
                      - id: 123
                        to: "+1234567890"
                        type: "double_optin"
                        createdAt: "2024-11-25T14:32:00Z"
                        contacts:
                          - id: 456
                            firstname: "John"
                            surname: "Doe"
                            phone: "+1234567890"
                    balance: 50.25
                    balance_mms: 10.5
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: object
                    additionalProperties: true
              examples:
                DoubleOptinBadRequestExample:
                  summary: Example of a bad request
                  value:
                    errors:
                      "bad payload for doubleoptinsms": "Invalid JSON payload"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "Internal server error occurred"
  /doubleoptin/{message_id}:
    get:
      tags:
        - SMS
      summary: Handle double opt-in via GDPR page
      description: Displays a GDPR-related double opt-in page for a given message ID.
      parameters:
        - name: message_id
          in: path
          required: true
          description: The ID of the message for which to handle double opt-in.
          schema:
            type: string
      responses:
        '200':
          description: GDPR double opt-in page rendered successfully
          content:
            text/html:
              schema:
                type: string
                example: "<html><body><h1>GDPR Page</h1><p>Double opt-in successful.</p></body></html>"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: "Internal server error occurred"
  
components:
  responses:
    BadRequest:
      description: Invalid request, such as lacking required request body or parameter
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: User authenticated but does not have permission to access the requested resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: User must authenticate before using this api
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnexpectedError:
      description: An internal error occured
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      allOf:
        - $ref: '#/components/schemas/ResponseError'
        - type: object
          required:
            - message
          properties:
            message:
              description: A human readable error message usually considered presentable on user interfaces
              type: string
    ResponseError:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - error
            - fail
    ResponseSuccess:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - success
    
    Polygon:
      type: array
      items:
        type: object
        properties:
          lat:
            type: number
            example: 48.869476
          lng:
            type: number
            example: 2.02458
    AdvancedSearchCondition:
      type: object
      additionalProperties: false
      properties:
        $condition:
          type: object
          required:
            - "attr"
            - "ope"
          properties:
            attr:
              type: string
              example: "surname"
              description: Attribute
            ope:
              type: string
              example: "eql"
              description: Operator
              enum:
                - eql:strictdata
                - not_eql:strictdata
                - contains
                - not_contains
                - eql
                - not_eql
                - ext
                - not_ext
                - range
                - lte
                - gte
                - start_with
                - not_start_with
            form_id:
              type: integer
              example: 4250
              description: If attr is form, the form_id is required
            form_ref_id:
              type: array
              description: If attr is form, the form_ref_id is required
              items:
                type: integer
              example: [6648]
            value:
              type: string
              description:  |-
                Value of the attr or form_ref_id if necessary (depends of the fields and the operator)
              nullable: true
              example: "Dupont"
    AdvancedSearchNode:
      type: object
      additionalProperties: false
      oneOf:
        - required: [ $all ]
        - required: [ $at_least_one ]
      properties:
        $all:
          type: array
          items:
            $ref: "#/components/schemas/AdvancedSearchCondition"
        $at_least_one:
          type: array
          items:
            $ref: "#/components/schemas/AdvancedSearchCondition"
    AdvancedSearch:
      type: object
      required: [query]
      additionalProperties: false
      properties:
        page:
          type: integer
          example: 0
        per_page:
          type: integer
          example: 50
        sort_asc:
          type: boolean
          example: true
        sort_attr:
          type: string
          example: "surname"
        query:
          type: object
          additionalProperties: false
          oneOf:
            - required: [ $all ]
            - required: [ $at_least_one ]
          properties:
            $all:
              type: array
              items:
                $ref: "#/components/schemas/AdvancedSearchNode"
            $at_least_one:
              type: array
              items:
                $ref: "#/components/schemas/AdvancedSearchNode"
    ClassicSearch:
      type: object
      properties:
        address_included:
          description: Values can be retrieve from /search/addresses
          type: array
          items:
            type: object
            properties:
              city:
                type: string
                description: Root occurence on /search/addresses response
              # count:
              #   type: integer
              #   description: Number of contacts matching the query in the city
              empty:
                type: boolean
              street:
                type: string
                description: Sub occurence on /search/addresses response
        contact_ids:
          type: array
          items:
            type: integer
        fields:
          type: array
          items:
            type: object
            properties:
              0:
                type: string
                description: "Group ID"
              1:
                type: string
              2:
                type: string
                description: Number of contacts in response
                example: "50"
              3:
                type: string
                description: Start at index
                example: "100"
              4:
                type: string
                description: Gender
                enum:
                  - m
                  - f
                  - a
              5:
                type: string
              6:
                type: string
                description: Integer corresponding to the age categories
                example: "4"
              7:
                type: string
              8:
                type: string
              9:
                type: string
                format: date-time
                description: Last visit date
              10:
                type: string
                description: Email
                enum:
                  - SET
                  - UNSET
              11:
                type: string
                description: Phone
                enum:
                  - SET
                  - UNSET
                  - ONLYMOBILE
              12:
                type: string
                description: Last visit status
              13:
                type: string
                description: Form response
        only_duplicates:
          type: boolean
        polling_station_included:
          type: array
          items:
            type: object
            properties:
              pollingstation:
                type: string
        polling_station_included_missing:
          type: boolean
        polygon:
          $ref: "#/components/schemas/Polygon"
        query:
          type: string
          description: "Query string to search by name or surname"
        tags:
          type: array
          items:
            type: string
    Search:
      anyOf:
        - $ref: "#/components/schemas/ClassicSearch"
        - properties:
            advanced_search:
              $ref: "#/components/schemas/AdvancedSearch"
            include_interactions:
              type: boolean
              example: true

      type: object
      properties:
        address_included:
          description: Values can be retrieve from /search/addresses
          type: array
          items:
            type: object
            properties:
              city:
                type: string
                description: Root occurence on /search/addresses response
              # count:
              #   type: integer
              #   description: Number of contacts matching the query in the city
              empty:
                type: boolean
              street:
                type: string
                description: Sub occurence on /search/addresses response
        contact_ids:
          type: array
          items:
            type: integer
        fields:
          type: array
          items:
            type: object
            properties:
              0:
                type: string
                description: "Group ID"
              1:
                type: string
              2:
                type: string
                description: Number of contacts in response
                example: "50"
              3:
                type: string
                description: Start at index
                example: "100"
              4:
                type: string
                description: Gender
                enum:
                  - m
                  - f
                  - a
              5:
                type: string
              6:
                type: string
                description: Integer corresponding to the age categories
                example: "4"
              7:
                type: string
              8:
                type: string
              9:
                type: string
                format: date-time
                description: Last visit date
              10:
                type: string
                description: Email
                enum:
                  - SET
                  - UNSET
              11:
                type: string
                description: Phone
                enum:
                  - SET
                  - UNSET
                  - ONLYMOBILE
              12:
                type: string
                description: Last visit status
              13:
                type: string
                description: Form response
        only_duplicates:
          type: boolean
        polling_station_included:
          type: array
          items:
            type: object
            properties:
              pollingstation:
                type: string
        polling_station_included_missing:
          type: boolean
        polygon:
          $ref: "#/components/schemas/Polygon"
        query:
          type: string
          description: "Query string to search by name or surname"
        tags:
          type: array
          items:
            type: string
 
    MessagingProfile:
      type: object
      properties:
        id:
          type: string
          description: The unique identifier for the messaging profile.
          example: "8888888-190e-4483-9e16-aaaaaaaa"
        name:
          type: string
          description: The name of the messaging profile.
          example: "jaybee"
        enabled:
          type: boolean
          description: Indicates whether the messaging profile is active.
          example: true
    SearchReply:
      type: object
      properties:
        Contacts:
          type: array
          items:
            $ref: "#/components/schemas/Contact"
        ArrayOfContacts:
          type: array
          items:
            type: array
            items:
              $ref: "#/components/schemas/Contact"
        Facts:
          type: array
          items:
            $ref: "#/components/schemas/Fact"
        IDs:
          type: array
          items:
            type: integer
            format: uint
        AddressAggs:
          type: array
          items:
            $ref: "#/components/schemas/AddressAggReply"
        AddressStreetAggs:
          type: array
          items:
            $ref: "#/components/schemas/AddressStreetAggReply"
        Kpi:
          type: array
          items:
            $ref: "#/components/schemas/KpiAggs"
        Aggregation:
          type: array
          items:
            type: array
            items:
              type: string
        Data:
          type: array
          items:
            $ref: "#/components/schemas/GenericMap"
        FactsAggreg:
          $ref: "#/components/schemas/FactsAggreg"
        ActionsAggreg:
          type: array
          items:
            $ref: "#/components/schemas/ActionAggreg"
        Actions:
          type: array
          items:
            $ref: "#/components/schemas/Action"
        UserKpi:
          $ref: "#/components/schemas/UserKpi"
        TermsAggregation:
          $ref: "#/components/schemas/TermsAggregation"
        CSV:
          type: array
          items:
            type: array
            items:
              type: string
        Count:
          type: integer
    Contact:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        phone:
          type: string
    Fact:
      type: object
      properties:
        id:
          type: integer
        description:
          type: string
    AddressAggReply:
      type: object
      properties:
        city:
          type: string
        count:
          type: integer
    AddressStreetAggReply:
      type: object
      properties:
        street:
          type: string
        count:
          type: integer
    KpiAggs:
      type: object
      properties:
        metric:
          type: string
        value:
          type: number
    GenericMap:
      type: object
      additionalProperties:
        type: string
    FactsAggreg:
      type: object
      properties:
        total:
          type: integer
    ActionAggreg:
      type: object
      properties:
        action:
          type: string
        count:
          type: integer
    Action:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
    UserKpi:
      type: object
      properties:
        userId:
          type: integer
        kpi:
          type: string
    TermsAggregation:
      type: object
      properties:
        term:
          type: string
        count:
          type: integer
  
    SmsReply:
      type: object
      properties:
        Usage:
          type: array
          items:
            $ref: "#/components/schemas/MessageStatus"
        ListMessages:
          type: array
          items:
            type: string
        InvalidNumber:
          type: array
          items:
            type: string
        Smss:
          type: array
          items:
            $ref: "#/components/schemas/Sms"
        Balance:
          type: number
          format: float
        BalanceMMS:
          type: number
          format: float

    Sms:
      type: object
      properties:
        id:
          type: integer
        to:
          type: string
        type:
          type: string
        createdAt:
          type: string
          format: date-time
        contacts:
          type: array
          items:
            $ref: "#/components/schemas/Contact"

    MessageStatus:
      type: object
      properties:
        status:
          type: string
        timestamp:
          type: string
          format: date-time
  examples:
    UnsubscribeExampleRequest:
      summary: Example request for unsubscribing contacts
      value:
        data:
          search:
            fields:
              - "630"
              - "all"
              - "6"
              - "0"
              - ""
              - ""
              - ""
              - "surname"
              - "true"
              - ""
              - ""
              - ""
            polygon: []
            query: ""
            tags: []
            address_included: []
            polling_station_included: []
            polling_station_included_missing: false
            advanced_search:
              query:
                $all:
                  - $at_least_one:
                      - $condition:
                          attr: "surname"
                          ope: "eql"
                          value: "Noemail"
                      - $condition:
                          attr: "mail"
                          ope: "start_with"
                          value: "hugo+12345"
              sort_attr: "surname"
              sort_asc: true
              page: 0
              per_page: 6