{
  "openapi": "3.0.3",
  "info": {
    "title": "Spoken Alpha API",
    "version": "0.1.0",
    "description": "Structured earnings-call data for AI agents. Cleaned transcripts, canonical IR URLs, and per-exchange interpretive scores. Tier 1 endpoints are live; Tier 2 and Tier 3 are in private beta.",
    "contact": {
      "name": "Spoken Alpha API support",
      "email": "support@spokenalpha.com",
      "url": "https://spokenalpha.com/docs"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api.spokenalpha.com/v1",
      "description": "Production"
    }
  ],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    {
      "name": "Tier 1 — metadata",
      "description": "Canonical IR URLs, recent earnings calls, and (planned) press-release feeds. Available on Free and all paid tiers."
    },
    {
      "name": "Tier 2 — parse + score",
      "description": "Speaker-attributed Q&A parsing and tonal/skepticism scoring. Available on Startup and Pro."
    },
    {
      "name": "Tier 3 — accountability",
      "description": "Executive and analyst longitudinal track records. Available on Pro and Enterprise."
    }
  ],
  "paths": {
    "/companies/{ticker}/ir-page": {
      "get": {
        "tags": ["Tier 1 — metadata"],
        "summary": "Canonical IR page URL for a company",
        "description": "Returns the canonical Investor Relations page URL. Paid tiers also get validation metadata (last-validated timestamp, validation status, planned confidence score, and detected sections). Free tier returns URL only plus a _tier_notice pointer to /pricing.",
        "operationId": "getIrPage",
        "x-status": "live",
        "parameters": [
          {
            "name": "ticker",
            "in": "path",
            "required": true,
            "description": "Uppercase US ticker (case-insensitive normalized at the boundary).",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z][A-Za-z0-9.\\-]{0,9}$",
              "example": "AAPL"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "IR page metadata. Free tier returns the slim shape; paid tiers return the full shape.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IRPageResponse" }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "404": {
            "description": "ticker_not_found (no company on file) or ir_page_not_found (company exists but no IR URL on file).",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "429": {
            "description": "Rate limit or quota exceeded.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          }
        }
      }
    },
    "/companies/{ticker}/earnings-calls": {
      "get": {
        "tags": ["Tier 1 — metadata"],
        "summary": "Recent earnings calls for a company",
        "description": "Returns recent earnings calls in reverse chronological order. Each call includes fiscal period, scheduled date, BMO/AMC flag, and confirmed status. Asset URLs (transcript / audio / slide deck) and the parsed-transcript URL are part of the v1 contract but currently null pending the IR-page section crawler and Tier 2 launch.",
        "operationId": "listEarningsCalls",
        "x-status": "live",
        "parameters": [
          {
            "name": "ticker",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "example": "AAPL" }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max calls per page. Default 8, max 40.",
            "schema": { "type": "integer", "minimum": 1, "maximum": 40, "default": 8 }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque pagination cursor from a prior response.",
            "schema": { "type": "string" }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive lower bound on call date (YYYY-MM-DD).",
            "schema": { "type": "string", "format": "date" }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Exclusive upper bound on call date (YYYY-MM-DD).",
            "schema": { "type": "string", "format": "date" }
          },
          {
            "name": "confirmed_only",
            "in": "query",
            "required": false,
            "description": "If true, only company_confirmed or edgar_confirmed calendar rows.",
            "schema": { "type": "boolean", "default": false }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of earnings calls, newest first.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EarningsCallListResponse" }
              }
            }
          },
          "401": { "description": "Missing or invalid API key." },
          "404": { "description": "No company found for ticker." },
          "422": {
            "description": "Invalid query parameter (limit out of range, malformed date, etc.)."
          },
          "429": { "description": "Rate limit or quota exceeded." }
        }
      }
    },
    "/companies/{ticker}/press-releases": {
      "get": {
        "tags": ["Tier 1 — metadata"],
        "summary": "Press releases for a company (scaffolded; not yet available)",
        "description": "Structured recent IR-page press releases for the company. The endpoint is scaffolded so clients can integrate against the locked contract today, but returns 503 data_not_yet_available until the SEC 8-K Item 2.02 + EX-99.1 ingest ships. Planned launch: Q3 2026.",
        "operationId": "listPressReleases",
        "x-status": "scaffolded",
        "x-planned-launch": "Q3 2026",
        "parameters": [
          {
            "name": "ticker",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "example": "AAPL" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of press releases (planned shape; not returned in v1).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PressReleaseListResponse" }
              }
            }
          },
          "401": { "description": "Missing or invalid API key." },
          "503": {
            "description": "data_not_yet_available — the data backing this endpoint has not yet shipped. Body includes planned_launch.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          }
        }
      }
    },
    "/transcripts/{call_id}/parse": {
      "post": {
        "tags": ["Tier 2 — parse + score"],
        "summary": "Parse a transcript into Q&A pairs",
        "description": "Returns speaker-attributed Q&A pairs and section markers (prepared remarks vs. analyst Q&A). Counts against the Tier 2 monthly quota.",
        "operationId": "parseTranscript",
        "x-status": "coming_soon",
        "parameters": [
          {
            "name": "call_id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "example": "call_AAPL_2026Q2_earnings" }
          }
        ],
        "responses": {
          "200": {
            "description": "Parsed transcript.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ParsedTranscript" }
              }
            }
          },
          "402": {
            "description": "Tier 2 quota exhausted and no overage allowed on current plan."
          }
        }
      }
    },
    "/transcripts/{call_id}/score": {
      "post": {
        "tags": ["Tier 2 — parse + score"],
        "summary": "Score a transcript",
        "description": "Returns universal interpretive scores (skepticism, evasion, hedging density). Proprietary deviation and composition signals are NOT exposed. Counts against the Tier 2 monthly quota.",
        "operationId": "scoreTranscript",
        "x-status": "coming_soon",
        "parameters": [
          {
            "name": "call_id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "example": "call_AAPL_2026Q2_earnings" }
          }
        ],
        "responses": {
          "200": {
            "description": "Score record.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CallScore" }
              }
            }
          }
        }
      }
    },
    "/executives/{ticker}": {
      "get": {
        "tags": ["Tier 3 — accountability"],
        "summary": "Executives for a ticker",
        "description": "Current and recent executives with tenure and role information.",
        "operationId": "listExecutives",
        "x-status": "coming_soon",
        "parameters": [
          {
            "name": "ticker",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Executive roster.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Executive" }
                }
              }
            }
          }
        }
      }
    },
    "/executives/{id}/track-record": {
      "get": {
        "tags": ["Tier 3 — accountability"],
        "summary": "Statement-to-outcome history for an executive",
        "description": "Longitudinal record of statements made on earnings calls and the realized outcomes. Used for accountability scoring.",
        "operationId": "getExecutiveTrackRecord",
        "x-status": "coming_soon",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Track record.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ExecutiveTrackRecord" }
              }
            }
          }
        }
      }
    },
    "/analysts/{name}": {
      "get": {
        "tags": ["Tier 3 — accountability"],
        "summary": "Analyst profile and accountability rating",
        "description": "Skepticism Accuracy Rating and exhibits for a sell-side analyst.",
        "operationId": "getAnalyst",
        "x-status": "coming_soon",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Analyst profile.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Analyst" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key passed as `Authorization: Bearer <key>`. Get yours at /pricing."
      }
    },
    "schemas": {
      "IRPageResponse": {
        "type": "object",
        "required": ["ticker", "company_name", "ir_page", "_self"],
        "properties": {
          "ticker": { "type": "string", "example": "AAPL" },
          "company_name": { "type": "string", "example": "Apple Inc." },
          "ir_page": {
            "type": "object",
            "required": ["url"],
            "properties": {
              "url": { "type": "string", "format": "uri", "example": "https://investor.apple.com" },
              "confidence": {
                "type": "number",
                "format": "float",
                "minimum": 0,
                "maximum": 1,
                "nullable": true,
                "description": "LLM-discovery confidence × recency adjustment. Paid tiers only. Null until the IR-page section crawler ships."
              },
              "last_validated_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "When we last confirmed the URL resolves to an IR-shaped page. Paid tiers only."
              },
              "validation_status": {
                "type": "string",
                "enum": ["valid", "invalid", "not_found", "unknown"],
                "description": "Paid tiers only."
              },
              "sections_found": {
                "type": "array",
                "items": { "type": "string" },
                "description": "Top-level navigation classes (earnings, press_releases, events_and_presentations, sec_filings, stock_info). Paid tiers only. Empty list until the section crawler ships."
              }
            }
          },
          "_self": { "type": "string", "format": "uri" },
          "_tier_notice": {
            "type": "string",
            "description": "Free tier only — pointer to /pricing for the upgrade unlock."
          }
        }
      },
      "EarningsCall": {
        "type": "object",
        "required": ["id", "ticker", "fiscal_year", "fiscal_quarter", "call_date", "_self"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable, deterministic public identifier. Format: call_{TICKER}_{YYYY}Q{Q}_{type}.",
            "example": "call_AAPL_2026Q2_earnings"
          },
          "ticker": { "type": "string" },
          "fiscal_year": { "type": "integer", "example": 2026 },
          "fiscal_quarter": { "type": "integer", "example": 2 },
          "call_type": {
            "type": "string",
            "enum": ["earnings", "conference", "investor_day", "other"]
          },
          "call_date": { "type": "string", "format": "date" },
          "scheduled_date": { "type": "string", "format": "date", "nullable": true },
          "scheduled_time_of_day": {
            "type": "string",
            "enum": ["BMO", "AMC", "UNKNOWN"],
            "nullable": true
          },
          "confirmed_status": {
            "type": "string",
            "enum": ["estimated", "company_confirmed", "edgar_confirmed"],
            "nullable": true
          },
          "release_timestamp_utc": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "8-K Item 2.02 filing timestamp. Null in v1 pending public-API exposure of 8-K filings."
          },
          "transcript": {
            "type": "object",
            "required": ["available"],
            "properties": {
              "available": { "type": "boolean" },
              "url_on_ir_page": { "type": "string", "format": "uri", "nullable": true },
              "parsed_url": {
                "type": "string",
                "format": "uri",
                "nullable": true,
                "description": "URL of the Tier 2 /v1/transcripts/{call_id} endpoint when Tier 2 ships. Null in v1."
              }
            }
          },
          "audio": {
            "type": "object",
            "required": ["available"],
            "properties": {
              "available": { "type": "boolean" },
              "url_on_ir_page": { "type": "string", "format": "uri", "nullable": true }
            }
          },
          "slide_deck": {
            "type": "object",
            "required": ["available"],
            "properties": {
              "available": { "type": "boolean" },
              "url_on_ir_page": { "type": "string", "format": "uri", "nullable": true }
            }
          },
          "_self": { "type": "string", "format": "uri" }
        }
      },
      "EarningsCallListResponse": {
        "type": "object",
        "required": ["ticker", "calls", "pagination", "_self"],
        "properties": {
          "ticker": { "type": "string" },
          "calls": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/EarningsCall" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" },
          "_self": { "type": "string", "format": "uri" }
        }
      },
      "PressRelease": {
        "type": "object",
        "required": ["id", "ticker", "title", "url", "published_at", "category", "_self"],
        "properties": {
          "id": { "type": "string", "example": "pr_01HX..." },
          "ticker": { "type": "string" },
          "title": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "published_at": { "type": "string", "format": "date-time" },
          "category": {
            "type": "string",
            "enum": ["earnings", "guidance", "corporate_action", "product", "other"]
          },
          "summary_first_paragraph": { "type": "string" },
          "fetched_at": { "type": "string", "format": "date-time" },
          "_self": { "type": "string", "format": "uri" }
        }
      },
      "PressReleaseListResponse": {
        "type": "object",
        "required": ["ticker", "press_releases", "pagination", "_self"],
        "properties": {
          "ticker": { "type": "string" },
          "press_releases": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PressRelease" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" },
          "_self": { "type": "string", "format": "uri" }
        }
      },
      "Pagination": {
        "type": "object",
        "required": ["next_cursor", "has_more"],
        "properties": {
          "next_cursor": { "type": "string", "nullable": true },
          "has_more": { "type": "boolean" }
        }
      },
      "ParsedTranscript": {
        "type": "object",
        "required": ["call_id", "qa_pairs"],
        "properties": {
          "call_id": { "type": "string" },
          "prepared_remarks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "speaker": { "type": "string" },
                "speaker_role": { "type": "string", "example": "CEO" },
                "text": { "type": "string" }
              }
            }
          },
          "qa_pairs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "analyst": { "type": "string" },
                "analyst_firm": { "type": "string" },
                "question": { "type": "string" },
                "responder": { "type": "string" },
                "responder_role": { "type": "string" },
                "answer": { "type": "string" }
              }
            }
          }
        }
      },
      "CallScore": {
        "type": "object",
        "required": ["call_id"],
        "properties": {
          "call_id": { "type": "string" },
          "skepticism": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 10,
            "example": 7.4
          },
          "evasion": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 10,
            "example": 6.1
          },
          "hedging_density": { "type": "number", "format": "float", "example": 0.18 },
          "rationale": { "type": "string" }
        }
      },
      "Executive": {
        "type": "object",
        "required": ["id", "name", "ticker"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "ticker": { "type": "string" },
          "role": { "type": "string", "example": "CEO" },
          "tenure_start": { "type": "string", "format": "date" },
          "tenure_end": { "type": "string", "format": "date", "nullable": true }
        }
      },
      "ExecutiveTrackRecord": {
        "type": "object",
        "properties": {
          "executive_id": { "type": "string" },
          "statements": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "call_id": { "type": "string" },
                "quote": { "type": "string" },
                "outcome": { "type": "string" },
                "outcome_status": {
                  "type": "string",
                  "enum": ["confirmed", "contradicted", "pending"]
                }
              }
            }
          }
        }
      },
      "Analyst": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "firm": { "type": "string" },
          "skepticism_accuracy_rating": { "type": "number", "format": "float", "example": 0.71 },
          "questions_asked": { "type": "integer", "example": 142 }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "request_id", "documentation_url"],
            "properties": {
              "code": { "type": "string", "example": "ticker_not_found" },
              "message": { "type": "string", "example": "No company found for ticker." },
              "request_id": { "type": "string", "format": "uuid" },
              "documentation_url": { "type": "string", "format": "uri" },
              "planned_launch": {
                "type": "string",
                "description": "Present only on 503 data_not_yet_available responses."
              }
            }
          }
        }
      }
    }
  }
}
