VendorStacks
← All posts
GTM8 min read

Vendor Stack API: Building Tech Stack Enrichment for Account-Based Marketing

A technical guide to enriching ABM target accounts with tech stack data, building vendor-based account lists, and automating stack detection in ABM workflows.

Stax
VendorStacks research desk

Why Tech Stack Data Matters for ABM

Account-based marketing works when you know what your target accounts actually use. A company running Salesforce needs different messaging than one using HubSpot. A team on AWS has different pain points than one on Google Cloud. But most ABM platforms don't tell you what's in a prospect's stack—they give you company size, industry, and employee count, not the vendors they've chosen.

Tech stack data closes that gap. When you know a prospect uses Stripe, you can speak to payment infrastructure. When you see OpenAI in their stack, you know they're building AI features. When you detect HubSpot but no Salesforce, you understand their CRM complexity.

This guide walks through building tech stack enrichment into ABM workflows using the VendorStacks API—from enriching static account lists to automating vendor detection for inbound leads.

The Core Pattern: Enriching Account Lists with Vendor Data

Most ABM campaigns start with a target account list: 50-500 companies you want to reach. The first implementation pattern is straightforward: enrich each account with its tech stack before you launch.

import requests
import csv
import time

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()

# Read target account list
with open('abm_accounts.csv', 'r') as f:
    accounts = list(csv.DictReader(f))

# Enrich with tech stack data
enriched = []
for account in accounts:
    stack_data = get_vendor_stack(account['domain'])
    
    if stack_data.get('found'):
        account['vendor_stack'] = stack_data['vendor_stack']
        account['vendors_detected'] = sum(len(v) for v in stack_data['vendor_stack'].values())
        account['uses_salesforce'] = 'Salesforce' in stack_data['vendor_stack'].get('crm_sales', [])
        account['uses_stripe'] = 'Stripe' in stack_data['vendor_stack'].get('payments', [])
        account['uses_openai'] = 'OpenAI' in stack_data['vendor_stack'].get('ai_ml', [])
    
    enriched.append(account)
    time.sleep(0.1)  # Rate limiting courtesy

# Write enriched list
with open('abm_accounts_enriched.csv', 'w') as f:
    writer = csv.DictWriter(f, fieldnames=enriched[0].keys())
    writer.writeheader()
    writer.writerows(enriched)

This pattern costs 1 credit per successful lookup. A 200-account ABM list costs ~200 credits ($1.80 at the $10/1,100 pack). Failed lookups or accounts with no public evidence cost nothing.

The enriched data becomes segmentation criteria. You can split campaigns by CRM vendor, target companies using specific payment processors, or prioritize accounts with AI infrastructure already in place.

Building Vendor-Based Account Segments

Once you have enriched data, segmentation becomes precise. Instead of "companies with 50-200 employees in SaaS," you can build segments like:

  • Companies using HubSpot but not Salesforce (simpler CRM needs)
  • Companies using Stripe and OpenAI (building AI-powered commerce)
  • Companies using AWS and no observability vendor (infrastructure monitoring gap)
  • Companies using Slack and Google Workspace (specific collaboration stack)

In our index of 1,000 companies, HubSpot appears in 130 stacks, Salesforce in 98, Stripe in 189, and OpenAI in 109. These aren't small segments—they're substantial pools of companies with known characteristics.

def segment_accounts(enriched_accounts):
    segments = {
        'hubspot_no_salesforce': [],
        'stripe_and_openai': [],
        'aws_no_observability': [],
        'slack_google': []
    }
    
    for account in enriched_accounts:
        if not account.get('vendor_stack'):
            continue
            
        stack = account['vendor_stack']
        crm = stack.get('crm_sales', [])
        payments = stack.get('payments', [])
        ai = stack.get('ai_ml', [])
        cloud = stack.get('cloud_infra', [])
        observability = stack.get('observability', [])
        productivity = stack.get('productivity', [])
        
        # Segment 1: HubSpot without Salesforce
        if 'HubSpot' in crm and 'Salesforce' not in crm:
            segments['hubspot_no_salesforce'].append(account)
        
        # Segment 2: Stripe + OpenAI (AI commerce)
        if 'Stripe' in payments and 'OpenAI' in ai:
            segments['stripe_and_openai'].append(account)
        
        # Segment 3: AWS without observability (monitoring gap)
        if 'AWS' in cloud and not observability:
            segments['aws_no_observability'].append(account)
        
        # Segment 4: Slack + Google Workspace
        if 'Slack' in productivity and 'Google Workspace' in productivity:
            segments['slack_google'].append(account)
    
    return segments

