VendorStacks
← All posts
GTM7 min read

Tech Stack Lookup API: Building Account Scoring Models with Vendor Categories

How to build scoring models that evaluate accounts by vendor category presence rather than individual tools—detecting infrastructure maturity, GTM sophistication, and buying signals programmatically.

Stax
VendorStacks research desk

Tech Stack Lookup API: Building Account Scoring Models with Vendor Categories

Most account scoring models that incorporate tech stack data focus on detecting individual vendors: "Do they use Salesforce? +10 points." This works when you're selling into a specific ecosystem, but it breaks down when you need to evaluate broader signals like infrastructure maturity, GTM sophistication, or security posture.

A better approach: score accounts based on vendor categories rather than individual tools. Instead of looking for Stripe specifically, detect whether a company has any payment processor. Instead of requiring Segment, detect whether they use any CDP or data integration tool.

This post walks through building category-based scoring models using the VendorStacks API, which returns tech stack data organized into 24 vendor categories.

Why Category-Based Scoring Works Better

Consider three real scenarios where individual-vendor scoring falls short:

Scenario 1: Payment infrastructure detection You sell fraud prevention tools. Your ICP uses online payments, but you don't care whether it's Stripe (189 companies in our index), Braintree, Adyen, or PayPal. You care that they process payments online. Scoring for "Stripe only" misses 70% of your addressable market.

Scenario 2: Data infrastructure maturity You sell a data warehouse connector. Your best customers have modern data stacks—they use some combination of cloud infrastructure, observability tools, and integration platforms. A company running AWS + Datadog + Fivetran scores identically to one running GCP + New Relic + Airbyte. Individual-vendor scoring forces you to maintain brittle logic for every tool permutation.

Scenario 3: GTM team sophistication You sell sales enablement software. You want companies with mature sales operations—CRM + marketing automation + analytics. Whether that's Salesforce + HubSpot + Google Analytics (common) or Pipedrive + ActiveCampaign + Mixpanel (less common) doesn't matter. Category presence signals operational maturity better than any single vendor.

The VendorStacks Category Schema

VendorStacks organizes detected vendors into 24 categories. Every vendor in the response includes its category alongside detection evidence:

{
  "vendor_stack": {
    "payments": [
      {
        "name": "Stripe",
        "detected_from": "subprocessor_urls",
        "evidence": "stripe.com",
        "vendor_confidence": "high"
      }
    ],
    "analytics_data": [
      {
        "name": "Google Analytics",
        "detected_from": "analytics_evidence",
        "evidence": "https://example.com/privacy (Google Analytics)",
        "vendor_confidence": "high"
      }
    ],
    "cloud_infra": [
      {
        "name": "AWS",
        "detected_from": "subprocessor_urls",
        "evidence": "amazonaws.com",
        "vendor_confidence": "high"
      }
    ]
  }
}

The 24 categories span infrastructure (cloud_infra, database_infra, observability), GTM tools (crm_sales, marketing_ads, analytics_data), product capabilities (payments, auth_identity, ai_ml), and operational systems (hr_payroll, finance_accounting, privacy_compliance).

This structure lets you ask questions like "Does this company have any payment infrastructure?" or "How many GTM tool categories do they use?" without maintaining vendor-specific logic.

Building a Category-Based Scoring Model

Here's a practical implementation for scoring accounts based on category presence. This example scores B2B SaaS companies based on infrastructure maturity and GTM sophistication:

import requests

API_KEY = "vr_live_your_key_here"
BASE_URL = "https://api.vendorstacks.com/v1"

