Find decision makers at a HubSpot company using Apollo and n8n

high complexityCost: $0-24/mo

Prerequisites

Prerequisites
  • n8n instance (cloud or self-hosted)
  • HubSpot private app token with crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.companies.read, and crm.schemas.contacts.read scopes
  • Apollo API key with People Search and Enrichment credits
  • n8n credential configured for HubSpot

Why n8n?

n8n gives you a visual workflow builder for the entire search-enrich-create pipeline without writing code. The Split In Batches node handles looping through Apollo results, and you can see each person's data flow through the workflow in the execution log. Self-hosted n8n is free with unlimited executions.

The trade-off is complexity. This workflow has 8+ nodes with HTTP Request nodes for both Apollo and HubSpot APIs. Debugging data mapping issues (like nested JSON paths) requires inspecting node output. For a simpler setup, consider the code approach where the logic is linear and easy to follow.

How it works

  • HubSpot Trigger (or Manual Trigger) starts the workflow when a company is tagged as an ABM target
  • HTTP Request node fetches the company domain from HubSpot
  • HTTP Request node calls Apollo People Search to find VP+/C-suite contacts by domain
  • Split In Batches node loops through each person, enriches via Apollo People Match, checks HubSpot for duplicates, creates contacts, and associates them with the company

Step 1: Add a HubSpot trigger or manual input

Create a new workflow. Choose your trigger based on how you want to kick this off:

Option A — Manual trigger with company ID: Add a Manual Trigger node with an input field for companyId. Useful for on-demand prospecting.

Option B — Watch for new target accounts: Add a HubSpot Trigger node watching for company property changes. Filter for companies where your ABM property (e.g., abm_tier) is set to Tier 1.

Step 2: Fetch company details from HubSpot

Add an HTTP Request node to get the company record:

  • Method: GET
  • URL: https://api.hubapi.com/crm/v3/objects/companies/{{ $json.companyId }}
  • Authentication: Predefined → HubSpot API
  • Query params: properties=domain,name,industry,numberofemployees

You need the domain property to search Apollo by company domain.

Step 3: Search Apollo for decision makers

Add an HTTP Request node to call Apollo's People Search API:

  • Method: POST
  • URL: https://api.apollo.io/api/v1/mixed_people/search
  • Headers: Content-Type: application/json, X-Api-Key: {{ $credentials.apolloApi.apiKey }}
  • Body:
{
  "q_organization_domains_list": ["{{ $json.properties.domain }}"],
  "person_titles": ["VP Sales", "CRO", "VP Marketing", "CMO", "VP RevOps", "Head of Sales"],
  "person_seniorities": ["vp", "c_suite", "director"],
  "page": 1,
  "per_page": 25
}
Customize titles for your ICP

Adjust person_titles and person_seniorities for your buying committee. Selling a dev tool? Search for VP Engineering, CTO, Head of Platform. Selling HR software? VP People, CHRO, Head of Talent.

Step 4: Loop through results and enrich

Add a Split In Batches node to iterate over the people array from Apollo's response.

For each person, add an HTTP Request node to get verified email via Apollo's enrichment endpoint:

  • Method: POST
  • URL: https://api.apollo.io/api/v1/people/match
  • Body:
{
  "first_name": "{{ $json.first_name }}",
  "last_name": "{{ $json.last_name }}",
  "organization_name": "{{ $json.organization.name }}",
  "reveal_personal_emails": false
}
Apollo credit usage

The People Search endpoint costs 1 credit per result returned. The People Match (enrichment) endpoint costs 1 additional credit per call. Searching a company that returns 8 results and enriching all 8 = 16 credits total.

Step 5: Check for existing contacts in HubSpot

Before creating a contact, check if they already exist. Add an HTTP Request node:

  • Method: POST
  • URL: https://api.hubapi.com/crm/v3/objects/contacts/search
  • Body:
{
  "filterGroups": [{
    "filters": [{
      "propertyName": "email",
      "operator": "EQ",
      "value": "{{ $json.email }}"
    }]
  }]
}

Add an IF node after this: if results array length is 0, proceed to create. Otherwise, skip to the association step using the existing contact ID.

Step 6: Create contacts in HubSpot

Add an HTTP Request node (inside the "true" branch of the IF node):

  • Method: POST
  • URL: https://api.hubapi.com/crm/v3/objects/contacts
  • Body:
{
  "properties": {
    "email": "{{ $json.email }}",
    "firstname": "{{ $json.first_name }}",
    "lastname": "{{ $json.last_name }}",
    "jobtitle": "{{ $json.title }}",
    "company": "{{ $json.organization.name }}",
    "phone": "{{ $json.phone_numbers[0].sanitized_number }}",
    "linkedin_url": "{{ $json.linkedin_url }}",
    "hs_lead_status": "NEW"
  }
}

Step 7: Associate contacts with the company

For each contact (new or existing), add an HTTP Request node to create the association:

  • Method: PUT
  • URL: https://api.hubapi.com/crm/v3/objects/contacts/{{ $json.contactId }}/associations/companies/{{ $json.companyId }}/contact_to_company

Step 8: Activate and test

  1. Click Execute Workflow with a real target company ID
  2. Verify contacts appear in HubSpot associated with the company
  3. Toggle the workflow to Active if using a trigger

Troubleshooting

Common questions

How many n8n executions does processing one company use?

Each company triggers 1 execution. Within that execution, the Split In Batches node processes each person as a sub-operation — those don't count as separate executions. A company with 10 decision makers is still 1 execution.

Can I process multiple companies in one run?

Yes. Use the Watch Companies trigger to pick up all companies that changed to Tier 1 since the last poll. Each company is a separate execution. Or use a Manual Trigger with a Code node that fetches a batch of companies via the HubSpot CRM Search API.

What if Apollo returns 25+ results for a large company?

Apollo's People Search paginates at the per_page limit (max 25). For large enterprises, you may want to add a second HTTP Request node that checks if there's a next page and loops. Alternatively, tighten your person_titles filter to reduce results.

Cost

  • n8n Cloud Starter: $24/mo for 2,500 executions. Each company processed = 1 execution with multiple sub-operations.
  • Self-hosted: Free. Unlimited executions.
  • Apollo credits: 1 credit per search result + 1 credit per enrichment. Budget ~2 credits per decision maker found.

Looking to scale your AI operations?

We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.