segments = segment_accounts(enriched)
for name, accounts in segments.items():
    print(f"{name}: {len(accounts)} accounts")

Each segment gets tailored messaging. The HubSpot-no-Salesforce segment hears about simplicity and speed. The Stripe-OpenAI segment gets AI commerce use cases. The AWS-no-observability segment receives infrastructure monitoring positioning.

Reverse Lookup: Building Account Lists from Vendor Usage

The opposite pattern also works: start with a vendor, find companies using it, filter to ICP matches. If you sell observability tools, find companies using AWS. If you sell CRM migration services, find companies using legacy CRMs.

def build_account_list_from_vendor(vendor_name, min_employees=None, industries=None):
    accounts = []
    page = 1
    
    while True:
        response = requests.get(
            f"{BASE_URL}/prospect",
            params={"vendor": vendor_name, "page": page},
            headers={"Authorization": f"Bearer {API_KEY}"}
        )
        data = response.json()
        
        if not data.get('results'):
            break
        
        for result in data['results']:
            # You would enrich with firmographic data from your CRM/database
            account = {
                'domain': result['domain'],
                'vendor': vendor_name,
                'evidence': result.get('evidence', '')
            }
            accounts.append(account)
        
        if not data.get('has_more'):
            break
        page += 1
    
    return accounts

# Build ABM list: companies using OpenAI
openai_accounts = build_account_list_from_vendor('OpenAI')
print(f"Found {len(openai_accounts)} companies using OpenAI")

# Build ABM list: companies using HubSpot
hubspot_accounts = build_account_list_from_vendor('HubSpot')
print(f"Found {len(hubspot_accounts)} companies using HubSpot")

This costs 1 credit per result returned (10 results per page). An empty result set costs nothing. If you pull 50 companies using OpenAI, that's 50 credits ($0.45). You're building a qualified account list for under a dollar.

The 109 companies using OpenAI in our index aren't a sample—they're every company we've scanned where OpenAI appears in public evidence. Same with the 130 HubSpot companies, 189 Stripe companies, 288 AWS companies. These are real detection counts, not estimates.

Automating Stack Detection for Inbound Leads

