{
  "openapi": "3.0.0",
  "info": {
    "title": "TraceAlpha Alternative Data API",
    "description": "Programmatic REST API for querying structured macroeconomic signals, supply chain insights, entity sentiment analysis, and dashboard statistics curated by TraceAlpha.\n\n### Authentication\n\nProtected endpoints support two authentication mechanisms:\n\n1. **Programmatic / Developer Access (Bearer Token)**: Include your API key in the `Authorization` header as a Bearer token: `Authorization: Bearer <your_api_key>`.\n2. **Browser Dashboard Session (Session Cookie)**: Secure HTTP-Only session cookie named `tracealpha_api_key`, automatically set on successful validation of a Magic Login link.\n\nSpecify either authentication mechanism to access premium endpoints.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/",
      "description": "Current Host (Relative URL)"
    },
    {
      "url": "https://tracealpha.io",
      "description": "TraceAlpha Production Server"
    }
  ],
  "paths": {
    "/api/stats": {
      "get": {
        "summary": "Retrieve Global Statistics",
        "description": "Fetch overall stats, including total entities, signals generated within the last 30 days, and signal count aggregated by sector.",
        "responses": {
          "200": {
            "description": "Successful stats retrieval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "totalEntities": {
                      "type": "integer",
                      "example": 1376
                    },
                    "totalSignals": {
                      "type": "integer",
                      "example": 542
                    },
                    "sectorStats": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "integer"
                      },
                      "example": {
                        "Agribusiness": 156,
                        "Clean Energy": 214,
                        "Technology": 172
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (unauthenticated users are limited to 30 requests per minute)"
          },
          "500": {
            "description": "Internal Database Error"
          }
        }
      }
    },
    "/api/signals": {
      "get": {
        "summary": "Query Alternative Data Signals",
        "description": "Returns a paginated list of extracted alternative data signals. Real-time signals (less than 48 hours old) require premium authentication and are redacted for free tier users.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Text search query targeting the signal impact summary",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter by event type exactly",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "Supply Chain Disruption",
                "Patent Filing",
                "Talent Pivot"
              ]
            }
          },
          {
            "name": "ticker",
            "in": "query",
            "description": "Filter by equity ticker symbol",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "figi",
            "in": "query",
            "description": "Filter by OpenFIGI composite code",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "company",
            "in": "query",
            "description": "Filter by company name (partial match)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sector",
            "in": "query",
            "description": "Filter by specific sector",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sentiment",
            "in": "query",
            "description": "Filter by exact sentiment score value (-1.00 to 1.00)",
            "required": false,
            "schema": {
              "type": "number",
              "format": "float"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "description": "Filter signals processed on or after this ISO date",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "description": "Filter signals processed on or before this ISO date",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "Sort order by processing timestamp",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "desc",
                "asc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number for pagination offset",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Count of objects returned per page",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Signals list retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "authorized": {
                      "type": "boolean",
                      "description": "Indicates whether a valid premium token was verified"
                    },
                    "signals": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Signal"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Database query error"
          }
        }
      }
    },
    "/api/sentiment-summary": {
      "get": {
        "summary": "Get Entity Sentiment Summary",
        "description": "Retrieve rolled-up entity statistics containing total signals count, weighted sentiment, materiality averages, and directional breakdowns. Note: For unauthenticated requests, rankings are truncated to the top 3 teaser items, and company-specific queries redact raw average_sentiment and weighted_sentiment scores to null.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "ticker",
            "in": "query",
            "description": "Search by ticker symbol",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "figi",
            "in": "query",
            "description": "Filter by FIGI index code",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sector",
            "in": "query",
            "description": "Filter by company sector name",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Column to order view results by",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ticker",
                "company_name",
                "total_signals",
                "average_sentiment",
                "average_materiality",
                "weighted_sentiment"
              ],
              "default": "weighted_sentiment"
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "Sort ordering direction",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "desc",
                "asc"
              ],
              "default": "desc"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page offset index",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Results per page count",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved entity summaries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "authorized": {
                      "type": "boolean"
                    },
                    "requires_premium": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntitySentimentSummary"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Query error"
          }
        }
      }
    },
    "/api/jobs": {
      "get": {
        "summary": "Fetch Background Job Runs",
        "description": "List the last 50 cron-triggered scraper and ingestion pipeline runs, automatically resolving zombie job failures.",
        "responses": {
          "200": {
            "description": "Successful jobs log retrieval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/JobRun"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database queries failed"
          }
        }
      }
    },
    "/api/auth/request": {
      "post": {
        "summary": "Request Passwordless Magic Login Link",
        "description": "Verifies if the email matches an active API key subscription, generates a one-time token, and sends it to the user via SMTP email (or logs it in development/Mailpit).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "example": "curator@company.com"
                  }
                }
              }
            }
          },
          "description": "Email address of the premium user"
        },
        "responses": {
          "200": {
            "description": "Generates link response (generic to prevent email harvesting)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string",
                      "example": "If your email is associated with a subscription, you will receive a login link shortly."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid email"
          },
          "500": {
            "description": "Database or SMTP server error"
          }
        }
      }
    },
    "/api/auth/magic": {
      "get": {
        "summary": "Authenticate Magic Login Token",
        "description": "Verifies token validity and expiration. Sets the secure HttpOnly cookie `tracealpha_api_key` containing the premium token, invalidates the token, and redirects to dashboard `/`.",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "description": "The unique magic UUID token emailed to the user",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "307": {
            "description": "Redirects to home page after setting the cookie headers"
          },
          "200": {
            "description": "HTML page error response if token validation fails"
          }
        }
      }
    },
    "/api/auth/session": {
      "get": {
        "summary": "Check Current Cookie Session status",
        "description": "Reads the browser cookie state and returns authentication variables.",
        "responses": {
          "200": {
            "description": "Returns session data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "email": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/signout": {
      "post": {
        "summary": "Sign Out User",
        "description": "Deletes the secure `tracealpha_api_key` cookie from the client browser.",
        "responses": {
          "200": {
            "description": "Successfully signed out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/sources": {
      "get": {
        "summary": "List Data Sources (Premium)",
        "description": "Fetch configured global templates or bespoke feeds. Requires a valid session cookie or premium Bearer token.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "is_global",
            "in": "query",
            "description": "Filter by template ('true') or entity-specific feeds ('false')",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful retrieval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DataSource"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized access (missing or invalid credentials)"
          }
        }
      },
      "post": {
        "summary": "Create Global Template (Premium)",
        "description": "Create a new global template in data_sources and write a delta log event. Requires a valid session cookie or premium Bearer token.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source_url",
                  "source_type",
                  "is_global"
                ],
                "properties": {
                  "source_url": {
                    "type": "string",
                    "example": "https://patents.google.com/?assignee={company_name}"
                  },
                  "source_type": {
                    "type": "string",
                    "example": "patent_filing"
                  },
                  "description": {
                    "type": "string"
                  },
                  "is_global": {
                    "type": "boolean",
                    "example": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Source created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/DataSource"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/entities": {
      "get": {
        "summary": "Query Tracked Entities (Premium)",
        "description": "Fetch a list of tracked public corporate entities. Allows filtering by a query parameter matching name, ticker, exchange, FIGI, or sector.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Search text to filter entities by company name, ticker, FIGI, or sector",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful retrieval of entities list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Entity"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized access (missing or invalid API key/session cookie)"
          },
          "500": {
            "description": "Database query or server execution error"
          }
        }
      },
      "post": {
        "summary": "Add Custom Tracked Entity (Premium)",
        "description": "Trigger an AI search grounding and OpenFIGI mapping flow to automatically discover, verify, and resolve details for a new public company entity, appending it to the database.",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "CookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The exact or colloquial company name to search, resolve, and tracking-enable.",
                    "example": "Shopify"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Entity successfully resolved, verified, and saved to database.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Entity"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request: Company name is missing or invalid."
          },
          "401": {
            "description": "Unauthorized: Invalid premium token or active session."
          },
          "409": {
            "description": "Conflict: Entity already exists (matched by exact name, resolved FIGI, or ticker + exchange)."
          },
          "422": {
            "description": "Unprocessable Entity: Google search grounding or OpenFIGI resolved details are incomplete or missing a valid FIGI."
          },
          "502": {
            "description": "Bad Gateway: Failure in resolving queries with external Google search grounding or OpenFIGI APIs."
          },
          "500": {
            "description": "Internal Server Error: e.g. server API key configuration error."
          }
        }
      }
    },
    "/api/admin/audit-logs": {
      "get": {
        "summary": "Query Audit Trail Logs (Admin-only)",
        "description": "Fetch chronological audit trail entries detailing who executed curation updates, deletions, or new creations. Requires session cookie.",
        "security": [
          {
            "CookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Audit trail retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLog"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Bearer Token",
        "description": "Authorization header using the format: Bearer <sk_live_tracealpha_your_key>. Essential for programmatic and curl integrations."
      },
      "CookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "tracealpha_api_key",
        "description": "Secure HTTP-Only session cookie used for browser authentication. Automatically set upon validation of a Magic Login link."
      }
    },
    "schemas": {
      "Entity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "company_name": {
            "type": "string",
            "example": "Tesla, Inc."
          },
          "ticker": {
            "type": "string",
            "example": "TSLA"
          },
          "exchange": {
            "type": "string",
            "example": "NASDAQ"
          },
          "composite_figi": {
            "type": "string",
            "example": "BBG000N9MNX3"
          },
          "sector": {
            "type": "string",
            "example": "Automotive / Clean Energy"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Signal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event_type": {
            "type": "string",
            "example": "Patent Filing"
          },
          "sentiment_score": {
            "type": "number",
            "nullable": true,
            "example": 0.45
          },
          "impact_summary": {
            "type": "string",
            "example": "Filing indicates development of high-efficiency solid-state batteries."
          },
          "source_document": {
            "type": "string",
            "nullable": true,
            "example": "google_patents_aapl_12.html"
          },
          "processed_at": {
            "type": "string",
            "format": "date-time"
          },
          "materiality_score": {
            "type": "integer",
            "nullable": true,
            "example": 4
          },
          "market_outlook": {
            "type": "string",
            "nullable": true,
            "example": "Bullish"
          },
          "investment_thesis": {
            "type": "string",
            "nullable": true,
            "example": "Supports long-term technology dominance in green transport sector."
          },
          "is_locked": {
            "type": "boolean"
          },
          "entities": {
            "type": "object",
            "properties": {
              "company_name": {
                "type": "string"
              },
              "ticker": {
                "type": "string"
              },
              "sector": {
                "type": "string"
              },
              "composite_figi": {
                "type": "string"
              }
            }
          }
        }
      },
      "EntitySentimentSummary": {
        "type": "object",
        "properties": {
          "entity_figi": {
            "type": "string"
          },
          "ticker": {
            "type": "string"
          },
          "company_name": {
            "type": "string"
          },
          "sector": {
            "type": "string"
          },
          "total_signals": {
            "type": "integer"
          },
          "average_sentiment": {
            "type": "number",
            "nullable": true
          },
          "average_materiality": {
            "type": "number"
          },
          "weighted_sentiment": {
            "type": "number",
            "nullable": true
          },
          "bullish_signals_count": {
            "type": "integer"
          },
          "bearish_signals_count": {
            "type": "integer"
          },
          "neutral_signals_count": {
            "type": "integer"
          },
          "premium_locked": {
            "type": "boolean"
          }
        }
      },
      "DataSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "source_url": {
            "type": "string"
          },
          "source_type": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "example": "validated"
          },
          "error_rate": {
            "type": "number"
          },
          "company_name": {
            "type": "string",
            "nullable": true
          },
          "ticker": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "last_checked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "is_global": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "user_email": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "target_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "details": {
            "type": "object",
            "description": "JSON representation of state differences (deltas) before and after modifications"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "JobRun": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "job_name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "processed_records": {
            "type": "integer"
          },
          "error_message": {
            "type": "string",
            "nullable": true
          }
        }
      }
    }
  }
}