{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "873f84ec-88d8-4f78-a426-25ee26398026",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1712,
        832
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "ee2db9cb-7b85-4306-b969-87a31e567aa1",
      "name": "Extract People",
      "type": "n8n-nodes-base.code",
      "position": [
        -704,
        384
      ],
      "parameters": {
        "jsCode": "// Extract people array from Apollo API response\nconst contacts = $input.first().json.people;\nreturn contacts.map(contact => ({ json: contact }));"
      },
      "typeVersion": 2
    },
    {
      "id": "20b4c29d-032f-4381-96da-8abf255d3536",
      "name": "Write to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -480,
        384
      ],
      "parameters": {
        "columns": {
          "value": {
            "Title": "={{ $json.title }}",
            "Website": "={{ $json.organization.website_url }}",
            "Apollo id": "={{ $json.id }}",
            "Full Name": "={{ $json.name }}",
            "Last Name": "={{ $json.last_name }}",
            "First Name": "={{ $json.first_name }}",
            "Org Twitter": "={{ $json.organization.twitter_url }}",
            "Contact City": "={{ $json.city }}",
            "Founded year": "={{ $json.organization.founded_year }}",
            "Org Facebook": "={{ $json.organization.facebook_url }}",
            "Org Linkedin": "={{ $json.organization.linkedin_url }}",
            "Contact State": "={{ $json.state }}",
            "Phone Numbers": "={{ $json.organization.primary_phone?.sanitized_number }}",
            "Organization_id": "={{ $json.organization.id }}",
            "Contact  Country": "={{ $json.country }}",
            "contact Linkedin": "={{ $json.linkedin_url }}",
            "Organization_Name": "={{ $json.organization.name }}"
          },
          "schema": [
            {
              "id": "Apollo id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Apollo id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "First Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "First Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Full Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Full Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "contact Linkedin",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "contact Linkedin",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact City",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact City",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact State",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact State",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact  Country",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact  Country",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone Numbers",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone Numbers",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Founded year",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Founded year",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Organization_Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Organization_Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Linkedin",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Linkedin",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Facebook",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Facebook",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Org Twitter",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Org Twitter",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1s6RZnRnuOL9LSJ1SogYV7vfon-ONxCNWJGMtTPl9rjU/edit?usp=drivesdk",
          "cachedResultName": "Apollo Leads"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c23c0d2c-64cb-42e9-a253-164fc6bee089",
      "name": "Extract Pagination Info",
      "type": "n8n-nodes-base.set",
      "position": [
        -816,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fe276499-6bdb-47eb-bf22-af499038a3a6",
              "name": "current_page",
              "type": "number",
              "value": "={{ $json.pagination.page }}"
            },
            {
              "id": "81b6add1-c2d5-4bc1-a076-ae69371014aa",
              "name": "total_pages",
              "type": "number",
              "value": "={{ $json.pagination.total_pages }}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "bab50260-20ee-4335-b25e-881a4603dc87",
      "name": "Increment Page",
      "type": "n8n-nodes-base.set",
      "position": [
        -368,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "35fb246d-34d8-43aa-9ae1-6ddf739ecb92",
              "name": "current_page",
              "type": "number",
              "value": "={{ $json.current_page + 1 }}"
            },
            {
              "id": "ecb5a01e-7a53-43e9-a401-90b1abd94ce7",
              "name": "base_filters",
              "type": "object",
              "value": "={{ $('Build API Filters').first().json.base_filters }}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.4
    },
    {
      "id": "b4ae43e3-7b32-4287-9357-6dcad900f825",
      "name": "Rate Limit Delay",
      "type": "n8n-nodes-base.wait",
      "position": [
        -192,
        832
      ],
      "parameters": {
        "amount": 2
      },
      "executeOnce": true,
      "typeVersion": 1.1
    },
    {
      "id": "2e768935-3b15-4ac5-aeb4-9c77d4912905",
      "name": "Has More Pages?",
      "type": "n8n-nodes-base.if",
      "position": [
        -592,
        832
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "16a4c7df-c769-495b-8d69-c89a0f840b54",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.current_page < $json.total_pages }}",
              "rightValue": ""
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 2.3
    },
    {
      "id": "7b13c400-8d3c-4697-94e0-b722b1793daf",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2304,
        496
      ],
      "parameters": {
        "width": 480,
        "height": 528,
        "content": "## Apollo.io Lead Scraper\n\n### How it works\n\n1. Converts any standard Apollo.io search URL into an API-ready JSON payload.\n2. Automatically maps standard URL filters (titles, locations, employees, etc.) to the API structure.\n3. Fetches leads from the `/v1/mixed_people/search` endpoint.\n4. Extracts the contact records and appends them directly to Google Sheets.\n5. Handles pagination and rate limits automatically (2s delay) to scrape all pages safely.\n\n### Setup steps\n\n- [ ] Generate an API Key in your Apollo.io developer settings.\n- [ ] Add the key to the `APOLLO_API_KEY` environment variable or credentials.\n- [ ] Authenticate the Google Sheets node and select your specific spreadsheet.\n- [ ] Go to Apollo.io, build your search, copy the URL, and paste it into the 'Input' node."
      },
      "typeVersion": 1
    },
    {
      "id": "3b10219c-0567-4bd6-95cb-53b65e28e3a1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1776,
        688
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 304,
        "content": "## 1. Setup & Parse Input\n\nPaste your Apollo search URL into the **Input (Set) node**. This should be the exact leads search URL you want to extract data from.\n\n\u26a0\ufe0f Set the **start_page** value to control where the workflow begins. For example, if you set `start_page = 5`, the workflow will skip earlier pages and start from page 5."
      },
      "typeVersion": 1
    },
    {
      "id": "f7a723bc-7abe-413d-829c-06c8b125c96f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1120,
        640
      ],
      "parameters": {
        "color": 7,
        "height": 352,
        "content": "## 2. API Request\n\n\ud83d\ude80 Sends a paginated **POST request** to the Apollo Search API.\n\n\ud83d\udd11 **Important:** Replace `APOLLO_API_KEY` in the headers with your actual Apollo API key."
      },
      "typeVersion": 1
    },
    {
      "id": "87df94b9-9be1-4660-b607-196a6e95019a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 304,
        "content": "## 3. Extract & Export\n\nIsolates the 'people' array from the API response and maps the data (Name, LinkedIn, Company, etc.) to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "6276f1cf-f9a8-4c25-9c89-399f08891bd6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 432,
        "content": "## 4. Pagination Control\n\n\u26a0\ufe0f In the **Extract Pagination Info** node, you control how many pages are processed.\n\nBy default, the workflow uses the detected `total_pages` from Apollo.\n\n\u2757 If you do **not** want all pages:\n- Remove the expression for `total_pages`  \n- Set a fixed page limit manually  \n\n\ud83c\udfaf This lets you extract only up to a specific page (e.g., first 10 pages).\n\n\ud83d\udd01 The workflow will loop only until your defined limit, not the full dataset."
      },
      "typeVersion": 1
    },
    {
      "id": "90c2c5ab-aa88-4cc6-bb2c-9369605619d7",
      "name": "Apollo Search Input",
      "type": "n8n-nodes-base.set",
      "position": [
        -1488,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "285f3c26-d8e5-42a7-8104-506a4863fb1d",
              "name": "url",
              "type": "string",
              "value": "https://app.apollo.io/#/people?sortByField=recommendations_score&sortAscending=false&organizationIndustryTagIds[]=5567cd467369644d39040000&includedOrganizationKeywordFields[]=tags&includedOrganizationKeywordFields[]=name&organizationNumEmployeesRanges[]=%2C300&personLocations[]=United%20States&excludedOrganizationKeywordFields[]=tags&excludedOrganizationKeywordFields[]=name&excludedOrganizationKeywordFields[]=social_media_description&contactEmailStatusV2[]=verified&qOrganizationKeywordTags[]=Affiliate%20marketing&qOrganizationKeywordTags[]=Affiliate%20agency&qOrganizationKeywordTags[]=Affiliate%20management&qOrganizationKeywordTags[]=Performance%20marketing&qOrganizationKeywordTags[]=Affiliate%20program%20management&qOrganizationKeywordTags[]=Partner%20marketing&qOrganizationKeywordTags[]=CPA%20marketing&qOrganizationKeywordTags[]=Performance%20affiliate&qOrganizationKeywordTags[]=Digital%20affiliate&qOrganizationKeywordTags[]=Affiliate%20network&qOrganizationKeywordTags[]=Partner%20management&qOrganizationKeywordTags[]=Revenue%20share%20marketing&qOrganizationKeywordTags[]=Commission-based%20marketing&qOrganizationKeywordTags[]=Affiliate%20optimization&personTitles[]=Founder&personTitles[]=Co-Founder&personTitles[]=CEO&personTitles[]=Chief%20Executive%20Officer&personTitles[]=President&personTitles[]=Owner&personTitles[]=Managing%20Director&personTitles[]=Managing%20Partner&personTitles[]=Chief%20Operating%20Officer&personTitles[]=COO&personTitles[]=VP%20of%20Sales&personTitles[]=Vice%20President%20of%20Sales&personTitles[]=Director%20of%20Sales&personTitles[]=Head%20of%20Sales&personTitles[]=Partner&personTitles[]=Chief%20Revenue%20Officer&personTitles[]=CRO&personTitles[]=VP%20of%20Business%20Development&personTitles[]=Head%20of%20Business%20Development&personTitles[]=Commercial%20Director&personTitles[]=Head%20of%20Growth&personTitles[]=Director%20of%20Growth&personTitles[]=VP%20of%20Growth&personTitles[]=Head%20of%20Partnerships&personTitles[]=Director%20of%20Partnerships&personTitles[]=VP%20of%20Partnerships&personTitles[]=Head%20of%20Affiliate%20Marketing&personTitles[]=VP%20of%20Affiliate%20Marketing&personTitles[]=Director%20of%20Affiliate%20Marketing&personTitles[]=Head%20of%20Partner%20Management&personTitles[]=VP%20of%20Partner%20Management&personTitles[]=Affiliate%20Manager&personTitles[]=Senior%20Affiliate%20Manager&personTitles[]=Affiliate%20Marketing%20Manager&personTitles[]=Partner%20Manager&personTitles[]=Head%20of%20Affiliate%20Operations&personTitles[]=Director%20of%20Affiliate%20Operations&personTitles[]=Affiliate%20Program%20Manager&personTitles[]=Performance%20Marketing%20Manager&qNotOrganizationKeywordTags[]=SEO%20agency&qNotOrganizationKeywordTags[]=Content%20marketing%20agency&qNotOrganizationKeywordTags[]=Web%20design&qNotOrganizationKeywordTags[]=PR%20agency&qNotOrganizationKeywordTags[]=Branding%20agency&qNotOrganizationKeywordTags[]=Creative%20studio&qNotOrganizationKeywordTags[]=Social%20media%20management&qNotOrganizationKeywordTags[]=Recruiting&qNotOrganizationKeywordTags[]=Staffing&qNotOrganizationKeywordTags[]=Software%20development&includeSimilarTitles=false&page=1"
            },
            {
              "id": "3bc0f265-4fc9-479a-a245-73c4ff96127e",
              "name": "start_page",
              "type": "string",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2f539704-2ef6-45dd-b2f1-c799870ec870",
      "name": "Build API Filters",
      "type": "n8n-nodes-base.code",
      "position": [
        -1264,
        832
      ],
      "parameters": {
        "jsCode": "// ============================================================\n// Apollo.io URL \u2192 API JSON Body Converter\n// Production-level | Drops unsupported params automatically\n// ============================================================\n\nconst input = $input.first().json;\nconst apolloUrl = input.url;\nconst startPage = parseInt(input.start_page, 10) || 1;\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 1: Extract query string from Apollo URL\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet queryString = '';\n\nif (apolloUrl.includes('#')) {\n  const hashPart = apolloUrl.split('#')[1] || '';\n  queryString = hashPart.includes('?') ? hashPart.split('?')[1] : '';\n} else if (apolloUrl.includes('?')) {\n  queryString = apolloUrl.split('?')[1];\n}\n\nif (!queryString) {\n  throw new Error('No query parameters found in URL: ' + apolloUrl);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 2: Parse all URL params into a map\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst params = {};\n\nfor (const part of queryString.split('&')) {\n  if (!part) continue;\n  const eqIndex = part.indexOf('=');\n  if (eqIndex === -1) continue;\n  const rawKey = part.substring(0, eqIndex);\n  const rawVal = decodeURIComponent(part.substring(eqIndex + 1).replace(/\\+/g, ' '));\n  const key = rawKey.replace(/\\[\\]$/, '').replace(/\\[/g, '[');\n  if (!params[key]) params[key] = [];\n  params[key].push(rawVal);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 3: SUPPORTED API parameters map\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst SUPPORTED = {\n  'personTitles':                          { key: 'person_titles',                           type: 'array' },\n  'personNotTitles':                       { key: 'person_not_titles',                       type: 'array' },\n  'personLocations':                       { key: 'person_locations',                        type: 'array' },\n  'personSeniorities':                     { key: 'person_seniorities',                      type: 'array' },\n  'organizationLocations':                 { key: 'organization_locations',                  type: 'array' },\n  'organizationIds':                       { key: 'organization_ids',                        type: 'array' },\n  'notOrganizationIds':                    { key: 'not_organization_ids',                    type: 'array' },\n  'organizationNumEmployeesRanges':        { key: 'organization_num_employees_ranges',       type: 'array' },\n  'organizationIndustryTagIds':            { key: 'organization_industry_tag_ids',           type: 'array' },\n  'organizationNotIndustryTagIds':         { key: 'organization_not_industry_tag_ids',       type: 'array' },\n  'contactEmailStatusV2':                  { key: 'contact_email_status',                    type: 'array' },\n  'qOrganizationKeywordTags':              { key: 'q_organization_keyword_tags',             type: 'array' },\n  'qNotOrganizationKeywordTags':           { key: 'q_not_organization_keyword_tags',         type: 'array' },\n  'includedOrganizationKeywordFields':     { key: 'included_organization_keyword_fields',    type: 'array' },\n  'excludedOrganizationKeywordFields':     { key: 'excluded_organization_keyword_fields',    type: 'array' },\n  'qOrganizationDomainsList':              { key: 'q_organization_domains_list',             type: 'array' },\n  'currentlyUsingAllOfTechnologyUids':     { key: 'currently_using_all_of_technology_uids',  type: 'array' },\n  'currentlyUsingAnyOfTechnologyUids':     { key: 'currently_using_any_of_technology_uids',  type: 'array' },\n  'currentlyNotUsingAnyOfTechnologyUids':  { key: 'currently_not_using_any_of_technology_uids', type: 'array' },\n  'qOrganizationJobTitles':                { key: 'q_organization_job_titles',               type: 'array' },\n  'organizationJobLocations':              { key: 'organization_job_locations',              type: 'array' },\n  'existFields':                           { key: 'exist_fields',                            type: 'array' },\n  'marketSegments':                        { key: 'market_segments',                         type: 'array' },\n  'qPersonPersonaIds':                     { key: 'q_person_persona_ids',                    type: 'array' },\n  'qKeywords':                             { key: 'q_keywords',                              type: 'string' },\n  'qPersonTitle':                          { key: 'q_person_title',                          type: 'string' },\n  'qOrganizationSearchListId':             { key: 'q_organization_search_list_id',           type: 'string' },\n  'sortByField':                           { key: 'sort_by_field',                           type: 'string' },\n  'sortAscending':                         { key: 'sort_ascending',                          type: 'boolean' },\n  'includeSimilarTitles':                  { key: 'include_similar_titles',                  type: 'boolean' },\n  'revenueRange[min]':                     { key: 'revenue_range',                           type: 'range_min' },\n  'revenueRange[max]':                     { key: 'revenue_range',                           type: 'range_max' },\n  'personTotalYoeRange[min]':              { key: 'person_total_yoe_range',                  type: 'range_min' },\n  'personTotalYoeRange[max]':              { key: 'person_total_yoe_range',                  type: 'range_max' },\n  'organizationNumJobsRange[min]':         { key: 'organization_num_jobs_range',             type: 'range_min' },\n  'organizationNumJobsRange[max]':         { key: 'organization_num_jobs_range',             type: 'range_max' },\n  'organizationJobPostedAtRange[min]':     { key: 'organization_job_posted_at_range',        type: 'range_min' },\n  'organizationJobPostedAtRange[max]':     { key: 'organization_job_posted_at_range',        type: 'range_max' },\n};\n\nconst UNSUPPORTED_DROP = new Set([\n  'contactEmailStatus', 'organizationKeywordTags', 'personFunctions',\n  'prospectedByCurrentTeam', 'isLikelyToEngage', 'emailStatus',\n  'listId', 'tableView', 'viewMode', 'activeTab', 'page', 'perPage'\n]);\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 4: Build the base filters (NO page)\n// page is excluded here \u2014 loop controls it\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst baseFilters = {};\nconst dropped = [];\nconst rangeBuffer = {};\n\nfor (const [urlKey, values] of Object.entries(params)) {\n  const match = SUPPORTED[urlKey];\n\n  if (!match) {\n    dropped.push({\n      param: urlKey,\n      reason: UNSUPPORTED_DROP.has(urlKey)\n        ? 'UI-only filter, not supported by API'\n        : 'Unknown parameter \u2014 not in API docs'\n    });\n    continue;\n  }\n\n  const { key, type } = match;\n\n  if (type === 'array') {\n    baseFilters[key] = values.map(v => v.trim()).filter(v => v !== '');\n  } else if (type === 'string') {\n    baseFilters[key] = values[0];\n  } else if (type === 'boolean') {\n    const val = values[0].toLowerCase();\n    baseFilters[key] = val === 'true' || val === '1';\n  } else if (type === 'range_min') {\n    if (!rangeBuffer[key]) rangeBuffer[key] = {};\n    rangeBuffer[key].min = isNaN(Number(values[0])) ? values[0] : Number(values[0]);\n  } else if (type === 'range_max') {\n    if (!rangeBuffer[key]) rangeBuffer[key] = {};\n    rangeBuffer[key].max = isNaN(Number(values[0])) ? values[0] : Number(values[0]);\n  }\n}\n\nfor (const [rangeKey, rangeVal] of Object.entries(rangeBuffer)) {\n  baseFilters[rangeKey] = rangeVal;\n}\n\n// Always set per_page\nbaseFilters.per_page = 100;\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// STEP 5: Output\n// current_page is what the loop will use\n// base_filters has everything EXCEPT page\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nreturn [{\n  json: {\n    base_filters: baseFilters,\n    current_page: startPage,\n    total_pages: null,\n    source_url: apolloUrl,\n    dropped_params: dropped,\n    total_dropped: dropped.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "73ecfeab-fac4-4f80-9e0f-7373a4ca419e",
      "name": "Fetch Leads (Apollo)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1040,
        832
      ],
      "parameters": {
        "url": "https://api.apollo.io/api/v1/mixed_people/search",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify(Object.assign({}, $json.base_filters, { page: $json.current_page })) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Cache-Control",
              "value": "no-cache"
            },
            {
              "name": "accept",
              "value": "application/json"
            },
            {
              "name": "X-Api-Key",
              "value": "APOLLO_API_KEY"
            }
          ]
        }
      },
      "typeVersion": 4.2
    }
  ],
  "connections": {
    "Extract People": {
      "main": [
        [
          {
            "node": "Write to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Increment Page": {
      "main": [
        [
          {
            "node": "Rate Limit Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has More Pages?": {
      "main": [
        [
          {
            "node": "Increment Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Delay": {
      "main": [
        [
          {
            "node": "Fetch Leads (Apollo)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build API Filters": {
      "main": [
        [
          {
            "node": "Fetch Leads (Apollo)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apollo Search Input": {
      "main": [
        [
          {
            "node": "Build API Filters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Leads (Apollo)": {
      "main": [
        [
          {
            "node": "Extract People",
            "type": "main",
            "index": 0
          },
          {
            "node": "Extract Pagination Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Pagination Info": {
      "main": [
        [
          {
            "node": "Has More Pages?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Apollo Search Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}