openapi: "3.0.3"

info:
  title: ArguCheck Public API
  version: "3.2.0"
  description: |
    Public read-only API for ArguCheck, a structured debate and argument mapping platform.

    **What is ArguCheck?**
    Users post claims (debatable propositions), build pro/contra argument trees,
    rate truthfulness (-2 to +2) and relevance (0-100%), and an evidence-based
    scoring algorithm produces a composite score from -1 (false) to +1 (true).

    **How to present results to users:**
    - Show the claim `title` as the main statement
    - Interpret `cachedScore`: below -0.2 = "Disputed", -0.2 to +0.2 = "Neutral", above +0.2 = "Supported"
    - Show `proCount` and `contraCount` to indicate debate depth
    - Link to the claim page: https://ArguCheck.com/{language}/claims/{slug}
    - For detailed views, show pro/contra arguments from `relations.pro` and `relations.contra`

    **Authentication:** Public endpoints require no authentication.

    **Rate limits:** 120 requests/minute per IP.
  contact:
    name: ArguCheck
    url: https://ArguCheck.com
  license:
    name: Proprietary
    url: https://ArguCheck.com

servers:
  - url: https://api.ArguCheck.com
    description: Production
  - url: http://localhost:4000
    description: Local development

paths:
  /queries/claims:
    get:
      operationId: listPublicClaims
      summary: List public claims with optional filtering and sorting
      description: |
        Returns a paginated list of all public claims. Each claim includes its
        community consensus score, argument counts, and tags. Use this to browse
        or discover debates on any topic.

        **Presentation hint:** Show title + score + pro/contra counts for each claim.
        Score interpretation: < -0.2 disputed, -0.2 to +0.2 neutral, > +0.2 supported.
      parameters:
        - name: visibility
          in: query
          required: true
          schema: { type: string, enum: [public] }
          description: Must be "public" for unauthenticated access
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
        - name: cursor
          in: query
          schema: { type: string }
          description: Pagination cursor from previous response's nextCursor
        - name: tag
          in: query
          schema: { type: string }
          description: "Filter by topic tag (e.g. climate, ai, health, economy)"
        - name: sort
          in: query
          schema: { type: string, enum: [recent, score, active], default: recent }
          description: "recent = newest first, score = highest community consensus first, active = most debated first"
      responses:
        "200":
          description: Paginated list of public claims
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ClaimListResponse" }

  /queries/claims/search:
    get:
      operationId: searchClaims
      summary: Full-text search across public claims
      description: |
        Search public claims by title text. Returns matching claims with scores.
        Use this when looking for a specific topic or debate.
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, minLength: 2 }
          description: Search query (min 2 characters)
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/ClaimSearchResult" }

  /queries/claims/{claimId}:
    get:
      operationId: getClaimDetail
      summary: Get full claim detail with argument tree, scores, and breadcrumbs
      description: |
        Returns a single claim with its complete pro/contra argument tree,
        community truth ratings, score breakdown, linked sources, and breadcrumb
        navigation to parent claims.

        The claimId parameter accepts either a ULID claim ID or a URL slug
        (e.g. "remote-work-increases-productivity").

        **Presentation hint:** Show the claim title, score verdict, then list
        pro arguments (green/positive) and contra arguments (red/negative).
        Each argument has its own score and relevance percentage.
      parameters:
        - name: claimId
          in: path
          required: true
          schema: { type: string }
          description: "Claim ID (ULID) or URL slug (e.g. remote-work-increases-productivity)"
      responses:
        "200":
          description: Full claim detail with argument tree
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ClaimDetailResponse" }
        "404":
          description: Claim not found or not publicly accessible

  /queries/tags:
    get:
      operationId: listTags
      summary: List popular debate topics
      description: |
        Returns the top 50 tags by usage count. Tags represent debate topics
        like "climate", "ai", "health", "economy". Use these to discover
        what people are debating.
      responses:
        "200":
          description: Tag list sorted by popularity
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      tags:
                        type: array
                        items: { type: string }
                        description: "Topic tags sorted by usage count (e.g. climate, ai, health)"

