VendorStacks
← All posts
GTM8 min read

Tech Stack Lookup API: Filtering Leads by Vendor Combinations and Stack Patterns

How to use tech stack lookup APIs to find companies matching specific vendor combinations—like Stripe + Salesforce or OpenAI + Snowflake—for targeted outreach and market segmentation.

Stax
VendorStacks research desk

Tech Stack Lookup API: Filtering Leads by Vendor Combinations and Stack Patterns

Most tech stack lookup use cases start with a single vendor: find everyone using Stripe, or everyone using OpenAI. But the highest-intent prospects often emerge when you filter by combinations—companies using both Stripe and Salesforce, or running OpenAI models on Google Cloud infrastructure, or storing data in Snowflake while using HubSpot for marketing.

This post walks through how to use a tech stack lookup API to build lead lists based on vendor combinations, with real implementation patterns and code examples.

Why Vendor Combinations Matter More Than Single Vendors

If you sell a Stripe-to-HubSpot sync tool, the 254 companies in our index using Stripe are your total addressable market—but the subset using both Stripe and HubSpot (132 companies use HubSpot) represents your highest-intent segment. They already have both systems; your product solves an immediate integration gap.

Similarly:

  • If you sell AI observability tooling, companies using OpenAI (190 in our index) and running production infrastructure on AWS (309 companies) or Google Cloud (156 companies) are more likely to need monitoring than hobby projects.
  • If you sell a Snowflake cost optimizer, companies with both Snowflake (120 companies) and a modern analytics stack (Google Analytics at 286 companies) likely have data teams spending real budget.
  • Security vendors targeting companies with compliance obligations can filter for companies using privacy-compliance tools and storing payment data (Stripe).

Single-vendor queries cast a wide net. Combination queries surface qualified leads.

Implementation Pattern: Check Then Filter

The VendorStacks API doesn't offer native boolean filters, but you can implement combination logic in two ways: sequential lookups with client-side filtering, or reverse lookup followed by verification.

Method 1: Reverse Lookup + Verification

Start with a reverse lookup for your anchor vendor (the less common one), then verify the second vendor in each result.

import requests

API_KEY = "vr_live_your_key_here"
BASE_URL = "https://api.vendorstacks.com/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}

def get_companies_with_both(vendor_primary, vendor_secondary, max_results=50):
    """
    Find companies using both vendor_primary AND vendor_secondary.
    Returns list of {domain, vendor_stack, scanned_at}.
    """
    companies_with_both = []
    page = 1
    
    while len(companies_with_both) < max_results:
        # Reverse lookup for primary vendor
        resp = requests.get(
            f"{BASE_URL}/prospect",
            headers=headers,
            params={"vendor": vendor_primary, "page": page}
        )
        resp.raise_for_status()
        data = resp.json()
        
        if not data.get("companies"):
            break  # No more results
        
        for company in data["companies"]:
            domain = company["domain"]
            
            # Check if this company also uses the secondary vendor
            check_resp = requests.get(
                f"{BASE_URL}/check",
                headers=headers,
                params={"url": domain}
            )
            check_resp.raise_for_status()
            stack_data = check_resp.json()
            
            if not stack_data.get("found"):
                continue  # No public evidence found
            
            # Flatten vendor_stack categories into single list
            all_vendors = []
            for category_vendors in stack_data.get("vendor_stack", {}).values():
                all_vendors.extend(category_vendors)
            
            if vendor_secondary in all_vendors:
                companies_with_both.append({
                    "domain": domain,
                    "vendor_stack": stack_data["vendor_stack"],
                    "scanned_at": stack_data.get("scanned_at")
                })
                
                if len(companies_with_both) >= max_results:
                    break
        
        page += 1
    
    return companies_with_both

# Example: Find companies using both Snowflake and Salesforce
results = get_companies_with_both("Snowflake", "Salesforce", max_results=20)
for company in results:
    print(f"{company['domain']}: {len(company['vendor_stack'])} categories")

Cost structure: You pay 1 credit per result from the reverse lookup, then 1 credit per /check call. If Snowflake's reverse lookup returns 10 companies per page and you check all 10, that's 10 credits (reverse results) + 10 credits (checks) = 20 credits per page. Companies that don't match your secondary filter still cost credits, so this works best when your primary vendor is the rarer one.

Method 2: Pre-Filter with Category Logic

If you're looking for "any payments vendor + any CRM," you can filter by category presence instead of exact vendor names:

