openapi: "3.0.3"
info:
  title: "Tokens Service"
  version: "3.0.0-beta"
servers:
  - url: "https://tokens.swap.coffee"
  - url: "http://localhost:8080"

tags:
  - name: Accounts
  - name: Jettons
  - name: Labels
  - name: Contracts

security:
  - { }
  - ApiKey: [ ]

paths:
  /api/v3/accounts/{address}/jettons:
    get:
      tags: [ Accounts ]
      summary: Get all jettons owned by the account
      operationId: getAccountJettons
      parameters:
        - name: address
          in: path
          required: true
          description: The owner wallet address
          schema:
            type: string
      responses:
        '200':
          description: A list of jettons
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiAccountJettons'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons:
    get:
      tags: [ Jettons ]
      summary: Get all jettons (up to 100 per request)
      operationId: getJettonsList
      parameters:
        - name: search
          in: query
          schema:
            type: string
          style: form
          explode: false
        - name: verification
          in: query
          schema:
            type: array
            items:
              $ref: '#/components/schemas/ApiJettonVerification'
            default: [ WHITELISTED ]
          style: form
          explode: false
        - name: label_id
          in: query
          schema:
            type: integer
          style: form
          explode: false
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
          style: form
          explode: false
        - name: size
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
          style: form
          explode: false
      responses:
        '200':
          description: A list of jettons
          headers:
            Cache-Control:
              description: Cache control header
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiJetton'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/{address}/holders:
    get:
      tags: [ Jettons ]
      summary: Get top 10 jetton holders
      operationId: getJettonHolders
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address
          schema:
            type: string
      responses:
        '200':
          description: A list of jetton holders
          headers:
            Cache-Control:
              description: Cache control header
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiJettonWallet'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/by-addresses:
    post:
      tags: [ Jettons ]
      summary: Bulk fetch jettons by addresses (up to 100 per request)
      operationId: getJettonsByAddresses
      parameters:
        - in: query
          name: refresh_price
          schema:
            type: boolean
            default: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: string
                example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
      responses:
        '200':
          description: A list of jettons
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiJetton'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/labels/{address}:
    post:
      tags: [ Labels ]
      summary: Assign a label to a jetton
      operationId: assignLabelToJetton
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiLabelAssignRequest'
      responses:
        '200':
          description: Label assigned successfully
        '404':
          description: Jetton not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
    delete:
      tags: [ Labels ]
      summary: Remove a label from a jetton
      operationId: removeLabelFromJetton
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address
          schema:
            type: string
        - name: label
          in: path
          required: true
          description: The label to remove from the jetton
          schema:
            type: string
      responses:
        '200':
          description: Label removed successfully
        '404':
          description: Jetton not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/labels:
    post:
      tags: [ Labels ]
      summary: Create a new label
      operationId: createLabel
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiLabelCreate'
      responses:
        '200':
          description: Label created successfully
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
    get:
      tags: [ Labels ]
      summary: Get all labels
      operationId: getLabels
      responses:
        '200':
          description: A list of labels
          headers:
            Cache-Control:
              description: Cache control header
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiJettonLabel'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/{address}:
    get:
      tags: [ Jettons ]
      summary: Get jetton by address
      operationId: getJetton
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address
          schema:
            type: string
        - in: query
          name: refresh_price
          schema:
            type: boolean
            default: true
      responses:
        '404':
          description: Jetton not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '200':
          description: A jetton
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiJetton'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/{address}/price-chart:
    get:
      tags: [ Jettons ]
      summary: Get jetton price chart data
      operationId: getJettonPriceChart
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address
          schema:
            type: string
        - name: from
          in: query
          required: true
          description: Start timestamp (ISO datetime)
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          required: true
          description: End timestamp (ISO datetime)
          schema:
            type: string
            format: date-time
        - name: currency
          in: query
          required: false
          description: Currency for price data
          schema:
            type: string
            enum: ['usd', 'ton']
            default: 'usd'
      responses:
        '200':
          description: Price chart data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiJettonPriceChartResponse'
        '404':
          description: Jetton not found or no price data available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/{address}/verification:
    put:
      tags: [ Jettons ]
      summary: Update jetton verification status
      operationId: updateJettonVerification
      parameters:
        - name: address
          in: path
          required: true
          description: The jetton master address in any form
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiJettonUpdateVerificationRequest'
      responses:
        '200':
          description: Jetton verification status updated successfully
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: Jetton not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'


  /api/v3/jettons/import:
    post:
      tags: [ Jettons ]
      summary: Import a jetton. If no verification is provided, the jetton will be marked according to our own whitelist.
      operationId: importJetton
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiJettonImportRequest'
      responses:
        '200':
          description: Jetton imported successfully
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/jettons/refresh:
    post:
      tags: [ Jettons ]
      summary: Refresh jetton data from the blockchain
      operationId: refreshJettons
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiJettonRefreshRequest'
      responses:
        '200':
          description: Jettons sent for refresh
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        'default':
          $ref: '#/components/responses/ApiError'
  /api/v3/hybrid-search:
    get:
      tags: [ Jettons ]
      summary: Jetton hybrid search
      description: |
        If query is not specified and `kind` is either `DEXES` or `MEMES_MEMEPADS`, page is accounted for, otherwise page is ignored.
        If query is not specified and `kind` is `DEXES`, sort is accounted for, otherwise sort is ignored.
        If kind is one of `ALL`, `MEMES_ALL`, `MEMES_MEMEPADS`, `verification` must include `COMMUNITY`
      operationId: hybridSearch
      parameters:
        - name: search
          in: query
          schema:
            type: string
          style: form
          explode: false
        - name: verification
          in: query
          schema:
            type: array
            items:
              $ref: '#/components/schemas/ApiJettonVerification'
            default: [ WHITELISTED ]
          style: form
          explode: false
        - name: size
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
          style: form
          explode: false
        - name: page
          in: query
          schema:
            type: integer
            default: 1
            minimum: 1
            maximum: 100
          style: form
          explode: false
        - name: kind
          in: query
          schema:
            $ref: '#/components/schemas/ApiHybridSearchKind'
          style: form
          explode: false
        - name: sort
          in: query
          schema:
            $ref: '#/components/schemas/ApiHybridSearchSort'
          style: form
          explode: false
      responses:
        '200':
          description: A list of jettons
          headers:
            Cache-Control:
              description: Cache control header
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiPolyJetton'
        'default':
          $ref: '#/components/responses/ApiError'
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      name: X-Api-Key
      in: header

  responses:
    ApiError:
      description: Some error during request processing
      content:
        application/json:
          schema:
            type: object
            required:
              - error
            properties:
              error:
                type: string
  schemas:
    ApiJettonUpdateVerificationRequest:
      type: object
      required:
        - verification
      properties:
        verification:
          $ref: '#/components/schemas/ApiJettonVerification'
        interface_name:
          type: string
          example: "jetton_wallet_tonfun"
        include_hash:
          type: boolean
          example: false
    ApiJettonRefreshRequest:
      type: object
      required:
        - addresses
      properties:
        addresses:
          type: array
          items:
            type: string
            example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
    ApiJettonImportRequest:
      type: object
      required:
        - address
      properties:
        address:
          type: string
          example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
        verification:
          $ref: '#/components/schemas/ApiJettonVerification'
    ApiError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: error description
    ApiAccountJettons:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ApiJettonBalance'
    ApiJettonBalance:
      type: object
      required:
        - balance
        - jetton_address
        - jetton_wallet
      properties:
        balance:
          type: string
          example: "1000000000"
        jetton_address:
          type: string
          example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
        jetton_wallet:
          type: string
          example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
        jetton:
          $ref: '#/components/schemas/ApiJetton'
    ApiJettonWallet:
      required:
        - wallet
        - master
        - balance
        - owner
      properties:
        owner:
          type: string
          title: Jetton wallet owner address
          example: "UQAp9u76fl9LHztpofaMYP3ersv7yazCwOvl5yB9CQyGL4fW"
        wallet:
          type: string
          title: Jetton wallet address
          example: "0:251F2F0038CA380D18FA41B028DEF9774A2B0D9BAF1BBEE70CC7277BFF485E9F"
        master:
          type: string
          title: Jetton master address
          example: "0:29F6EEFA7E5F4B1F3B69A1F68C60FDDEAECBFBC9ACC2C0EBE5E7207D090C862F"
        balance:
          type: string
          title: Jetton balance in nano units
          example: "1234567890"
    ApiJettonVerification:
      type: string
      enum:
        - BLACKLISTED
        - UNKNOWN
        - COMMUNITY
        - WHITELISTED
    ApiJettonMarketStats:
      type: object
      required:
        - holders_count
        - price_usd
        - price_change_5m
        - price_change_1h
        - price_change_6h
        - price_change_24h
        - price_change_7d
        - volume_usd_24h
        - tvl_usd
        - fdmc
        - mcap
      properties:
        holders_count:
          type: integer
          example: 1000
        price_usd:
          type: number
          example: 1.0
        price_change_7d:
          type: number
          example: 0.2
        price_change_5m:
          type: number
          example: 0.01
        price_change_1h:
          type: number
          example: 0.02
        price_change_6h:
          type: number
          example: 0.03
        price_change_24h:
          type: number
          example: 0.1
        volume_usd_24h:
          type: number
          example: 1000000.0
        tvl_usd:
          type: number
          example: 1000000.0
        fdmc:
          type: number
          example: 1000000.0
        mcap:
          type: number
          example: 1000000.0
        trust_score:
          type: integer
          example: 100
    ApiMemepadJettonMarketStats:
      type: object
      required:
        - price_usd
        - tvl_usd
        - fdmc_usd
        - collected_ton
      properties:
        price_usd:
          type: number
          example: 1.0
        tvl_usd:
          type: number
          example: 1000000.0
        fdmc_usd:
          type: number
          example: 1000000.0
        max_ton:
          type: number
          example: 1000000.0
        collected_ton:
          type: number
          example: 1000000.0
        progress:
          type: number
    ApiJettonLabel:
      type: object
      required:
        - label
        - created_at
        - id
      properties:
        label:
          type: string
          example: "label"
        id:
          type: integer
          example: 1
        created_at:
          type: string
          format: date-time
          example: "2023-10-01T12:00:00Z"

    ApiJettonLabelRelation:
      type: object
      required:
        - label
        - created_at
        - label_id
      properties:
        label:
          type: string
          example: "label"
        label_id:
          type: integer
          example: 1
        created_at:
          type: string
          format: date-time
          example: "2023-10-01T12:00:00Z"
        expires_at:
          type: string
          format: date-time
          example: "2023-10-01T12:00:00Z"
    ApiLabelCreate:
      type: object
      required:
        - label
      properties:
        label:
          type: string
          example: "label"
    ApiLabelAssignRequest:
      type: object
      required:
        - label
      properties:
        label:
          type: string
          example: "label"
        expiration_seconds:
          type: integer
          example: 3600
          description: "Optional expiration time in seconds. If not provided, the label will not expire."

    ApiJettonScaledUiMultiplier:
      type: object
      required:
        - numerator
        - denominator
      properties:
        numerator:
          type: string
          format: bigint
        denominator:
          type: string
          format: bigint

    ApiJetton:
      type: object
      required:
        - address
        - decimals
      properties:
        created_at:
          type: string
          format: date-time
          example: "2023-10-01T12:00:00Z"
        address:
          type: string
          example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
        total_supply:
          type: string
          example: "1000000000"
        name:
          type: string
          example: "Tether USD"
        symbol:
          type: string
          example: "USDT"
        decimals:
          type: integer
          format: int32
          example: 6
        mintable:
          type: boolean
          example: false
        buy_fee:
          type: integer
          format: int32
        sell_fee:
          type: integer
          format: int32
        verification:
          $ref: '#/components/schemas/ApiJettonVerification'
        contract_interface:
          type: string
          example: "jetton_wallet_tonfun"
        image_url:
          type: string
          example: "https://tokens.swap.coffee/images/USDT.png"
        market_stats:
          $ref: '#/components/schemas/ApiJettonMarketStats'
        labels:
          type: array
          items:
            $ref: '#/components/schemas/ApiJettonLabelRelation'
        scaled_ui_multiplier:
          $ref: '#/components/schemas/ApiJettonScaledUiMultiplier'

    ApiJettonPriceChartResponse:
      type: object
      required:
        - points
      properties:
        points:
          type: array
          items:
            $ref: '#/components/schemas/ApiJettonPriceChartPoint'
          description: Array of price chart data points

    ApiJettonPriceChartPoint:
      type: object
      required:
        - value
        - time
      properties:
        value:
          type: number
          format: double
          description: Price value in the requested currency
          example: 1.234
        time:
          type: string
          format: date-time
          description: Time of the price point in ISO 8601 format
          example: "2024-01-15T10:30:00Z"
    ApiMemepadJetton:
      type: object
      required:
        - address
        - protocol
        - total_supply
        - decimals
        - mintable
        - verification
        - created_at
      properties:
        created_at:
          type: string
          format: date-time
          example: "2023-10-01T12:00:00Z"
        address:
          type: string
          example: "0:a5d12e31be87867851a28d3ce271203c8fa1a28ae826256e73c506d94d49edad"
        protocol:
          type: string
          example: TONFUN
        name:
          type: string
          example: "Tether USD"
        symbol:
          type: string
          example: "USDT"
        decimals:
          type: integer
          example: 6
        image_url:
          type: string
          example: "https://tokens.swap.coffee/images/USDT.png"
        market_stats:
          $ref: '#/components/schemas/ApiMemepadJettonMarketStats'
    ApiPolyJetton:
      oneOf:
        - $ref: '#/components/schemas/ApiJetton'
        - $ref: '#/components/schemas/ApiMemepadJetton'
      discriminator:
        propertyName: 'type'
        mapping:
          common: '#/components/schemas/ApiJetton'
          memepad: '#/components/schemas/ApiMemepadJetton'
    ApiHybridSearchKind:
      type: string
      enum:
        - ALL
        - DEXES
        - MEMES_ALL
        - MEMES_DEXES
        - MEMES_MEMEPADS
      default: DEXES
    ApiHybridSearchSort:
      type: string
      enum:
        - FDMC
        - TVL
        - MCAP
        - VOLUME_24H
        - PRICE_CHANGE_24H


