openapi: "3.1.0"
info:
  title: Magnetz API
  description: Search and retrieve torrent metadata — magnet links, file lists, swarm health.
  version: "1.0.0"
  contact:
    url: https://magnetz.app/about
servers:
  - url: https://magnetz.app
    description: Production
paths:
  /api/magnets/search:
    get:
      operationId: searchMagnets
      summary: Search torrents by keyword
      description: Full-text search returning up to 25 results per page ordered by relevance.
      parameters:
        - name: query
          in: query
          required: true
          description: Search keyword (at least one non-whitespace character, max 255)
          schema:
            type: string
            maxLength: 255
        - name: page
          in: query
          required: false
          description: Page number (default 1, max 4 — 100 results total)
          schema:
            type: integer
            default: 1
            minimum: 1
            maximum: 4
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/MagnetSummary'
                  links:
                    $ref: '#/components/schemas/PaginationLinks'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'
        "422":
          $ref: '#/components/responses/InvalidQuery'
        "503":
          $ref: '#/components/responses/BackendUnavailable'
  /api/magnets/{sqid}:
    get:
      operationId: getMagnet
      summary: Get torrent details by sqid
      description: Returns full detail including file list, tracker list, and release metadata.
      parameters:
        - name: sqid
          in: path
          required: true
          description: Short alphanumeric ID shown in the magnet page URL
          schema:
            type: string
            example: a1B2c3D4
      responses:
        "200":
          description: Torrent detail
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/MagnetDetail'
        "404":
          $ref: '#/components/responses/NotFound'
  /api/magnets/infohash/{infohash}:
    get:
      operationId: getMagnetByInfohash
      summary: Get torrent details by infohash
      description: Look up a torrent by its SHA-1 info hash. Returns the same shape as the sqid endpoint.
      parameters:
        - name: infohash
          in: path
          required: true
          description: 40-character hex SHA-1 hash, optionally prefixed with urn:btih:
          schema:
            type: string
            example: 3B4C5D6E7F8A9B0C1D2E3F4A5B6C7D8E9F0A1B2C
      responses:
        "200":
          description: Torrent detail
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/MagnetDetail'
        "404":
          $ref: '#/components/responses/NotFound'
        "422":
          $ref: '#/components/responses/InvalidInfohash'
components:
  schemas:
    MagnetSummary:
      type: object
      description: Torrent result as returned in search listings
      properties:
        sqid:
          type: string
          example: a1B2c3D4
        name:
          type: string
          example: Ubuntu 22.04.3 LTS Desktop amd64
        info_hash:
          type: string
          example: 3B4C5D6E7F8A9B0C1D2E3F4A5B6C7D8E9F0A1B2C
        size:
          type: integer
          description: Total size in bytes
          example: 1580945408
        human_size:
          type: string
          example: 1.47 GB
        score:
          type: number
          format: float
          description: Normalised quality score 0–1
          example: 0.92
        health:
          type: number
          format: float
          description: Normalised swarm health 0–1
          example: 0.85
        is_verified:
          type: boolean
        largest_file:
          type: string
          nullable: true
          example: ubuntu-22.04.3-desktop-amd64.iso
        magnet_link:
          type: string
          example: "magnet:?xt=urn:btih:3B4C5D..."
        seeders:
          type: integer
          example: 421
        leechers:
          type: integer
          example: 18
        created_at:
          type: string
          format: date-time
        web_url:
          type: string
          example: https://magnetz.app/a1B2c3D4
    MagnetDetail:
      type: object
      description: Full torrent detail including files and trackers
      properties:
        sqid:
          type: string
        name:
          type: string
        info_hash:
          type: string
        size:
          type: integer
        human_size:
          type: string
        score:
          type: number
          format: float
        health:
          type: number
          format: float
        number_of_pieces:
          type: integer
          nullable: true
        piece_length:
          type: integer
          nullable: true
        creator:
          type: string
          nullable: true
        creation_date:
          type: string
          format: date-time
          nullable: true
        is_private:
          type: boolean
        is_verified:
          type: boolean
        is_active:
          type: boolean
        magnet_link:
          type: string
        web_url:
          type: string
        release:
          $ref: '#/components/schemas/MagnetRelease'
          description: Release metadata parsed from the torrent name. May be an empty object when no release data is available.
        trackers:
          type: array
          items:
            type: string
        files:
          type: array
          items:
            $ref: '#/components/schemas/MagnetFile'
    MagnetFile:
      type: object
      properties:
        path:
          type: string
        size:
          type: integer
        human_size:
          type: string
    MagnetRelease:
      type: object
      description: Release metadata parsed from the torrent name. All fields are optional and only present when the parser detected a value.
      properties:
        type:
          type: string
          nullable: true
          example: Movie
        title:
          type: string
          nullable: true
          example: The Matrix
        release:
          type: string
          nullable: true
          example: The.Matrix.1999.1080p.BluRay.x264
        group:
          type: string
          nullable: true
          example: FGT
        year:
          type: integer
          nullable: true
          example: 1999
        resolution:
          type: string
          nullable: true
          example: 1080p
        format:
          type: string
          nullable: true
          example: MKV
        source:
          type: string
          nullable: true
          example: BluRay
        audio:
          type: string
          nullable: true
          example: DTS
        season:
          type: integer
          nullable: true
          example: 2
        episode:
          type: integer
          nullable: true
          example: 5
        language:
          type: string
          nullable: true
          example: English
        country:
          type: string
          nullable: true
          example: US
        version:
          type: string
          nullable: true
          example: v2
        device:
          type: string
          nullable: true
          example: iPad
        os:
          type: string
          nullable: true
          example: Windows
        disc:
          type: string
          nullable: true
          example: DISC1
        flags:
          type: string
          nullable: true
          example: PROPER
        title_extra:
          type: string
          nullable: true
          example: Extended Cut
        date:
          type: string
          nullable: true
          example: "2024-03-15"
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
          description: Human-readable error description
        error:
          type: string
          description: Machine-readable error code
    PaginationLinks:
      type: object
      properties:
        first:
          type: string
          nullable: true
        last:
          type: string
          nullable: true
        prev:
          type: string
          nullable: true
        next:
          type: string
          nullable: true
    PaginationMeta:
      type: object
      properties:
        query:
          type: string
        current_page:
          type: integer
        last_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
        from:
          type: integer
          nullable: true
        to:
          type: integer
          nullable: true
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            message: Magnet not found for sqid: a1B2c3D4
            error: magnet_not_found
    InvalidQuery:
      description: Query is empty or invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            message: The query must contain at least one searchable character.
            error: invalid_query
    InvalidInfohash:
      description: Infohash is not a valid 40-character hex string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            message: Invalid infohash format. Expected a 40-character hexadecimal hash.
            error: invalid_infohash_format
    BackendUnavailable:
      description: Search engine is temporarily unreachable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            message: Search backend is currently unavailable. Please try again later.
            error: search_backend_unavailable