def check_category_combination(domain, required_categories):
    """
    Check if a domain has vendors in ALL required categories.
    required_categories: list like ["payments", "crm_sales"]
    """
    resp = requests.get(
        f"{BASE_URL}/check",
        headers=headers,
        params={"url": domain}
    )
    resp.raise_for_status()
    data = resp.json()
    
    if not data.get("found"):
        return False
    
    vendor_stack = data.get("vendor_stack", {})
    categories_found = [cat for cat, vendors in vendor_stack.items() if vendors]
    
    return all(cat in categories_found for cat in required_categories)

# Example: Check if a company uses both payments AND CRM tools
if check_category_combination("example.com", ["payments", "crm_sales"]):
    print("Match: company uses payments + CRM")

This is useful for broader segmentation ("companies with both data infrastructure and AI") without requiring exact vendor matches.

Real-World Filtering Scenarios

Scenario 1: AI Companies on Cloud Infrastructure

You sell GPU cost optimization for AI workloads. Your ICP is companies using OpenAI or Anthropic and running on AWS, Google Cloud, or Azure.

AI_VENDORS = ["OpenAI", "Anthropic"]
CLOUD_VENDORS = ["AWS", "Google Cloud", "Microsoft Azure"]

def is_ai_on_cloud(vendor_stack):
    all_vendors = []
    for vendors in vendor_stack.values():
        all_vendors.extend(vendors)
    
    has_ai = any(v in all_vendors for v in AI_VENDORS)
    has_cloud = any(v in all_vendors for v in CLOUD_VENDORS)
    return has_ai and has_cloud

# Start with OpenAI reverse lookup, filter for cloud
resp = requests.get(
    f"{BASE_URL}/prospect",
    headers=headers,
    params={"vendor": "OpenAI", "page": 1}
)
companies = resp.json().get("companies", [])

for company in companies:
    check = requests.get(
        f"{BASE_URL}/check",
        headers=headers,
        params={"url": company["domain"]}
    ).json()
    
    if check.get("found") and is_ai_on_cloud(check["vendor_stack"]):
        print(f"Qualified lead: {company['domain']}")

From our index: 190 companies use OpenAI, 160 use Anthropic. The subset running on major cloud platforms (309 AWS + 156 GCP + 130 Azure = hundreds of potential overlaps) represents production AI deployments, not experimental use.

Scenario 2: E-commerce Companies with Modern Marketing Stacks

You sell a post-purchase survey tool. You want Stripe or Shopify users who also run Google Analytics or HubSpot (indicating they care about conversion data).

PAYMENT_VENDORS = ["Stripe"]  # 254 companies in index
ANALYTICS_VENDORS = ["Google Analytics", "HubSpot"]  # 286 + 132

def qualifies_for_survey_tool(vendor_stack):
    all_vendors = []
    for vendors in vendor_stack.values():
        all_vendors.extend(vendors)
    
    has_payments = any(v in all_vendors for v in PAYMENT_VENDORS)
    has_analytics = any(v in all_vendors for v in ANALYTICS_VENDORS)
    return has_payments and has_analytics

This surfaces companies with both transaction flow (Stripe) and conversion tracking infrastructure.

Scenario 3: Data Teams with Specific Stack Patterns

You sell a data quality monitoring tool for companies running Snowflake with cloud-native ETL (not legacy warehouses). Filter for Snowflake + (AWS or GCP), excluding companies showing no cloud infrastructure.

def is_modern_data_stack(vendor_stack):
    all_vendors = []
    for vendors in vendor_stack.values():
        all_vendors.extend(vendors)
    
    has_snowflake = "Snowflake" in all_vendors
    has_modern_cloud = any(v in all_vendors for v in ["AWS", "Google Cloud"])
    
    return has_snowflake and has_modern_cloud

Snowflake appears in 120 companies in our index; the subset on AWS (309 companies) or GCP (156 companies) likely represents production data warehouses vs. sandbox environments.

Optimizing Credit Usage for Combination Queries

Key principle: You only pay for successful results. A /check that returns "found": false costs 0 credits. A reverse lookup page with zero results costs 0 credits.

To minimize costs when filtering combinations:

  1. Start with the rarer vendor: If you want "Stripe + Salesforce," and Salesforce (116 companies) is less common than Stripe (254 companies), run the reverse lookup on Salesforce first. Fewer results to verify = lower cost.
  1. Batch verification: If you're checking 50 domains, make the /check calls in parallel (respecting rate limits) rather than sequentially. Faster results, same cost.
  1. Cache results: If you're running the same combination query daily, cache the vendor stacks locally and only re-check domains that haven't been scanned recently (use the scanned_at timestamp).
  1. Use category filters first: If "any payments vendor + any CRM" works for your use case, you can filter client-side on category presence without needing exact vendor name matches, reducing the number of confirmation calls.

Handling Edge Cases

Empty reverse lookups: If GET /prospect?vendor=X returns no companies, that vendor either isn't in the index yet or has very low adoption. This costs 0 credits.

