{
  "openapi": "3.1.0",
  "info": {
    "title": "DilutionLens API",
    "version": "1.0.0",
    "description": "Per-ticker ASX dilution data: dilution snapshots free, full raise history / options / cash runway / issuance timeline / insider dealings on paid plans. Raise history, options and the issuance timeline are also served as CSV by appending .csv to those paths. One company per call — there are no bulk, batch or market-wide endpoints at any tier; for bulk data contact pro@dilutionlens.com. Authentication is an API key sent as the x-api-key header (never Authorization, which the CDN reserves), minted at https://dilutionlens.com/account/. Keyed calls share one per-account hourly rate budget with the website; the free snapshot is additionally limited to roughly 20 calls per day per caller. An MCP server with the same tools runs at https://dilutionlens.com/mcp — see https://dilutionlens.com/developers/."
  },
  "servers": [{ "url": "https://dilutionlens.com" }],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Created and revoked at https://dilutionlens.com/account/. Shown once at creation; stored hashed."
      }
    },
    "parameters": {
      "ticker": {
        "name": "ticker",
        "in": "path",
        "required": true,
        "schema": { "type": "string", "pattern": "^[A-Za-z0-9]{2,8}$" },
        "description": "One ASX ticker code, e.g. BHP."
      }
    },
    "responses": {
      "unauthorized": {
        "description": "Missing, unknown or revoked API key. The body carries an error code (auth_required | invalid_key)."
      },
      "paymentRequired": {
        "description": "This endpoint is part of a paid plan (error code unlock_required). Plans: https://dilutionlens.com/pricing/"
      },
      "rateLimited": {
        "description": "The shared per-account budget (or the free daily cap) is spent. Hourly budgets reset at the top of the hour; the free cap resets at midnight UTC."
      },
      "badRequest": {
        "description": "Unknown ticker, unknown section, or a bulk-shaped request (error code per_ticker_only, answered with the professional contact address)."
      }
    }
  },
  "paths": {
    "/api/v1/company/{ticker}/snapshot": {
      "get": {
        "summary": "Free dilution snapshot for one company",
        "description": "Headline metrics as shown on the free company page: dilution risk level, cash cover band, market cap, industry, 12-month raise count, max dilution percent, and a link to the page. Works without a key (~20 calls/day per caller, per UTC day).",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{}, { "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The snapshot.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "400": { "$ref": "#/components/responses/badRequest" },
          "429": { "$ref": "#/components/responses/rateLimited" }
        }
      }
    },
    "/api/v1/company/{ticker}/raises": {
      "get": {
        "summary": "Every capital raise on record for one company (paid)",
        "description": "Identical to the paid company page's raise history: every raise with date, type, amount and per-raise detail, cited to the source announcements.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The raise history.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/options": {
      "get": {
        "summary": "Every option and convertible line for one company (paid)",
        "description": "Identical to the paid company page's options block: each line with its terms, expiry and in-the-money value.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The options detail.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/cash": {
      "get": {
        "summary": "Quarterly cash and runway history for one company (paid)",
        "description": "Identical to the paid company page's cash detail (IQ Cash): quarterly figures and cover, for companies that file quarterly cash reports.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The cash history.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/timeline": {
      "get": {
        "summary": "The share-issuance timeline for one company (paid)",
        "description": "Every issuance-relevant filing for the company, dated and cited — identical to the paid company page's timeline.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The timeline.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/insiders": {
      "get": {
        "summary": "Director dealing notices for one company (paid)",
        "description": "Identical to the paid company page's dealings block, cited to the filings.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The dealing notices.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/raises.csv": {
      "get": {
        "summary": "Every capital raise on record for one company, as CSV (paid)",
        "description": "The rows of /api/v1/company/{ticker}/raises, serialised as CSV. Columns are that endpoint's own JSON field names, one row per raise. The response carries Content-Disposition: attachment with the filename <TICKER>-raises-<YYYY-MM-DD>.csv, dated by the build the rows came from rather than by the download. Per-ticker only, and counted against the same shared budget as every other keyed call.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The CSV file. An empty body means the company has no rows on record.",
            "content": { "text/csv": { "schema": { "type": "string" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/options.csv": {
      "get": {
        "summary": "Every option and convertible line for one company, as CSV (paid)",
        "description": "The rows of /api/v1/company/{ticker}/options, serialised as CSV. Where the lines are adjusted for a share consolidation, a consolidation_adjusted column carries that fact — the same caveat the page prints above the table. Content-Disposition names the file <TICKER>-options-<YYYY-MM-DD>.csv. Per-ticker only.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The CSV file. An empty body means the company has no rows on record.",
            "content": { "text/csv": { "schema": { "type": "string" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/company/{ticker}/timeline.csv": {
      "get": {
        "summary": "The share-issuance timeline for one company, as CSV (paid)",
        "description": "The rows of /api/v1/company/{ticker}/timeline, serialised as CSV. Columns are that endpoint's own JSON field names, one row per filing. The timeline itself is capped at the 200 most recent issuance filings, so a company with a longer history exports those 200 and not its whole record — the JSON endpoint and the website's own table carry exactly the same 200. Content-Disposition names the file <TICKER>-timeline-<YYYY-MM-DD>.csv. Per-ticker only.",
        "parameters": [{ "$ref": "#/components/parameters/ticker" }],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "The CSV file. An empty body means the company has no rows on record.",
            "content": { "text/csv": { "schema": { "type": "string" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    },
    "/api/v1/screen": {
      "get": {
        "summary": "Screen the market (paid, top 20 rows)",
        "description": "Filter and sort the universe by dilution risk, cash cover band, market-cap band, industry or name. Returns at most 20 rows — always the TOP rows of the requested ordering; there is no offset paging on this endpoint (an explicit offset, or a limit above 20, is ignored and reported in the response's ignored list). A discovery tool, not an extract. Query parameters match the public screener's URL vocabulary: q, risk, cover, cap, industry, sort, dir.",
        "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string" }, "description": "Name or ticker search." },
          { "name": "risk", "in": "query", "schema": { "type": "string" }, "description": "Very high | High | Moderate | Low | Minimal | Not rated." },
          { "name": "cover", "in": "query", "schema": { "type": "string" }, "description": "<2q | 2-4q | 4+q | na." },
          { "name": "cap", "in": "query", "schema": { "type": "string" }, "description": "nano | micro | small | mid | large | na." },
          { "name": "industry", "in": "query", "schema": { "type": "string" } },
          { "name": "sort", "in": "query", "schema": { "type": "string" }, "description": "risk | cover | mktcap | raises | ticker | name | industry | itm | pending | expiry | short." },
          { "name": "dir", "in": "query", "schema": { "type": "string" }, "description": "asc | desc." }
        ],
        "security": [{ "apiKey": [] }],
        "responses": {
          "200": {
            "description": "Up to 20 matching rows plus the honest total.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "401": { "$ref": "#/components/responses/unauthorized" },
          "402": { "$ref": "#/components/responses/paymentRequired" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "400": { "$ref": "#/components/responses/badRequest" }
        }
      }
    }
  }
}