components:
  schemas:
    ClaimListResponse:
      type: object
      properties:
        ok: { type: boolean }
        data: { $ref: "#/components/schemas/ClaimListData" }

    ClaimDetailResponse:
      type: object
      properties:
        ok: { type: boolean }
        data: { $ref: "#/components/schemas/ClaimDetail" }

    ClaimListData:
      type: object
      properties:
        items:
          type: array
          items: { $ref: "#/components/schemas/ClaimSummary" }
        nextCursor:
          type: string
          nullable: true
          description: Pass as cursor parameter to get the next page. Null when no more results.

    ClaimSummary:
      type: object
      description: A debatable proposition with its community consensus score
      properties:
        claimId:
          type: string
          description: "Internal unique ID. Use slug for human-readable URLs instead."
        slug:
          type: string
          description: "URL-friendly identifier. Link to claim: https://ArguCheck.com/{language}/claims/{slug}"
        title:
          type: string
          description: "The claim statement, e.g. 'Remote work increases overall productivity'"
        tags:
          type: array
          items: { type: string }
          description: "Topic categories (e.g. climate, ai, health)"
        language:
          type: string
          enum: [en, de, es]
          description: "Content language: en=English, de=German, es=Spanish"
        cachedScore:
          type: number
          description: "Community consensus: -1.0 = definitely false, 0 = neutral, +1.0 = definitely true. Below -0.2 is 'Disputed', above +0.2 is 'Supported'."
        proCount:
          type: integer
          description: "Number of supporting arguments"
        contraCount:
          type: integer
          description: "Number of opposing arguments"
        truthRatingCount:
          type: integer
          description: "How many people have rated this claim's truthfulness"
        createdAt:
          type: string
          format: date-time

    ClaimSearchResult:
      type: object
      description: Minimal claim info from search results
      properties:
        claimId: { type: string }
        title:
          type: string
          description: "The claim statement"
        language:
          type: string
          description: "Content language (en/de/es)"
        cachedScore:
          type: number
          description: "Community consensus score (-1 to +1)"

    ClaimDetail:
      type: object
      description: Full claim with argument tree, ratings, and sources
      properties:
        claimId: { type: string }
        slug:
          type: string
          description: "URL slug. Link: https://ArguCheck.com/{language}/claims/{slug}"
        title:
          type: string
          description: "The main claim statement"
        body:
          type: string
          description: "Optional explanation or context for the claim"
        language:
          type: string
          enum: [en, de, es]
          description: "Content language"
        tags:
          type: array
          items: { type: string }
          description: "Topic tags"
        cachedScore:
          type: number
          description: "Community consensus: -1 (false) to +1 (true). Below -0.2 = Disputed, above +0.2 = Supported."
        ownerNickname:
          type: string
          description: "Pseudonym of the claim author"
        source:
          $ref: "#/components/schemas/SourceInfo"
        createdAt:
          type: string
          format: date-time
        truth:
          $ref: "#/components/schemas/TruthInfo"
        scoreBreakdown:
          $ref: "#/components/schemas/ScoreBreakdown"
        relations:
          type: object
          description: "The argument tree: pro arguments support the claim, contra arguments oppose it"
          properties:
            pro:
              type: array
              items: { $ref: "#/components/schemas/RelationDetail" }
              description: "Arguments supporting this claim (sorted by strength)"
            contra:
              type: array
              items: { $ref: "#/components/schemas/RelationDetail" }
              description: "Arguments opposing this claim (sorted by strength)"
        proCount:
          type: integer
          description: "Total number of supporting arguments"
        contraCount:
          type: integer
          description: "Total number of opposing arguments"
        breadcrumbs:
          type: array
          description: "Parent claims from root to current, showing where this argument sits in the debate tree"
          items:
            type: object
            properties:
              claimId: { type: string }
              title: { type: string, description: "Parent claim title" }

    TruthInfo:
      type: object
      description: "Community truth assessment for this claim"
      properties:
        avgValue:
          type: number
          nullable: true
          description: "Average community rating: -2 = definitely false, -1 = likely false, 0 = neutral, +1 = likely true, +2 = definitely true"
        nRatings:
          type: integer
          description: "Number of people who rated this claim. Higher = more reliable consensus."

    ScoreBreakdown:
      type: object
      description: "Shows why the score is what it is — how much comes from direct truth ratings vs. sub-arguments"
      properties:
        truthComponent:
          type: number
          description: "Score contribution from direct community truth ratings (0 to 1)"
        derivedComponent:
          type: number
          description: "Score contribution from pro/contra sub-arguments"
        proInfluence:
          type: number
          description: "How much pro arguments push the score up (0 = no effect)"
        contraInfluence:
          type: number
          description: "How much contra arguments push the score down (negative number)"

    RelationDetail:
      type: object
      description: "A pro or contra argument linked to the parent claim"
      properties:
        relationId: { type: string }
        type:
          type: string
          enum: [pro, contra]
          description: "pro = supports parent claim, contra = opposes parent claim"
        fromClaim:
          $ref: "#/components/schemas/SubClaimInfo"
        avgRelevance:
          type: number
          description: "How relevant this argument is to the parent claim: 0.0 = irrelevant, 1.0 = core argument. Displayed as 0-100%."
        nRatings:
          type: integer
          description: "Number of relevance ratings"
        createdAt:
          type: string
          format: date-time

    SubClaimInfo:
      type: object
      description: "A sub-claim that argues for or against its parent"
      properties:
        claimId: { type: string }
        title:
          type: string
          description: "The argument statement"
        body:
          type: string
          description: "Optional reasoning or evidence"
        language: { type: string }
        ownerNickname:
          type: string
          description: "Author pseudonym"
        cachedScore:
          type: number
          description: "This argument's own community consensus (-1 to +1). Arguments with score < 0 (rated untrue) have zero effect on the parent."
        source:
          $ref: "#/components/schemas/SourceInfo"
        createdAt:
          type: string
          format: date-time

    SourceInfo:
      type: object
      nullable: true
      description: "A linked reference (study, article, report) backing the claim"
      properties:
        sourceId: { type: string }
        title:
          type: string
          description: "Source title, e.g. 'Bloom et al. (2015) — Does Working from Home Work?'"
        type:
          type: string
          enum: [study, book, web, report, video, other]
          description: "Source category"
        link:
          type: string
          description: "URL or DOI to the original source"
        author:
          type: string
          description: "Author name(s)"
        year:
          type: integer
          description: "Publication year"
        journal:
          type: string
          description: "Journal or publisher name"
