{
  "openapi": "3.1.0",
  "info": {
    "title": "PSX Investors Public Data API",
    "version": "1.0.0",
    "description": "Read-only market data endpoints for the PSX Investors website. New integrations should use the stable /api/v1/ URL paths. The unversioned paths remain compatibility aliases. Future breaking changes will use a new major URL version, and deprecated versions will be announced on the developer portal with a documented Sunset timeline. Market data may be unavailable outside market hours or when an official source cannot be verified. This API is not investment advice."
  },
  "servers": [
    {
      "url": "https://psxinvestors.pk"
    }
  ],
  "paths": {
    "/api/v1/market-data/": {
      "get": {
        "operationId": "getKse100MarketData",
        "summary": "Get the latest verified KSE-100 quote",
        "description": "Returns a quote only when it can be obtained and validated from an official PSX source. The endpoint does not provide investment advice.",
        "responses": {
          "200": {
            "description": "Quote or a structured unavailable response",
            "headers": {
              "API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MarketDataResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "headers": {
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/api/v1/psx-stocks/": {
      "get": {
        "operationId": "listPsxStocks",
        "summary": "List available PSX stock quotes",
        "description": "Returns verified Yahoo Finance quotes where available. Missing quotes are not replaced with fabricated values.",
        "parameters": [
          {
            "name": "sector",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Optionally filter by sector."
          }
        ],
        "responses": {
          "200": {
            "description": "Verified quote list",
            "headers": {
              "API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StockListResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "headers": {
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "No verified quote data is currently available",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "ApiVersion": {
        "description": "Version of the API response.",
        "schema": { "type": "string", "example": "1" }
      },
      "RateLimitLimit": {
        "description": "Maximum requests permitted in the current one-minute window.",
        "schema": { "type": "integer", "minimum": 1 }
      },
      "RateLimitPolicy": {
        "description": "Rate-limit policy using the limit and window in seconds.",
        "schema": { "type": "string", "example": "60;w=60" }
      },
      "RetryAfter": {
        "description": "Seconds until the client should retry.",
        "schema": { "type": "integer", "minimum": 1 }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": ["success", "error"],
        "properties": {
          "success": { "const": false },
          "error": { "type": "string" },
          "code": { "type": "string" },
          "retryAfterSeconds": { "type": "integer", "minimum": 1 }
        }
      },
      "MarketDataResponse": {
        "type": "object",
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean" },
          "source": { "type": "string" },
          "timestamp": { "type": "string", "format": "date-time" },
          "error": { "type": "string" },
          "data": { "$ref": "#/components/schemas/MarketQuote" }
        }
      },
      "MarketQuote": {
        "type": "object",
        "required": ["index", "change", "changePercent", "previousClose", "source"],
        "properties": {
          "index": { "type": "number" },
          "change": { "type": "number" },
          "changePercent": { "type": "number" },
          "previousClose": { "type": "number" },
          "dayHigh": { "type": "number" },
          "dayLow": { "type": "number" },
          "week52High": { "type": "number" },
          "week52Low": { "type": "number" },
          "volume": { "type": "number" },
          "timestamp": { "type": "integer" },
          "source": { "type": "string" }
        }
      },
      "StockListResponse": {
        "type": "object",
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean" },
          "data": {
            "type": "object",
            "required": ["stocks", "topGainers", "topLosers", "lastUpdated", "source", "sectors"],
            "properties": {
              "stocks": { "type": "array", "items": { "$ref": "#/components/schemas/StockQuote" } },
              "topGainers": { "type": "array", "items": { "$ref": "#/components/schemas/StockQuote" } },
              "topLosers": { "type": "array", "items": { "$ref": "#/components/schemas/StockQuote" } },
              "lastUpdated": { "type": "integer" },
              "source": { "type": "string" },
              "sectors": { "type": "array", "items": { "type": "string" } }
            }
          },
          "error": { "type": "string" }
        }
      },
      "StockQuote": {
        "type": "object",
        "required": ["symbol", "name", "sector", "price", "change", "changePercent", "lastUpdated"],
        "properties": {
          "symbol": { "type": "string" },
          "name": { "type": "string" },
          "sector": { "type": "string" },
          "price": { "type": "number" },
          "change": { "type": "number" },
          "changePercent": { "type": "number" },
          "volume": { "type": "number" },
          "dayHigh": { "type": "number" },
          "dayLow": { "type": "number" },
          "previousClose": { "type": "number" },
          "lastUpdated": { "type": "integer" }
        }
      }
    }
  }
}
