Product Reports Resources Pricing Login Book a demo

Cookbook 01 ยท Startup discovery

Turn an investment thesis into a ranked startup shortlist

Translate a plain-language thesis into Dealroom taxonomy and filters, then rank the matching companies by signal score.

Python 10 minutes 4 API calls Beginner
GET /data/companies 200 OK
and(
  tag_id[in_all]:industrial_automation|ai,
  hq_location[eq]:europe,
  launch_date[gte]:2020,
  total_funding[lte]:50000000,
  signal_rating[gte]:65
)
sort=-signal_rating

Loading the result snapshot...

16matching companies
8returned in shortlist
3values resolved first

The goal

Start with a thesis, not an endpoint

Most scouting workflows begin as a sentence. The useful work is turning each part of that sentence into a filter the API can apply consistently.

European industrial automation startups using AI, founded since 2020, with no more than $50M raised and a Dealroom signal score of at least 65.

This guide resolves the three human-readable taxonomy values at runtime, sends one company list request, and sorts the result by signal score. The live query currently finds 16 companies and returns the top eight.

Why a list endpoint?

The output is a list of companies. Use GET /data/companies. Aggregate endpoints are for grouped metrics such as funding by year or company count by country.

Step 1

Authenticate once, then let the client refresh

Create a Programmatic M2M key in Dealroom and keep both credentials on the server. The downloadable script uses OAuth2 client credentials and retries once with a fresh token after a 401 response.

.env
DEALROOM_CLIENT_ID=your_client_id
DEALROOM_CLIENT_SECRET=your_client_secret
DEALROOM_USER_AGENT=your-company-thesis-shortlist/1.0

Install the three small dependencies used by the example:

terminal
pip install authlib requests python-dotenv

Do not put a Programmatic M2M secret in browser code. Run this script on a server, in a scheduled job, or locally.

Step 2

Resolve names to taxonomy IDs

Filters use stable IDs, but a thesis uses names such as Europe, Industrial Automation, and Artificial Intelligence. Resolve those names before constructing the filter instead of copying IDs into your application.

thesis_to_shortlist.py
def exact_value(items, label, source_type=None):
    for item in items:
        item_label = item.get("label") or item.get("name", "")
        item_type = item.get("source_type") or item.get("type")
        if item_label.casefold() == label.casefold() and (
            source_type is None or item_type == source_type
        ):
            return str(item.get("value") or item["id"])
    raise LookupError(f"Could not resolve {label!r}")

europe_id = resolve_location("Europe", "continent")
industrial_id = resolve_tag("Industrial Automation", "sector")
ai_id = resolve_tag("Artificial Intelligence", "technology")

Location discovery returns name/id. Cross-filter search returns label/value. The helper accepts both response shapes, then requires an exact case-insensitive label and the expected taxonomy type.

Resolved for this run

Europe is location 34. Industrial Automation is sector tag 99301. Artificial Intelligence is technology tag 202. The code still discovers them each time so taxonomy changes fail visibly.

Step 3

Translate each thesis clause into a filter

The filter DSL keeps the query readable. Each clause corresponds to one decision in the thesis.

Thesis clauseAPI filter
Industrial automation and AItag_id[in_all]:99301|202
Headquartered in Europehq_location[eq]:34
Startup and still operatingis_startup[eq]:true + company_status[eq]:operational
Founded since 2020launch_date[gte]:2020
No more than $50M raisedtotal_funding[lte]:50000000
Signal score of at least 65signal_rating[gte]:65
thesis_to_shortlist.py
filters = [
    f"tag_id[in_all]:{industrial_id}|{ai_id}",
    f"hq_location[eq]:{europe_id}",
    "is_startup[eq]:true",
    "company_status[eq]:operational",
    "launch_date[gte]:2020",
    "total_funding[lte]:50000000",
    "signal_rating[gte]:65",
]

company_filter = f"and({','.join(filters)})"

The in_all operator matters here. It requires both tags. Using in_any would also return general AI companies and industrial automation companies without AI.

Step 4

Rank on the server

Ask the list endpoint for the top eight records ordered by descending signal score. Set include_total=true so the response also tells you how many companies matched before the limit was applied.

thesis_to_shortlist.py
result = client.get(
    "/data/companies",
    params={
        "filter": company_filter,
        "sort": "-signal_rating",
        "limit": 8,
        "include_total": "true",
    },
)

print(result["page"]["total"])
print(result["data"][0]["name"])

Company rows already include the fields needed for a first-pass shortlist, including the tagline, headquarters, founding year, funding summary, team size, tags, hiring status, founders, and signal score.

The output

A shortlist you can inspect

Top eight of 16 matches, ranked by signal score.

JSON

Loading the result snapshot...

Snapshot generated 2 Sep 2026. Funding values are shown in USD. Dealroom signal scores are discovery aids, not investment recommendations.

Next steps

Turn the shortlist into a workflow

This example stops at a ranked list. A production scouting workflow can add a small amount of state and human judgment:

  • Run the query on a schedule and store the company UUIDs you have already reviewed.
  • Flag newly matched companies and meaningful changes in funding, headcount, or hiring.
  • Add your own score for thesis fit instead of treating the Dealroom signal score as a final decision.
  • Write analyst notes and decisions to your CRM, database, or internal scouting tool.

Complete example

Run the full Python script

The download includes authentication, runtime taxonomy discovery, the complete filter, and clean JSON output.