openapi: 3.0.3
info:
  title: BriefTape Financial Newswire API
  description: Real-time AI-summarized financial news from SEC EDGAR, Federal Reserve, FDA, BLS, and insider filings. Ticker-tagged and sentiment-scored. Updated every 60 seconds.
  version: 2.0.0
  contact:
    email: hello@brieftape.com
    url: https://brieftape.com
  license:
    name: Commercial
    url: https://brieftape.com/tos.html
servers:
  - url: https://api.brieftape.com
    description: Production
paths:
  /v1/news:
    get:
      summary: Get latest financial news
      operationId: getNews
      tags: [News]
      parameters:
        - name: tickers
          in: query
          description: Comma-separated ticker symbols (e.g. AAPL,NVDA)
          schema: {type: string, example: AAPL,NVDA}
        - name: category
          in: query
          schema:
            type: string
            enum: [Earnings,Guidance,M&A,Buyback,Dividend,Leadership,Restructuring,Regulatory,Legal,Cyber,Offering,Bankruptcy,FDA,Insider Trading,News,Other]
        - name: limit
          in: query
          schema: {type: integer, minimum: 1, maximum: 100, default: 20}
        - name: offset
          in: query
          schema: {type: integer, minimum: 0, default: 0}
      security: [{BearerAuth: []}, {}]
      responses:
        '200': {description: Successful response}
        '429': {description: Rate limit exceeded}
  /v1/tickers/{ticker}/news:
    get:
      summary: Get news for a specific ticker
      operationId: getTickerNews
      tags: [News]
      parameters:
        - name: ticker
          in: path
          required: true
          schema: {type: string, example: AAPL}
        - name: limit
          in: query
          schema: {type: integer, minimum: 1, maximum: 100, default: 20}
        - name: offset
          in: query
          schema: {type: integer, minimum: 0, default: 0}
      security: [{BearerAuth: []}, {}]
      responses:
        '200': {description: Successful response}
  /v1/stories/{id}:
    get:
      summary: Get a single story by UUID or slug
      operationId: getStory
      tags: [News]
      parameters:
        - name: id
          in: path
          required: true
          schema: {type: string, example: fda-approves-hepcludex-20260604}
      security: [{BearerAuth: []}, {}]
      responses:
        '200': {description: Successful response}
        '404': {description: Story not found}
  /v1/categories:
    get:
      summary: List categories with story counts
      operationId: getCategories
      tags: [Meta]
      security: [{BearerAuth: []}, {}]
      responses:
        '200': {description: Successful response}
  /health:
    get:
      summary: API health check
      operationId: getHealth
      tags: [Meta]
      responses:
        '200': {description: Successful response}
  /api/v1/join:
    post:
      summary: Sign up for free API access
      operationId: joinFree
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email: {type: string, format: email}
                cfToken: {type: string}
      responses:
        '200': {description: Signup successful}
        '400': {description: Invalid email}
        '429': {description: Too many signups from this IP}
  /stripe/checkout:
    get:
      summary: Start paid subscription checkout
      operationId: stripeCheckout
      tags: [Billing]
      parameters:
        - name: tier
          in: query
          required: true
          schema: {type: string, enum: [hacker, pro, quant]}
      responses:
        '303': {description: Redirect to Stripe Checkout}
        '400': {description: Invalid tier}
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API key from paid tier. Free tier uses IP-based rate limiting, no key required.
  schemas:
    Story:
      type: object
      properties:
        id: {type: string, format: uuid}
        slug: {type: string}
        headline: {type: string}
        summary: {type: string}
        category: {type: string}
        sentiment: {type: number, format: float, minimum: -1.0, maximum: 1.0}
        tickers: {type: array, items: {type: string}}
        company_name: {type: string}
        source_url: {type: string, format: uri}
        filed_at: {type: string, format: date-time}
        ingested_at: {type: string, format: date-time}