def get_vendor_stack(domain):
    response = requests.get(
        f"{BASE_URL}/check",
        params={"url": domain},
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    return response.json()

def score_account(domain):
    data = get_vendor_stack(domain)
    
    if not data.get("found"):
        return {"domain": domain, "score": 0, "reason": "no_stack_detected"}
    
    vendor_stack = data.get("vendor_stack", {})
    score = 0
    signals = []
    
    # Infrastructure maturity (25 points max)
    infra_categories = ["cloud_infra", "database_infra", "observability"]
    infra_present = sum(1 for cat in infra_categories if vendor_stack.get(cat))
    infra_score = min(infra_present * 10, 25)
    score += infra_score
    if infra_score > 0:
        signals.append(f"infra_maturity:{infra_present}/3")
    
    # GTM sophistication (30 points max)
    gtm_categories = ["crm_sales", "marketing_ads", "analytics_data", "support_cx"]
    gtm_present = sum(1 for cat in gtm_categories if vendor_stack.get(cat))
    gtm_score = min(gtm_present * 10, 30)
    score += gtm_score
    if gtm_score > 0:
        signals.append(f"gtm_sophistication:{gtm_present}/4")
    
    # Product capabilities (25 points max)
    product_categories = ["payments", "auth_identity", "ai_ml", "ecommerce_pos"]
    product_present = sum(1 for cat in product_categories if vendor_stack.get(cat))
    product_score = min(product_present * 8, 25)
    score += product_score
    if product_score > 0:
        signals.append(f"product_capabilities:{product_present}/4")
    
    # Security/compliance posture (20 points max)
    security_categories = ["security_fraud", "privacy_compliance", "auth_identity"]
    security_present = sum(1 for cat in security_categories if vendor_stack.get(cat))
    security_score = min(security_present * 10, 20)
    score += security_score
    if security_score > 0:
        signals.append(f"security_posture:{security_present}/3")
    
    return {
        "domain": domain,
        "score": score,
        "max_score": 100,
        "signals": signals,
        "categories_detected": list(vendor_stack.keys())
    }

# Score a batch of accounts
accounts = ["stripe.com", "example-startup.com", "acme-corp.com"]
for account in accounts:
    result = score_account(account)
    print(f"{result['domain']}: {result['score']}/100 - {', '.join(result['signals'])}")

This model assigns points across four dimensions:

  1. Infrastructure maturity (cloud, database, observability): Signals technical sophistication and likely infrastructure budget
  2. GTM sophistication (CRM, marketing, analytics, support): Indicates sales/marketing team maturity
  3. Product capabilities (payments, auth, AI, ecommerce): Shows product complexity and monetization
  4. Security posture (security tools, privacy compliance, auth): Indicates enterprise readiness

A company scoring 70+ likely has mature operations across multiple dimensions. A company scoring 30-50 might have strong product capabilities but immature GTM. A company scoring <20 is probably pre-product-market-fit.

Real Category Distribution Across 1000 Companies

Here's how categories appear in our index of 1000 companies (real data):

  • analytics_data: 308 companies use analytics tools (Google Analytics most common)
  • cloud_infra: 409 companies use cloud infrastructure (AWS: 284, Google Cloud: 125, others)
  • payments: 189 companies use payment processors (Stripe most common)
  • crm_sales: 97 companies use Salesforce, 132 use HubSpot (category total higher due to other CRMs)
  • ai_ml: 106 companies use OpenAI, plus others using different AI vendors
  • productivity: 93 companies use Slack, plus Microsoft/Google workspace tools
  • marketing_ads: 89 companies use Google Ads, plus Meta (103), other ad platforms

These distributions tell you something important: if you're scoring for "has analytics," you'll match 30% of the index. If you're scoring for "has payments," you'll match 19%. Adjust your category weights based on how selective you want to be.

Combining Category Scores with Reverse Lookup

You can also build category-based prospect lists using reverse lookup. Instead of finding "companies using Stripe," find "companies using any payment processor":

def find_prospects_by_category(category_vendors, max_results=50):
    """Find prospects using any vendor in a category."""
    all_prospects = set()
    
    # Query multiple vendors in the category
    for vendor in category_vendors:
        response = requests.get(
            f"{BASE_URL}/prospect",
            params={"vendor": vendor},
            headers={"Authorization": f"Bearer {API_KEY}"}
        )
        
        data = response.json()
        for result in data.get("results", []):
            all_prospects.add(result["domain"])
            
        if len(all_prospects) >= max_results:
            break
    
    return list(all_prospects)[:max_results]

# Find companies using any major payment processor
payment_vendors = ["Stripe", "Braintree", "Adyen", "PayPal"]
prospects = find_prospects_by_category(payment_vendors, max_results=100)

print(f"Found {len(prospects)} companies using payment infrastructure")

This approach costs 1 credit per result returned (not per API call), so finding 100 companies across 4 vendor queries might cost 100 credits total, depending on overlap.

Category Combinations for Advanced Scoring

The most powerful scoring models evaluate category combinations—detecting patterns that indicate specific company profiles:

E-commerce companies: payments + ecommerce_pos + (marketing_ads OR analytics_data)

Data-intensive B2B SaaS: cloud_infra + database_infra + observability + analytics_data

Enterprise-ready products: security_fraud + privacy_compliance + auth_identity + (cloud_infra OR database_infra)

High-velocity sales teams: crm_sales + marketing_ads + analytics_data + (sms_messaging OR support_cx)

Here's how to implement combination logic:

def evaluate_profile(vendor_stack, profile_requirements):
    """Check if a vendor stack matches a profile.
    
    profile_requirements format:
    {
        "required": ["payments", "cloud_infra"],
        "any_of": ["marketing_ads", "analytics_data"],
        "min_any_of": 1
    }
    """
    # Check required categories
    for category in profile_requirements.get("required", []):
        if not vendor_stack.get(category):
            return False
    
    # Check any_of categories
    any_of = profile_requirements.get("any_of", [])
    if any_of:
        min_required = profile_requirements.get("min_any_of", 1)
        matches = sum(1 for cat in any_of if vendor_stack.get(cat))
        if matches < min_required:
            return False
    
    return True

# Example: Find e-commerce companies
ecommerce_profile = {
    "required": ["payments"],
    "any_of": ["ecommerce_pos", "marketing_ads", "analytics_data"],
    "min_any_of": 2
}

data = get_vendor_stack("example-shop.com")
if data.get("found"):
    is_ecommerce = evaluate_profile(data["vendor_stack"], ecommerce_profile)
    print(f"E-commerce profile match: {is_ecommerce}")

Practical Considerations

1. Not all companies expose complete stacks The API returns only what's publicly detectable. A found: false response means no public evidence was located—not that the company uses nothing. Category-based scoring is more resilient to incomplete data than individual-vendor scoring because you're looking for any match within a category.

2. Category overlap Some vendors appear in multiple categories (e.g., Google Cloud in both cloud_infra and ai_ml). Decide whether to count these once or multiple times based on your scoring goals.

3. Vendor confidence levels Each detection includes vendor_confidence: high|medium|low. You might weight high-confidence detections more heavily or filter out low-confidence results entirely.

4. Index limitations Our index contains 1000 companies and 314 distinct vendors across 24 categories. Reverse lookup works well for common vendors (Google Analytics: 308 companies, AWS: 284, Stripe: 189) but returns fewer results for niche tools.

When to Use Category-Based vs. Individual-Vendor Scoring

Use category-based scoring when:

  • You care about capabilities or maturity, not specific tools
  • Your ICP spans multiple vendor ecosystems ("modern data stack" companies)
  • You're building broad market segmentation ("enterprise-ready" vs. "early-stage")
  • You want scoring logic that's resilient to vendor churn/switching

Use individual-vendor scoring when:

  • You're selling a direct integration or replacement
  • You have strong ecosystem-specific positioning ("the X for Salesforce users")
  • You're running competitive displacement campaigns
  • You need to trigger workflows based on exact vendor presence

For most account scoring use cases, category-based approaches provide better signal with less maintenance than individual-vendor lookups.

Getting Started

Generate an API key instantly at https://api.vendorstacks.com/v1/keys (no signup required, 25 free credits). Each successful lookup costs 1 credit; failed lookups and empty results cost 0.

The scoring model above gives you a starting point. Adjust category weights and combinations based on your ICP, then validate the model against accounts you've already won and lost. The best scoring models are always trained on your own conversion data.

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