openapi: 3.0.3
info:
  title: YFarmX public data API
  version: 1.0.0
  description: >-
    Read-only JSON over the YFarmX newsroom: frontier-technology news across
    the AI, crypto, quantum, security and space desks, six incident and
    threat trackers, a glossary of more than 3,000 terms, verified event listings and the desks'
    state-of-play briefs. Every /data/v1/ payload opens with the same
    provenance envelope; the tracker downloads and /api/model-compare keep
    their own shapes, described below. Cite answers as "YFarmX" with the
    record's URL and date. The connector brief at https://yfarmx.com/connectors/muse.md carries
    recipes and citation rules.
  termsOfService: https://yfarmx.com/terms/
  contact:
    name: YFarmX
    url: https://yfarmx.com/contact/
servers:
  - url: https://yfarmx.com
paths:
  /data/v1/index.json:
    get:
      operationId: getManifest
      summary: The manifest naming every endpoint, feed and documentation link
      responses:
        '200':
          description: Manifest
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Manifest'
  /data/v1/news/latest.json:
    get:
      operationId: getLatestNews
      summary: The newest 30 articles across every desk, newest first
      responses:
        '200':
          description: Article list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArticleList'
  /data/v1/news/{desk}.json:
    get:
      operationId: getDeskNews
      summary: The newest 30 articles on one desk, newest first
      parameters:
        - name: desk
          in: path
          required: true
          schema:
            type: string
            enum: ['ai', 'crypto', 'quantum', 'security', 'space', 'robotics']
      responses:
        '200':
          description: Article list for the desk
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArticleList'
  /data/v1/articles/index.json:
    get:
      operationId: getArticleIndex
      summary: Every published article as a metadata row; fetch once and filter locally to search
      responses:
        '200':
          description: Full article index
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArticleList'
  /data/v1/articles/{month}.json:
    get:
      operationId: getArticleRecords
      summary: Full article records for one publication month, matched on slug
      parameters:
        - name: month
          in: path
          required: true
          description: A publication month as yyyy-mm; take it from the recordFile field of a row in /data/v1/articles/index.json
          schema:
            type: string
            pattern: '^\d{4}-\d{2}$'
      responses:
        '200':
          description: Article records for the month, newest first
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    required: [records]
                    properties:
                      month:
                        type: string
                      count:
                        type: integer
                      records:
                        type: array
                        items:
                          $ref: '#/components/schemas/ArticleRecord'
  /data/v1/glossary/index.json:
    get:
      operationId: getGlossaryManifest
      summary: Glossary manifest with term count and the letter-shard files
      responses:
        '200':
          description: Glossary manifest
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GlossaryManifest'
  /data/v1/glossary/{shard}.json:
    get:
      operationId: getGlossaryShard
      summary: One letter of the glossary, definitions included
      parameters:
        - name: shard
          in: path
          required: true
          description: Lowercased first character of the term, a to z, or 0 for anything else
          schema:
            type: string
            pattern: '^[a-z0]$'
      responses:
        '200':
          description: Glossary terms for the letter
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    required: [records]
                    properties:
                      updated:
                        type: string
                      shard:
                        type: string
                      count:
                        type: integer
                      records:
                        type: array
                        items:
                          $ref: '#/components/schemas/GlossaryTerm'
  /data/v1/events.json:
    get:
      operationId: getEvents
      summary: Upcoming AI, crypto and quantum events, verified against organiser sites
      responses:
        '200':
          description: Upcoming events sorted by start date
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    required: [records]
                    properties:
                      updated:
                        type: string
                      asOf:
                        type: string
                        description: Build date the upcoming cut was taken on
                      count:
                        type: integer
                      records:
                        type: array
                        items:
                          $ref: '#/components/schemas/EventRecord'
  /data/v1/state-of-play.json:
    get:
      operationId: getStateOfPlay
      summary: The dated state-of-play briefs from the AI, crypto and quantum desks
      responses:
        '200':
          description: State-of-play briefs keyed by pillar
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    required: [pillars]
                    properties:
                      pillars:
                        type: object
                        description: One entry per pillar, keyed ai, crypto and quantum
                        additionalProperties:
                          $ref: '#/components/schemas/StateOfPlayPillar'
  /api/model-compare:
    get:
      operationId: getModelFingerprints
      summary: 'AI Fingerprinting: the model picker list, a 12-match search, or two full fingerprint records'
      description: >-
        The YFarmX AI Fingerprinting lab measures tokenizer fingerprints and API contracts. The
        catalogue holds 526 models and 333 of them have a measured
        fingerprint (dataset updated 5 October 2026); the picker list and the search serve the
        measured ones. With no parameters it returns the picker list (id, name, measured). With q
        it returns up to 12 matches ranked by relevance, each carrying its measured family and
        confidence; match on name to pick a model, because a newer sibling can rank first. With a
        and b it returns those two models' full records: family, confidence, signature, per-string
        token counts, providers and API contract. Records are free to quote with attribution to
        YFarmX; methodology at https://yfarmx.com/ai/models/methodology/
      parameters:
        - name: q
          in: query
          required: false
          schema:
            type: string
          description: Search term; model name, id, lab, family, signature or a status word (stealth, measured, placed)
        - name: a
          in: query
          required: false
          schema:
            type: string
          description: First model's catalogue id (pair with b)
        - name: b
          in: query
          required: false
          schema:
            type: string
          description: Second model's catalogue id (pair with a)
      responses:
        '200':
          description: Picker list, search matches, or the two named records with the 50 test-string names
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ModelPickerList'
                  - $ref: '#/components/schemas/ModelSearch'
                  - $ref: '#/components/schemas/ModelPair'
        '400':
          description: a or b names a model outside the catalogue
          content:
            application/json:
              schema:
                type: object
                required: [error]
                properties:
                  error:
                    type: string
  /tools/{tracker}/data.json:
    get:
      operationId: getTrackerDataset
      summary: One tracker's full dataset, CC BY 4.0 with attribution to YFarmX
      parameters:
        - name: tracker
          in: path
          required: true
          schema:
            type: string
            enum: ['exploit-tracker', 'ai-risk-radar', 'quantum-threat-tracker', 'bounty-economics', 'ai-found-vulnerabilities', 'model-security-capability']
      responses:
        '200':
          description: Tracker dataset; records carry per-row dates, sources and page URLs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackerDataset'
