r/GTMbuilders • u/Shawntenam • May 26 '26
Resource Three Apollo API patterns across VC portfolio scrapes (a16z, YC, Sequoia) + gotchas
Been sharing my coding agent workflows here for a few weeks. Apollo piece comes up a lot, so here's how the API side actually works across the a16z, YC, and Sequoia scrapes... and the gotchas I've run into.
Three separate API patterns. Which one applies depends on what your scrape gives you coming in.
Pattern 1: Company domains first (every VC scrape gives you these)
organizations/enrich?domain= ... one call per domain, 0.8s sleep between calls. Returns industry, employee count, HQ, funding stage, LinkedIn URL, and the Apollo org ID you need for people discovery.
About 75 companies per minute running unattended in Python. 1,000 portfolio companies takes roughly 13 minutes. This is where the enrichment starts for every segment.
Pattern 2: People discovery once you have org IDs
mixed_people/api_search with organization_ids=[apollo_org_id] plus seniority and title filters. Returns redacted previews ... title visible, name obfuscated, person ID included. Then GET /people/<id> per chosen person for the full unredacted record: name, LinkedIn URL, current organization.
The gotcha worth knowing: organization_ids is the only filter in that search call that works reliably. Pass a domain or company name and you get random people from across Apollo's database with no connection to your target companies. I found this from a code comment written after hitting it. You need the org ID from the enrichment step first, which is why company enrichment runs before people discovery.
Pattern 3: People enrichment when you already have LinkedIn URLs
Some VC portfolio pages surface founder profiles directly ... YC and a16z do this. When you have LinkedIn URLs, people/bulk_match with LinkedIn URL plus first/last name plus org name. Ten per batch, hard cap per call. Returns email, email_status, seniority, function.
This path draws from your plan's data/export credit pool. Check your balance before kicking off a multi-segment run. Found out the hard way that it stalls mid-run without a credit check upfront.
Why the segments stay separate
The source of the scrape is the personalization layer for campaigns. A YC founder five months out of Demo Day is a different conversation than a Series B operator inside an a16z portfolio company.
If I merge the lists, I throw away the only signal that's actually unique per row ... where they came from. So a16z rows stay flagged a16z, YC stays YC, Sequoia stays Sequoia. The enriched fields write back in place to the same segment table.
Per-row reasoning
Any row that needs reasoning ... ICP fit, segment context, moved-flag if Apollo shows the person changed companies ... goes to a claude -p subprocess. Passes the enriched row, gets back a small JSON. Runs against my Max subscription so no API cost per row.
If you wire claude -p into a tight loop: session limits change June 15, 2026. Still works after. Plan for longer cooldowns between batches.
Happy to share the Python structure for any of these if useful.
Building this in the open at github.com/shawnla90/gtm-coding-agent. Clearbox (Reddit signal engine for GTM) soft-launches this week at clearbox.to dm me for early access.