Scans that find nothing: If you call /check?url=domain.com and get "found": false, the company has no public vendor evidence. This costs 0 credits, but it doesn't mean they use nothing—just that we found no public signals.

Vendor name matching: Vendor names in the API are normalized ("Google Cloud" not "GCP", "Microsoft Azure" not "Azure"). Check the evidence fields in an initial query to confirm exact spelling before building filters.

Combining This with Your CRM

Once you've identified companies matching your vendor combination, you typically want to:

  1. Enrich CRM records: Push the vendor stack data into Salesforce, HubSpot, or your CRM as custom fields. See our guide on CRM enrichment for implementation details.
  1. Trigger outreach sequences: If a company starts using both vendors in your target combination (detected via a weekly re-scan), automatically add them to a nurture campaign.
  1. Score leads: Assign higher scores to companies matching multiple vendor criteria (e.g., +10 points for Stripe, +10 for Salesforce, +20 if both).

The vendor stack data from /check includes vendor_stack (categorized), scanned_at (ISO timestamp), and *_evidence fields (the actual source rows we extracted). You can store all of this or just the vendor names, depending on your use case.

Example: End-to-End Combination Query

Here's a complete script that finds companies using both Stripe and Google Analytics, formats the output, and shows credit consumption:

import requests
import json

API_KEY = "vr_live_your_key_here"
BASE_URL = "https://api.vendorstacks.com/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}

def find_stripe_and_analytics(max_results=10):
    results = []
    page = 1
    initial_balance = None
    
    while len(results) < max_results:
        # Reverse lookup for Stripe
        resp = requests.get(
            f"{BASE_URL}/prospect",
            headers=headers,
            params={"vendor": "Stripe", "page": page}
        )
        data = resp.json()
        
        if initial_balance is None:
            initial_balance = data.get("credit_balance")
        
        companies = data.get("companies", [])
        if not companies:
            break
        
        for company in companies:
            # Verify they also use Google Analytics
            check_resp = requests.get(
                f"{BASE_URL}/check",
                headers=headers,
                params={"url": company["domain"]}
            )
            check_data = check_resp.json()
            
            if not check_data.get("found"):
                continue
            
            all_vendors = []
            for vendors in check_data.get("vendor_stack", {}).values():
                all_vendors.extend(vendors)
            
            if "Google Analytics" in all_vendors:
                results.append({
                    "domain": company["domain"],
                    "vendors": all_vendors,
                    "scanned_at": check_data.get("scanned_at")
                })
                
            if len(results) >= max_results:
                break
        
        page += 1
    
    # Check final balance
    balance_resp = requests.get(f"{BASE_URL}/balance", headers=headers)
    final_balance = balance_resp.json().get("credit_balance")
    credits_used = initial_balance - final_balance if initial_balance else None
    
    return results, credits_used

# Run the query
matches, credits = find_stripe_and_analytics(max_results=10)

print(f"Found {len(matches)} companies using both Stripe and Google Analytics")
print(f"Credits used: {credits}\n")

for match in matches:
    print(f"{match['domain']}: {len(match['vendors'])} total vendors")
    print(f"  Scanned: {match['scanned_at']}")

This will output something like:

Found 10 companies using both Stripe and Google Analytics
Credits used: 47

example1.com: 12 total vendors
  Scanned: 2024-01-15T10:23:11Z
example2.com: 8 total vendors
  Scanned: 2024-01-14T15:44:02Z
...

The credit cost includes both the reverse lookup results (1 credit per company returned) and the verification checks (1 credit per successful scan). Companies where the check returns "found": false don't add to the cost.

What This Unlocks

Filtering by vendor combinations transforms tech stack lookup from "list of companies using X" into "qualified leads matching our exact ICP." You can build:

  • Vertical-specific lists: "Fintech companies using Stripe + Plaid + Salesforce"
  • Technographic scoring: "Companies using 3+ vendors in our integration ecosystem"
  • Competitive displacement: "Companies using Competitor A + our integration partners"
  • Expansion triggers: "Existing customers who just added Vendor Y" (via weekly re-scans)

The implementation is straightforward: reverse lookup for the anchor vendor, verify the second vendor with /check, filter client-side. Costs scale with results, not queries, so failed matches don't burn budget.

Get started with a free API key at https://api.vendorstacks.com—25 credits, no card required. That's enough to test combination queries and see real vendor stacks for your target accounts.

About the author

Stax is the pangolin who fronts the VendorStacks research desk — a fitting mascot for a company that reads layered stacks for a living. Posts under this byline are written by the VendorStacks team.

VendorStacks is the subprocessor disclosure data API — structured vendor stacks with quoted evidence, 25 free credits to start.

Get an API key