Full source, exactly as shipped. The download above is byte-identical.
pitchbook_competitor_enrich.pyPython
# PitchBook Competitor Enrichment — pulls bio, most-recent financing, and
# investors for a single PitchBook company ID. Designed to run once per
# competitor in a loop driven by the "Map Competitors" automation.
#
# Two independent Zapier "Run Python" steps live in this file:
# 1) competitor_full_summary — bio + financing + financials -> one JSON blob
# 2) competitor_investors — investor names for the same pb_id
#
# Both steps take the same inputs:
# input_data = { "api_key": "...", "pb_id": "10618-03" }
#
# ----------------------------------------------------------------------
# STEP 1 — Full company summary (bio + financing + financials)
# ----------------------------------------------------------------------
import requests
import json
# Expected input_data:
# {
# "api_key": "...",
# "pb_id": "10618-03"
# }
api_key = input_data["api_key"]
pb_id = input_data["pb_id"]
headers_v1 = {"Authorization": f"PB-Token {api_key}"}
def safe_get(url, headers, timeout=30):
try:
r = requests.get(url, headers=headers, timeout=timeout)
if r.status_code == 200 and r.text and r.text.strip():
return r.json()
return {}
except Exception:
return {}
def money(obj):
"""
PitchBook money object:
{"amount": 123, "currency": "USD", ...}
"""
if not isinstance(obj, dict):
return None
amt = obj.get("amount")
cur = obj.get("currency") or obj.get("nativeCurrency")
if amt is None:
return None
return f"{amt} {cur}" if cur else str(amt)
def parse_revenue_fields(financials):
"""
Extract revenue + revenue period only.
"""
if not isinstance(financials, dict):
return (None, None)
rev_obj = financials.get("revenue")
revenue = money(rev_obj) if isinstance(rev_obj, dict) else None
period = financials.get("period")
return (revenue, period)
# ------------------------------------------------------------------
# Pull endpoints
# ------------------------------------------------------------------
financing = safe_get(
f"https://api.pitchbook.com/companies/{pb_id}/most-recent-financing",
headers_v1,
)
financials = safe_get(
f"https://api.pitchbook.com/companies/{pb_id}/most-recent-financials",
headers_v1,
)
bio = safe_get(
f"https://api.pitchbook.com/companies/{pb_id}/bio",
headers_v1,
)
# ------------------------------------------------------------------
# Revenue extraction
# ------------------------------------------------------------------
revenue, revenue_period = parse_revenue_fields(financials)
# ------------------------------------------------------------------
# Build final summary object
# ------------------------------------------------------------------
result = {
"pb_id": pb_id,
"company_name": (
bio.get("companyName", {}).get("formalName")
if isinstance(bio.get("companyName"), dict)
else bio.get("companyName")
),
"description": bio.get("description"),
"hq_location": bio.get("hqLocation"),
"website": bio.get("website"),
"employees": bio.get("employees"),
"year_founded": bio.get("yearFounded"),
"total_raised": money(bio.get("totalMoneyRaised")),
"last_round_date": financing.get("lastFinancingDate"),
"last_round_type": (
financing.get("lastFinancingDealType", {}).get("description")
if isinstance(financing.get("lastFinancingDealType"), dict)
else financing.get("lastFinancingDealType")
),
"last_round_amount": money(financing.get("lastFinancingSize")),
"last_round_post_valuation": money(financing.get("lastKnownValuation")),
# Revenue fields (clean)
"revenue": revenue,
"revenue_period": revenue_period,
# Raw financials retained for coverage variance
"most_recent_financials": financials,
}
# ------------------------------------------------------------------
# Return ONE variable for Zapier
# ------------------------------------------------------------------
# return {
# "company_full_summary": json.dumps(result, ensure_ascii=False)
# }
# ======================================================================
# STEP 2 — Investor names for the same pb_id
# ======================================================================
# Drop the block above and use this as a separate Zapier "Run Python" step.
#
# import requests
# import json
#
# api_key = (input_data.get("api_key") or "").strip()
# pb_id = (input_data.get("pb_id") or "").strip()
#
# url = f"https://api-v2.pitchbook.com/companies/{pb_id}/investors"
#
#
# def try_request(headers):
# resp = requests.get(url, headers=headers, timeout=30)
# text = resp.text or ""
# return resp.status_code, text, resp
#
#
# # PitchBook's auth header varies by tenant / API version. Try the
# # common variants until one returns 200, then remember which worked.
# candidates = [
# ("Authorization: <key>", {"Authorization": api_key}),
# ("Authorization: Bearer <key>", {"Authorization": f"Bearer {api_key}"}),
# ("X-Api-Key: <key>", {"X-Api-Key": api_key}),
# ("PB-Token (v1 style)", {"Authorization": f"PB-Token {api_key}"}),
# ]
#
# investor_names = []
# debug = {
# "url": url,
# "attempts": [],
# "success_auth_variant": None,
# }
#
# data = None
# for label, headers in candidates:
# status, text, resp = try_request(headers)
# debug["attempts"].append({
# "auth_variant": label,
# "status_code": status,
# "response_preview": text[:300],
# })
#
# if status == 200 and text.strip():
# debug["success_auth_variant"] = label
# try:
# data = resp.json()
# except Exception:
# data = json.loads(text)
# break
#
# if isinstance(data, dict):
# inv_list = data.get("investors", []) or []
# for inv in inv_list:
# if isinstance(inv, dict):
# name = inv.get("investorName")
# if name:
# investor_names.append(name)
#
# # de-dupe while preserving order
# seen = set()
# investor_names = [x for x in investor_names if not (x in seen or seen.add(x))]
#
# return {
# "pb_id": pb_id,
# "investor_names": ", ".join(investor_names),
# "investor_names_array": investor_names,
# "debug": debug,
# }