openapi: 3.1.0
info:
  title: Storyflo Agent API
  description: |
    Aggregate, search, and listen to articles across tech, finance,
    science, media, sports, and culture. Built for agent consumption.
  version: 1.0.0
  contact:
    email: ali@droplinked.com
servers:
  - url: https://storyflo.com
    description: Production
components:
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://storyflo.com/oauth/authorize
          tokenUrl: https://storyflo.com/oauth/token
          scopes:
            articles:read: Search and read articles, get audio URLs
            subscriptions:read: List feeds the agent has subscribed
            subscriptions:write: Subscribe / unsubscribe topic feeds
            digest:run: Aggregate top-N articles in a window
  schemas:
    Article:
      type: object
      properties:
        slug: {type: string}
        title: {type: string}
        publisher_name: {type: string}
        vertical: {type: string}
        snippet: {type: string}
        listen_seconds: {type: integer}
        audio_url: {type: string}
        cover_image_url: {type: string}
security:
  - oauth2: [articles:read]
paths:
  /v1/agent/articles:
    get:
      operationId: search_articles
      summary: Search or browse the article corpus
      security:
        - oauth2: [articles:read]
      parameters:
        - in: query
          name: q
          schema: {type: string}
          description: Free-text search; omit to browse the recent feed
        - in: query
          name: vertical
          schema:
            type: string
            enum: [tech, finance, science, media, sports, culture]
        - in: query
          name: limit
          schema: {type: integer, minimum: 1, maximum: 100, default: 20}
      responses:
        "200":
          description: Article search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  count: {type: integer}
                  articles:
                    type: array
                    items: {$ref: '#/components/schemas/Article'}
  /v1/agent/articles/{slug}:
    get:
      operationId: get_article
      summary: Get a single article record
      security:
        - oauth2: [articles:read]
      parameters:
        - in: path
          name: slug
          required: true
          schema: {type: string}
      responses:
        "200":
          description: Article record
          content:
            application/json:
              schema: {$ref: '#/components/schemas/Article'}
  /v1/agent/articles/{slug}/audio:
    get:
      operationId: get_audio_url
      summary: Resolve playable audio URL for an article
      security:
        - oauth2: [articles:read]
      parameters:
        - in: path
          name: slug
          required: true
          schema: {type: string}
      responses:
        "200":
          description: Audio URL + creative metadata when stitched
  /v1/agent/subscriptions:
    get:
      operationId: list_subscriptions
      summary: List the listener feed(s) this agent manages
      security:
        - oauth2: [subscriptions:read]
      responses:
        "200":
          description: Subscriptions list
    post:
      operationId: subscribe_topic
      summary: Update the listener's verticals to subscribe to
      security:
        - oauth2: [subscriptions:write]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [verticals]
              properties:
                verticals:
                  type: array
                  items:
                    type: string
                    enum: [tech, finance, science, media, sports, culture]
      responses:
        "200":
          description: Subscription updated; feed_url returned
  /v1/agent/digest:
    post:
      operationId: digest
      summary: Aggregate top-N articles in a window
      security:
        - oauth2: [digest:run]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                verticals:
                  type: array
                  items: {type: string}
                window:
                  type: string
                  enum: [24h, 7d, 30d]
                  default: 24h
                limit:
                  type: integer
                  minimum: 1
                  maximum: 20
                  default: 5
      responses:
        "200":
          description: Article list with audio URLs