components:
  schemas:
    Envelope:
      type: object
      description: Provenance fields every /data/v1/ payload opens with
      required: [product, version, homepage, docs, openapi, generatedAt, source, license, licenseUrl, attribution, citeAs]
      properties:
        product:
          type: string
        version:
          type: string
        homepage:
          type: string
        docs:
          type: string
        openapi:
          type: string
        generatedAt:
          type: string
          format: date-time
          description: The UTC day this payload was built, at midnight; the data refreshes when the site publishes
        source:
          type: string
        license:
          type: string
        licenseUrl:
          type: string
        attribution:
          type: string
        citeAs:
          type: string
    Manifest:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          required: [endpoints]
          properties:
            auth:
              type: string
            brief:
              type: string
            endpoints:
              type: array
              items:
                type: object
                required: [path, what]
                properties:
                  path:
                    type: string
                  what:
                    type: string
            feeds:
              type: object
            links:
              type: object
    ArticleList:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          required: [count, records]
          properties:
            desk:
              type: string
            count:
              type: integer
            records:
              type: array
              items:
                $ref: '#/components/schemas/ArticleSummary'
    ArticleSummary:
      type: object
      required: [slug, url, title, desk, security, published, description, tags]
      properties:
        slug:
          type: string
        url:
          type: string
          description: The article page; stable, canonical, the link to cite
        title:
          type: string
        desk:
          type: string
        subcategory:
          type: string
        security:
          type: boolean
          description: True when the story also sits on the cross-pillar Security Desk
        published:
          type: string
          format: date-time
        updated:
          type: string
          format: date-time
        description:
          type: string
        tags:
          type: array
          items:
            type: string
        recordFile:
          type: string
          description: The monthly bundle holding this article's full record; present on index rows
    ArticleRecord:
      allOf:
        - $ref: '#/components/schemas/ArticleSummary'
        - type: object
          required: [keyPoints, sources, readMinutes, publisher, editor]
          properties:
            seoTitle:
              type: string
            summary:
              type: string
            keyPoints:
              type: array
              description: The In brief points where the article carries them as data; empty for articles that carry none
              items:
                type: string
            sources:
              type: array
              description: The structured source list where the article carries one; empty for older articles, which cite inline on the page
              items:
                type: object
                required: [title, url]
                properties:
                  title:
                    type: string
                  url:
                    type: string
            image:
              type: string
            imageAlt:
              type: string
            audio:
              type: string
              description: Audio version of the article, when one exists
            readMinutes:
              type: integer
            publisher:
              type: string
            editor:
              type: string
            author:
              type: string
              description: Present only when a named person wrote the copy
    GlossaryManifest:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          required: [count, shards]
          properties:
            updated:
              type: string
            count:
              type: integer
            lookup:
              type: string
            shards:
              type: array
              items:
                type: object
                required: [shard, url, count]
                properties:
                  shard:
                    type: string
                  url:
                    type: string
                  count:
                    type: integer
    GlossaryTerm:
      type: object
      required: [term, id, def, pillar, url]
      properties:
        term:
          type: string
        id:
          type: string
        def:
          type: string
        pillar:
          type: string
          enum: ['ai', 'crypto', 'quantum']
        url:
          type: string
          description: The term's own page; the link to cite
    EventRecord:
      type: object
      required: [title, pillar, start, topics, page]
      properties:
        title:
          type: string
        pillar:
          type: string
          enum: ['ai', 'crypto', 'quantum']
        start:
          type: string
          format: date
        end:
          type: string
          format: date
        type:
          type: string
        location:
          type: string
        venue:
          type: string
        description:
          type: string
        topics:
          type: array
          items:
            type: string
        highlights:
          type: string
        organiserUrl:
          type: string
        ticketsUrl:
          type: string
        sourceUrl:
          type: string
        image:
          type: string
        page:
          type: string
          description: The YFarmX events page for the pillar
    TrackerDataset:
      type: object
      description: The established tracker download shape, extended by addition
      required: [name, homepage, updated, source, license, licenseUrl, attribution, records]
      properties:
        name:
          type: string
        homepage:
          type: string
        updated:
          type: string
          format: date
        source:
          type: string
        license:
          type: string
        licenseUrl:
          type: string
        attribution:
          type: string
        citeAs:
          type: string
        count:
          type: integer
          description: The length of records
        records:
          type: array
          items:
            $ref: '#/components/schemas/TrackerRecord'
    TrackerRecord:
      type: object
      description: >-
        Rows differ per tracker. Every row carries a date and a url to its own record page.
        The exploit, AI risk, quantum threat and AI-found vulnerability rows carry a title;
        the bounty platform and model capability rows carry a name instead.
      required: [date, url]
      properties:
        id:
          type: string
        slug:
          type: string
        date:
          type: string
          format: date
        title:
          type: string
        name:
          type: string
        summary:
          type: string
        url:
          type: string
          format: uri
          description: The row's record page on yfarmx.com; the link to cite
        links:
          type: array
          description: Sources for the row, where the tracker records them per row
          items:
            type: object
            properties:
              label:
                type: string
              url:
                type: string
                format: uri
      additionalProperties: true
    StateOfPlayPillar:
      type: object
      required: [updated, sections]
      properties:
        updated:
          type: string
          format: date
        page:
          type: string
        sections:
          type: array
          items:
            type: object
            required: [key, label, text]
            properties:
              key:
                type: string
              label:
                type: string
              text:
                type: string
              url:
                type: string
            additionalProperties: true
    ModelPickerList:
      type: object
      description: GET /api/model-compare with no parameters
      required: [updated, models]
      properties:
        product:
          type: string
        source:
          type: string
        attribution:
          type: string
        terms:
          type: string
        terms_url:
          type: string
        updated:
          type: string
          format: date
        models:
          type: array
          items:
            type: object
            required: [id, name, measured]
            properties:
              id:
                type: string
              name:
                type: string
              measured:
                type: boolean
    ModelSearch:
      type: object
      description: GET /api/model-compare?q=term, up to 12 matches ranked by relevance
      required: [updated, models]
      properties:
        updated:
          type: string
          format: date
        models:
          type: array
          maxItems: 12
          items:
            type: object
            required: [id, name, lab, status]
            properties:
              id:
                type: string
              slug:
                type: string
              name:
                type: string
              lab:
                type: string
              tag:
                type: string
              family:
                type: string
              kind:
                type: string
              confidence:
                type: string
              status:
                type: string
              fresh:
                type: boolean
              alias:
                type: boolean
    ModelPair:
      type: object
      description: GET /api/model-compare?a=id&b=id, the two full records keyed by id
      required: [updated, strings, models]
      properties:
        product:
          type: string
        source:
          type: string
        attribution:
          type: string
        terms:
          type: string
        terms_url:
          type: string
        updated:
          type: string
          format: date
        strings:
          type: array
          description: The names of the 50 test strings, in the order counts are keyed
          items:
            type: string
        models:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/ModelRecord'
    ModelRecord:
      type: object
      required: [name, slug, lab, measured]
      properties:
        name:
          type: string
        slug:
          type: string
        lab:
          type: string
        tag:
          type: string
        family:
          type: string
        confidence:
          type: string
        signature:
          type: string
        measured:
          type: boolean
        counts:
          type: object
          description: Token count per test string; absent until measured
          additionalProperties:
            type: integer
        providers:
          type: array
          items:
            type: string
        measured_at:
          type: string
        api:
          type: object
          additionalProperties: true