The third pattern: enrich inbound leads automatically. When a prospect fills out a form, hits your pricing page, or books a demo, check their tech stack before the sales call.

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/webhook/new_lead', methods=['POST'])
def handle_new_lead():
    lead = request.json
    domain = lead.get('company_domain')
    
    if not domain:
        return jsonify({"error": "no domain"}), 400
    
    # Get tech stack
    stack_response = requests.get(
        f"{BASE_URL}/check",
        params={"url": domain},
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    stack_data = stack_response.json()
    
    # Build enrichment payload
    enrichment = {
        'lead_id': lead['id'],
        'domain': domain,
        'stack_found': stack_data.get('found', False)
    }
    
    if stack_data.get('found'):
        stack = stack_data['vendor_stack']
        enrichment.update({
            'uses_salesforce': 'Salesforce' in stack.get('crm_sales', []),
            'uses_hubspot': 'HubSpot' in stack.get('crm_sales', []),
            'uses_stripe': 'Stripe' in stack.get('payments', []),
            'uses_aws': 'AWS' in stack.get('cloud_infra', []),
            'uses_openai': 'OpenAI' in stack.get('ai_ml', []),
            'vendor_categories': list(stack.keys()),
            'total_vendors': sum(len(v) for v in stack.values())
        })
    
    # Push to CRM (example: HubSpot)
    # requests.patch(
    #     f"https://api.hubapi.com/crm/v3/objects/contacts/{lead['id']}",
    #     json={"properties": enrichment}
    # )
    
    return jsonify(enrichment)

if __name__ == '__main__':
    app.run(port=5000)

This runs in real-time. If the domain is already indexed (most scans complete in under 1 second), you get results before the lead confirmation page loads. If it's not indexed, the API triggers a scan that completes in 15-90 seconds—still before the first sales touchpoint.

The enriched data goes into your CRM as custom fields. Your sales team sees "Uses Salesforce: Yes" and "Uses OpenAI: Yes" before they pick up the phone. Your ABM platform can trigger different nurture sequences based on detected vendors.

Vendor Categories as ABM Signals

The API returns vendors grouped into 24 categories: ai_ml, email, crm_sales, support_cx, cloud_infra, productivity, auth_identity, finance_accounting, payments, marketing_ads, ecommerce_pos, sms_messaging, analytics_data, database_infra, security_fraud, search_discovery, observability, integration_etl, hr_payroll, privacy_compliance, media_cdn, esignature_contracts, data_enrichment, realtime_infra.

These categories become ABM dimensions. You can target companies with:

  • No observability vendor (infrastructure monitoring gap)
  • Multiple analytics vendors (data stack complexity)
  • Payment processor but no fraud vendor (fraud detection opportunity)
  • CRM but no marketing automation (marketing ops gap)
  • Cloud infrastructure but no CDN (performance opportunity)
def find_stack_gaps(vendor_stack):
    gaps = []
    
    # Has payments but no fraud detection
    if vendor_stack.get('payments') and not vendor_stack.get('security_fraud'):
        gaps.append('fraud_detection')
    
    # Has cloud infra but no observability
    if vendor_stack.get('cloud_infra') and not vendor_stack.get('observability'):
        gaps.append('observability')
    
    # Has CRM but no marketing automation
    if vendor_stack.get('crm_sales') and not vendor_stack.get('marketing_ads'):
        gaps.append('marketing_automation')
    
    # Has database but no integration/ETL
    if vendor_stack.get('database_infra') and not vendor_stack.get('integration_etl'):
        gaps.append('data_integration')
    
    return gaps

# Score accounts by stack completeness
for account in enriched:
    if account.get('vendor_stack'):
        gaps = find_stack_gaps(account['vendor_stack'])
        account['stack_gaps'] = gaps
        account['gap_count'] = len(gaps)

Gap analysis isn't speculation—it's observable fact. If a company uses AWS (public evidence: job posts, engineering blog, infrastructure references) but mentions no observability vendor (no Datadog, New Relic, or Grafana references), that's a detectable gap. You're not guessing at needs; you're seeing what's missing from their public footprint.

Cost Structure for ABM Enrichment

Pricing follows usage: 1 credit per successful lookup, 1 credit per reverse-lookup result, 0 credits for lookups that find nothing. For ABM:

  • Enriching 200 target accounts: ~200 credits ($1.80)
  • Reverse lookup pulling 100 companies using Stripe: 100 credits ($0.90)
  • Enriching 1,000 inbound leads per month: ~1,000 credits ($9.10)
  • Monthly account list refresh (500 accounts): 500 credits ($4.55)

The $10 pack (1,100 credits) covers most monthly ABM enrichment. The $50 pack (6,000 credits) handles higher-volume campaigns. You're billed only for data returned—empty results cost nothing.

Implementation Checklist

To add tech stack enrichment to your ABM workflow:

  1. Get an API key at https://api.vendorstacks.com/v1/keys (instant, 25 free credits)
  2. Export your target account list with company domains
  3. Run enrichment script: GET /v1/check?url=DOMAIN for each account
  4. Parse vendor_stack response into segmentation fields
  5. Build segments by vendor presence/absence and category gaps
  6. Push enriched data to your ABM platform or CRM
  7. Set up inbound lead enrichment webhook for real-time detection
  8. Build alerts for when target accounts change their stack

The core loop is: domain → vendor detection → segmentation → targeted messaging. Tech stack data makes ABM messaging specific instead of generic, turning "we help companies like yours" into "we integrate with your Salesforce instance and complement your existing Stripe setup."

What This Doesn't Do

Tech stack enrichment finds vendors with public evidence—job posts, engineering blogs, service pages, integration docs, privacy policies. It does not:

  • Detect vendors with no public footprint
  • Guarantee completeness (a company may use tools they don't mention publicly)
  • Provide usage metrics, seat counts, or spend data
  • Access private networks, traffic, or internal systems

The API returns what's observable from public sources. A "found": false response means no public evidence exists, not that the company uses nothing. Use this data as signal enrichment, not ground truth.

Why This Matters

ABM without tech stack data is targeting by firmographics: company size, industry, revenue. ABM with tech stack data is targeting by reality: what they've actually chosen to run their business. The difference is generic messaging versus specific positioning.

When you know a prospect uses HubSpot, you speak to marketing automation users. When you see AWS and no observability, you address infrastructure monitoring gaps. When you detect Stripe and OpenAI together, you reference AI-powered payments. You're not guessing—you're responding to what's already there.

The VendorStacks API provides the detection layer. Your ABM platform provides the orchestration. Together, they turn company domains into actionable vendor intelligence that makes every campaign more targeted.

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