For AI agents
Machine-readable access to the Security Startups catalog and its stats. No key for reads. Connect an assistant with one URL over MCP, or call the HTTP endpoints below.
OpenAPI
Machine-readable spec for the public catalog: /openapi.json. Search, dump, stats, the MCP endpoint and the priority listing checkout. No auth. Versioned aliases live at /api/v1/search and /api/v1/startups.json.
Catalog search API
GET https://securitystartups.com/api/search?category=application-security&q=authz GET https://securitystartups.com/api/search?funding_stage=Series%20A&limit=20 GET https://securitystartups.com/api/search?category=ai-security&limit=100
Params: category, funding_stage (repeatable, comma-separable), q, limit (default 50; if present, must be an integer from 1 to 100, else HTTP 400 JSON). Category values are listed in /api/startups.json. Also at GET /api/v1/search.
Response fields: total (matches before limit), count (results returned this page), limit (applied cap), normalized, results. Prefer total for catalog size under a filter; unfiltered full size is also on the dump below.
Full dump
GET https://securitystartups.com/api/startups.json
Shape: count, categoryCount, categories, startups (full public fields, alphabetical by name), dataAsOf (latest catalog date_added), lastUpdated (response date).
llms.txt
/llms.txt (index: categories, machine endpoints, counts) and /llms-full.txt (full catalog text, same company count as the JSON dump).
Human category indexes (alphabetical within category, not ranked): /categories.
Stats API
GET https://securitystartups.com/api/v1/stats GET https://securitystartups.com/api/v1/stats/history
/api/v1/stats returns the five charts of /stats as JSON: each with n, covered, coverage, caveat, method, asOf, a license object, its CSV and image URLs, and the data (bars or rows, the same numbers as the CSV). /api/v1/stats/history lists the quarterly snapshots and one series per chart; it never fills gaps, so with one snapshot it returns points: 1 and a note saying when history starts. Breakdowns of listed companies, never market totals. CC BY 4.0: credit "Security Startups (securitystartups.com)" with a link. CORS is open. Both are built at deploy time and share the per-IP budget of the other API routes.
MCP server (remote, read-only)
https://securitystartups.com/mcp
Add it in Claude as a custom connector (Settings, Connectors), in ChatGPT as a connector in developer mode (Settings, Apps and connectors), or in Cursor as an MCP server (Settings, MCP): paste the URL, no key or install.
Tools: search_startups (query, category, funding_stage, limit up to 50), get_startup (slug), check_if_listed (company_name), list_categories, get_stats (optional chart slug) and get_stats_history. Every result carries the attribution and the company or chart URL. Read-only: no tool submits or pays; listing goes through /submit. Streamable HTTP, stateless, JSON responses (POST only; GET returns 405). Limit: 60 requests per minute per IP. Protocol details in /openapi.json. The same tools run over stdio from mcp-server/ in the repo (the npm package is not published).
Submit a company
Humans and agents: /submit. Free submissions go through the Tally form linked from /submit/free (or by email) into a review queue: every submission is reviewed before it goes live, within about 90 days. The priority listing ($299, one-time) publishes within 24 hours of payment.
Direct API intake (POST /api/submit) is open when the operator flag is on and returns an honest 503 with a pointer to the form when it is off. Submissions require a proof-of-life link (funding, launch, or news). The MCP server has no submit tool.
Priority listing ($299)
POST the listing details as JSON to /api/checkout. The response carries a Stripe Checkout link. Hand that link to your human: an agent cannot pay by itself, and nothing is charged until a person pays on Stripe. Same curation bar as the free queue. It buys queue position, never rank. Published within 24 hours of payment; if we cannot list it, full refund.
POST https://securitystartups.com/api/checkout
Content-Type: application/json
{
"email": "you@company.example",
"name": "Example Security",
"url": "https://example.security",
"proof_source_url": "https://news.example.org/example-security-seed",
"brief_summary": "What the company builds, in one or two sentences.",
"category": "application-security"
}
200 {"url": "https://checkout.stripe.com/...", "sessionId": "cs_...", "intentId": "..."}Required: email, name (2 to 120 characters), url, proof_source_url (a funding, launch, or news link), brief_summary (20 to 300 characters) and category (a category slug or name from /api/v1/startups.json). Optional: description, hq, country, founded, funding_stage, total_funding, tags (array, up to 8), signal, linkedin. A url without a scheme gets https:// added. Over-long values are cut to the limits in the OpenAPI document rather than rejected. Send one JSON object (anything else returns 400), up to 32 KB.
Handled errors return JSON {ok: false, error}. 400: invalid JSON, moderation, or validation (with a per-field errors map). 409: already listed or already in the queue. 413: body too large. 429: too many attempts (8 per minute per IP), with Retry-After when the edge limiter answers. 503: checkout is not open right now, including when the daily session budget is spent; use the free form instead. 500: Stripe or server error, safe to retry later. Retrying with the same url and email before payment returns the still-open checkout link, or a fresh one if it expired. Full schema in /openapi.json.