Enrich Webinar Leads and Create Outreach with Surfe API: Python Code Tutorial

Enrich Webinar Leads and Create Outreach with Surfe API: Python Code Tutorial

Your team spent hours running the webinar—don’t waste another second chasing incomplete leads.

This Python tutorial shows you how to turn Zoom registrants into enriched, sequenced prospects—faster than ever.

Using Surfe’s Contact Enrichment API, you’ll fetch Zoom webinar registrants, enrich them with verified contact details, and create new Outreach prospects—all in one streamlined script. It’s the perfect workflow for sales teams looking to act fast on inbound webinar leads without losing hours to repetitive tasks.

By the end of this tutorial, you’ll have a fully functioning Python script that:

  • Fetches webinar registrants directly from Zoom

  • Extracts key information for lead qualification

  • Enriches registrant data with verified emails and phone numbers using Surfe’s API

  • Creates prospects in Outreach directly

  • Adds prospects to your sales sequence for immediate follow-up

Let’s get into it.

Want the full script?Jump to the bottom or view it on GitHub!

Prerequisites

  1. Python 3.x Installation

Most modern operating systems come with Python 3 pre-installed. To check if Python is installed on your system:

  • Windows: Open Command Prompt (Win + R, type cmd, press Enter) and run:
py --version
  • macOS/Linux: Open Terminal and run:
python3 --version

If Python is not installed, download it from the official Python website and follow the installation instructions for your OS.

  1. Basic Python Programming Knowledge
  2. Zoom Account with API Access

To fetch webinar registrants, you’ll need a Zoom account with API access:

  • Create a Zoom app in your Zoom Marketplace account
  • Generate either a JWT token or OAuth credentials
  • Note your webinar ID from a webinar with registrants
  1. Surfe Account and API Key

To enrich your leads, you’ll need a Surfe account and API key. You can find the API documentation and instructions for generating your API key in the Surfe Developer Docs.

  1. Outreach Account with API Access

To create prospects and add them to sequences:

  • Set up OAuth access in your Outreach account
  • Obtain your access token
  • Have a sequence ID and mailbox ID ready for prospect assignment

Step 1: Setting Up Your Environment

Let’s begin by setting up your development environment and installing the necessary dependencies.

Creating a Virtual Environment (Optional but Recommended)

Creating a virtual environment is recommended to keep your project dependencies organized:

# macOS/Linuxpython3 -m venv env
source env/bin/activate
# Windowspy -m venv env
env\\Scripts\\activate

Installing Required Packages

Install the necessary Python packages:

# macOS/Linux
python3 -m pip install requests python-dotenv
# Windows
py -m pip install requests python-dotenv

Storing Your API Keys Securely

Never hardcode API keys in your script. Instead, store them as environment variables.

Create a file named .env in your project’s root directory:

ZOOM_API_TOKEN=your_zoom_api_token
ZOOM_WEBINAR_ID=your_webinar_id
SURFE_API_KEY=your_surfe_api_key
OUTREACH_ACCESS_TOKEN=your_outreach_access_token
OUTREACH_SEQUENCE_ID=your_sequence_id
OUTREACH_MAILBOX_ID=your_mailbox_id

Create a Python script file named main.py and add the necessary imports, then create a main function and load all the environment variables:

import os
import sys
import time
from dotenv import load_dotenv

def main():
    # Load environment variables
    load_dotenv()
    zoom_api_token = os.getenv("ZOOM_API_TOKEN")
    surfe_api_key = os.getenv("SURFE_API_KEY")
    outreach_access_token = os.getenv("OUTREACH_ACCESS_TOKEN")
    
    # Get required IDs from environment variables
    webinar_id = os.getenv("ZOOM_WEBINAR_ID")
    sequence_id = os.getenv("OUTREACH_SEQUENCE_ID")
    mailbox_id = os.getenv("OUTREACH_MAILBOX_ID")
    
    # Validate required environment variables
    if not all([zoom_api_token, surfe_api_key, outreach_access_token, webinar_id, sequence_id, mailbox_id]):
        print("Error: Missing required environment variables. Please check your .env file.")
        return

Step 2: Fetching Webinar Registrants from Zoom – Creating a Zoom Service

We will kick off our project by creating a Zoom service containing a variety of functions and utilities specifically concerned with the Zoom Meeting API to help us organise and visualize our logic. Here is how we initialize it:

class ZoomService:
    
    def __init__(self, api_token, api_base_url="<https://api.zoom.us/v2>"):
        self.api_token = api_token
        self.api_base_url = api_base_url

The first component we will build is a method that makes requests to Zoom API while always adding the the api_token to the headers and formatting the endpoint URLs and methods. this will help us make the following components simpler and avoid repeating the same steps:

def _make_request(self, method, endpoint, params=None, data=None, json_data=None):
    url = urljoin(self.api_base_url, endpoint)
    
    headers = {
        "Authorization": f"Bearer {self.api_token}",
        "Content-Type": "application/json",
        "Accept": "application/json"
    }
    
    payload = json.dumps(json_data) if json_data else data
    
    response = requests.request(
        method=method,
        url=url,
        params=params,
        headers=headers,
        data=payload
    )
    
    response.raise_for_status()
    return response.json()

Next, the following function connects to Zoom’s API and retrieves all registrants for a specific webinar. The get_webinar_registrants functions is for handling pagination automatically to ensure we capture all registrants, regardless of the webinar size:

def get_webinar_registrants(self, webinar_id, page_size=100, next_page_token=None):
    endpoint = f"webinars/{webinar_id}/registrants"
    params = {
        "page_size": page_size
    }
    
    if next_page_token:
        params["next_page_token"] = next_page_token
        
    response = self._make_request("GET", endpoint, params=params)
    return response

def get_all_webinar_registrants(self, webinar_id, page_size=100):
    all_registrants = []
    next_page_token = None
    
    while True:
        response = self.get_webinar_registrants(webinar_id, page_size, next_page_token)
        registrants = response.get("registrants", [])
        all_registrants.extend(registrants)
        
        next_page_token = response.get("next_page_token")
        if not next_page_token:
            break
            
    return all_registrants

Not all registrant data is suitable for enrichment. We need to filter and process the data to extract contacts with sufficient information for lead qualification.

The sufficient data for using the enrichment API is either:

  • linkedinUrl OR
  • firstName + lastName + companyName OR
  • firstName + lastName + companyDomain

This function processes the raw registrant data from Zoom to extract essential information like names and company details. Registrants without complete information are filtered out to ensure quality leads:

def process_webinar_registrants(self, registrants):
    processed_registrants = []
    
    for registrant in registrants:            
        # Skip registrants without first name, last name, or company
        if not (registrant.get("first_name") and registrant.get("last_name") and (registrant.get("org") or registrant.get("email"))):
            continue

        if registrant.get("email"):
            companyDomain = registrant.get("email").split("@")[1]
        else:
            companyDomain = None
            
        processed_registrants.append({
            "firstName": registrant.get("first_name", ""),
            "lastName": registrant.get("last_name", ""),
            "companyName": registrant.get("org", ""),
            "companyDomain": companyDomain
        })
            
    return processed_registrants 

Lastly, a method that will fetch the webinar’s full details from zoom to add more data to the prospect:

  def get_webinar_details(self, webinar_id):
      endpoint = f"webinars/{webinar_id}"
      response = self._make_request("GET", endpoint)
      return response

Step 3: Enriching Leads with Surfe API – Creating a Surfe service

Now we’ll enrich the processed registrant data using Surfe’s People Enrichment API to get verified email addresses, phone numbers, and additional information.

This is where the magic happens. We send the processed registrant data to Surfe’s API for enrichment. The API will return verified contact information including email addresses, phone numbers, job titles, and more.

Just like Zoom, we will create a similar service for Surfe methods that will be used to build this script. This is how we will initialize our service:

class SurfeService:    
    def __init__(self, api_key, version="v2"):
        self.api_key = api_key
        self.base_url = f"<https://api.surfe.com/{version}>"
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }

First method we will create is one that prepares the payload for calling the Surfe enrichment API:

def prepare_people_payload(self, people_data):      
    return {
        "include": {
        "email": True,
        "mobile": True,
        "linkedInUrl": True,
		    },
		    "people": people_data
		}

Next is a method that sends a POST request to /v2/people/enrich to start the enrichment process:

def start_enrichment(self, payload):
    url = f"{self.base_url}/people/enrich"
    
    response = requests.post(url, headers=self.headers, json=payload)
    response.raise_for_status()
    data = response.json()
    return data["id"]

Surfe’s bulk enrichment process operates asynchronously, meaning we need to poll the API to check when the process is completed and retrieve the results. The last method is one that Monitors the status of an enrichment request until completion or failure:

def poll_enrichment_status(self, enrichment_id, max_attempts=60, delay=5):
    url = f"{self.base_url}/people/enrich/{enrichment_id}"
    
    attempts = 0
    while attempts < max_attempts:
        response = requests.get(url, headers=self.headers)
        response.raise_for_status()
        data = response.json()
        
        status = data.get("status")
        if status == "COMPLETED":
            return data
        elif status == "FAILED":
            raise Exception(f"Enrichment failed: {data.get('error', 'Unknown error')}")
        
        print(f"Enrichment status: {status}. Waiting {delay} seconds...")
        time.sleep(delay)
        attempts += 1
    
    raise Exception("Enrichment timed out")

Step 4: Adding Prospects in Outreach – Creating an Outreach Service

Same as before, we’ll start initializing a service the holds all helper methods for the Outreach API:

class OutreachService:
    
    def __init__(self, access_token, api_base_url="<https://api.outreach.io/api/v2>"):
        self.access_token = access_token
        self.api_base_url = api_base_url

Now, for each enriched contact we will need to format its new data for Outreach, this function simply maps Surfe’s enrichment response to the Outreach prospect API endpoint:

  def format_enriched_data_for_outreach(self, enriched_person, event_name):
      outreach_data = {
          "firstName": enriched_person.get("firstName", ""),
          "lastName": enriched_person.get("lastName", ""),
          "company": enriched_person.get("companyName", ""),
          "title": enriched_person.get("title", ""),
          "occupation": enriched_person.get("jobTitle", ""),
          "linkedinUrl": enriched_person.get("linkedinUrl", ""),
          "websiteUrl1": enriched_person.get("companyDomain", ""),
          "tags": enriched_person.get("department", []) + enriched_person.get("seniorities", []),
          "event": event_name
      }
      
      # Add all valid emails
      if enriched_person.get("emails") and len(enriched_person["emails"]) > 0:
          # Filter for valid emails and extract email addresses
          valid_emails = [
              email.get("email") 
              for email in enriched_person["emails"]
              if email.get("validationStatus") == "VALID" and email.get("email")
          ]
          if valid_emails:
              outreach_data["emails"] = valid_emails
      
      # Add phone if available
      if enriched_person.get("mobilePhones") and len(enriched_person["mobilePhones"]) > 0:
          # Sort by confidence score
          sorted_phones = sorted(
              enriched_person["mobilePhones"],
              key=lambda x: x.get("confidenceScore", 0),
              reverse=True
          )
          if sorted_phones:
              outreach_data["phones"] = [
                  phone.get("mobilePhone") 
                  for phone in sorted_phones 
                  if phone.get("mobilePhone")
              ]
      
      return outreach_data 
  

Afterwards, we need a function that checks if this contact already exists in the Outreach prospects list using the e-mail provided from Surfe:

def find_prospect_by_email(self, email):
    endpoint = "prospects"
    params = {
        "filter[emails]": email
    }
    
    response = self._make_request("GET", endpoint, params=params)
    
    if response.get("data") and len(response["data"]) > 0:
        return response["data"][0]
    
    return None

After filtering out the existing prospects we will use this function to create new prospects:

def create_prospect(self, prospect_data):
    endpoint = "prospects"
    
    # Format data for Outreach API (JSON:API format)
    json_data = {
        "data": {
            "type": "prospect",
            "attributes": prospect_data
        }
    }
    
    response = self._make_request("POST", endpoint, json_data=json_data)
    return response

The final step is adding the prospects to your Outreach sequence for automated follow-up:

def add_prospect_to_sequence(self, prospect_id, sequence_id, mailbox_id):
    endpoint = "sequenceStates"
    
    # Format data for Outreach API (JSON:API format)
    json_data = {
        "data": {
            "type": "sequenceState",
            "relationships": {
                "prospect": {
                    "data": {
                        "type": "prospect",
                        "id": prospect_id
                    }
                },
                "sequence": {
                    "data": {
                        "type": "sequence",
                        "id": sequence_id
                    }
                },
                "mailbox": {
                    "data": {
                        "type": "mailbox",
                        "id": mailbox_id
                    }
                }
            }
        }
    }
    
    response = self._make_request("POST", endpoint, json_data=json_data)
    return response

Step 5: Putting It All Together

Now it is time to start putting together all the components we just created to build the full script. we go back to the main.py file and build the rest of the script.

The following illustration helps explain better what the flow looks like:

Untitled Diagram.drawio (2)
def main():
    # Load environment variables
    load_dotenv()
    zoom_api_token = os.getenv("ZOOM_API_TOKEN")
    surfe_api_key = os.getenv("SURFE_API_KEY")
    outreach_access_token = os.getenv("OUTREACH_ACCESS_TOKEN")
    
    # Get required IDs from environment variables
    webinar_id = os.getenv("ZOOM_WEBINAR_ID")
    sequence_id = os.getenv("OUTREACH_SEQUENCE_ID")
    mailbox_id = os.getenv("OUTREACH_MAILBOX_ID")
    
    # Validate required environment variables
    if not all([zoom_api_token, surfe_api_key, outreach_access_token, webinar_id, sequence_id, mailbox_id]):
        print("Error: Missing required environment variables. Please check your .env file.")
        return
    
    try:
        # Initialize services
        zoom_service = ZoomService(zoom_api_token)
        surfe_service = SurfeService(surfe_api_key, version="v2")
        outreach_service = OutreachService(outreach_access_token)
        
        # Step 1: Fetch webinar registrants from Zoom
        print(f"Fetching registrants for webinar {webinar_id}...")
        registrants = zoom_service.get_all_webinar_registrants(webinar_id)
        print(f"Found {len(registrants)} registrants for the webinar")
        
        # Step 2: Process registrants to extract essential information
        print("Processing registrants to extract name and company information...")
        processed_registrants = zoom_service.process_webinar_registrants(registrants)
        print(f"Found {len(processed_registrants)} registrants with valid name and company information")
        
        if not processed_registrants:
            print("No registrants with valid information found. Exiting...")
            return
        
        # Step 3: Prepare and start Surfe enrichment
        print("Preparing Surfe enrichment...")
        surfe_payload = surfe_service.prepare_people_payload(processed_registrants)
        
        print("Starting Surfe enrichment process...")
        enrichment_id = surfe_service.start_enrichment(surfe_payload)
        print(f"Enrichment started with ID: {enrichment_id}")
        
        # Step 4: Poll for enrichment results
        print("Polling for enrichment results...")
        enriched_data = surfe_service.poll_enrichment_status(enrichment_id)
        print("Enrichment completed successfully")
        
        enriched_people = enriched_data.get("people", [])
        print(f"Enriched {len(enriched_people)} registrants")
        
        # Step 5: Create prospects in Outreach and add to sequence
        print("Adding enriched registrants to Outreach...")
        event_name = zoom_service.get_webinar_details(webinar_id).get("topic")
        
        success_count = 0
        for person in enriched_people:
            try:
                # Format the enriched data for Outreach
                prospect_data = outreach_service.format_enriched_data_for_outreach(person, event_name)
                
                # Check if we have a valid email
                if not prospect_data.get("emails"):
                    print(f"Skipping {person.get('firstName')} {person.get('lastName')} - No valid email found")
                    continue
                
                # Check if prospect already exists in Outreach
                existing_prospect = outreach_service.find_prospect_by_email(prospect_data["emails"])
                
                if existing_prospect:
                    prospect_id = existing_prospect["id"]
                    print(f"Prospect {person.get('firstName')} {person.get('lastName')} already exists with ID: {prospect_id}")
                else:
                    # Create a new prospect
                    print(f"Creating prospect for {person.get('firstName')} {person.get('lastName')}...")
                    prospect_response = outreach_service.create_prospect(prospect_data)
                    prospect_id = prospect_response["data"]["id"]
                    print(f"Created prospect with ID: {prospect_id}")
                
                # Add the prospect to the sequence
                print(f"Adding prospect {prospect_id} to sequence {sequence_id}...")
                outreach_service.add_prospect_to_sequence(prospect_id, sequence_id, mailbox_id)
                print(f"Successfully added prospect to sequence")
                
                success_count += 1
                
            except Exception as e:
                print(f"Error processing {person.get('firstName')} {person.get('lastName')}: {str(e)}")
        
        print(f"Successfully added {success_count} prospects to Outreach sequence {sequence_id}")
        
    except Exception as e:
        print(f"Error: {str(e)}")

Step 6: Running the Script

Once you’ve set up your environment variables and created the script, you can run it:

Now that you have your complete script, Here’s how to execute the script and what to expect during its operation.

  1. Ensure your .env file contains all necessary variables
# Zoom API credentials
ZOOM_API_TOKEN=your_zoom_jwt_or_oauth_token_here
ZOOM_WEBINAR_ID=your_webinar_id_here

# Surfe API credentials
SURFE_API_KEY=your_surfe_api_key_here

# Outreach API credentials
OUTREACH_ACCESS_TOKEN=your_outreach_oauth_token_here
OUTREACH_SEQUENCE_ID=your_outreach_sequence_id_here
OUTREACH_MAILBOX_ID=your_outreach_mailbox_id_here 
  1. Open your terminal or command prompt, navigate to the directory containing your script, and run:
python main.py

Expected Output

When you run the script, you will see a series of status messages in the console that help you track its progress:

Screenshot 2025-05-26 at 2.29.16 AM

Complete Code for Easy Integration

"""
Zoom Webinar Lead Generation and Outreach Integration

This script fetches webinar registrants from Zoom, enriches them using Surfe API,
and adds them to an Outreach sequence for follow-up.
"""
import os
import sys
import time
from dotenv import load_dotenv

# Add core directory to path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))

# Import core services
from core.surfe import SurfeService
from core.integrations.zoom import ZoomService
from core.integrations.outreach import OutreachService

def main():
"""
Main function to orchestrate the integration process
"""
# Load environment variables
load_dotenv()
zoom_api_token = os.getenv("ZOOM_API_TOKEN")
surfe_api_key = os.getenv("SURFE_API_KEY")
outreach_access_token = os.getenv("OUTREACH_ACCESS_TOKEN")

# Get required IDs from environment variables
webinar_id = os.getenv("ZOOM_WEBINAR_ID")
sequence_id = os.getenv("OUTREACH_SEQUENCE_ID")
mailbox_id = os.getenv("OUTREACH_MAILBOX_ID")

# Validate required environment variables
if not all([zoom_api_token, surfe_api_key, outreach_access_token, webinar_id, sequence_id, mailbox_id]):
print("Error: Missing required environment variables. Please check your .env file.")
return

try:
# Initialize services
zoom_service = ZoomService(zoom_api_token)
surfe_service = SurfeService(surfe_api_key, version="v2")
outreach_service = OutreachService(outreach_access_token)

# Step 1: Fetch webinar registrants from Zoom
print(f"Fetching registrants for webinar {webinar_id}...")
registrants = zoom_service.get_all_webinar_registrants(webinar_id)
print(f"Found {len(registrants)} registrants for the webinar")

# Step 2: Process registrants to extract essential information
print("Processing registrants to extract name and company information...")
processed_registrants = zoom_service.process_webinar_registrants(registrants)
print(f"Found {len(processed_registrants)} registrants with valid name and company information")

if not processed_registrants:
print("No registrants with valid information found. Exiting...")
return

# Step 3: Prepare and start Surfe enrichment
print("Preparing Surfe enrichment...")
surfe_payload = surfe_service.prepare_people_payload(
processed_registrants,
list_name=f"Zoom Webinar {webinar_id} Enrichment {time.strftime('%Y-%m-%d %H:%M:%S')}"
)

print("Starting Surfe enrichment process...")
enrichment_id = surfe_service.start_enrichment(surfe_payload)
print(f"Enrichment started with ID: {enrichment_id}")

# Step 4: Poll for enrichment results
print("Polling for enrichment results...")
enriched_data = surfe_service.poll_enrichment_status(enrichment_id)
print("Enrichment completed successfully")

enriched_people = enriched_data.get("people", [])
print(f"Enriched {len(enriched_people)} registrants")

# Step 5: Create prospects in Outreach and add to sequence
print("Adding enriched registrants to Outreach...")

event_name = zoom_service.get_webinar_details(webinar_id).get("topic")

success_count = 0
for person in enriched_people:
try:
# Format the enriched data for Outreach
prospect_data = outreach_service.format_enriched_data_for_outreach(person, event_name)

# Check if we have a valid email
if not prospect_data.get("emails"):
print(f"Skipping {person.get('firstName')} {person.get('lastName')} - No valid email found")
continue

# Check if prospect already exists in Outreach
existing_prospect = outreach_service.find_prospect_by_email(prospect_data["emails"])

if existing_prospect:
prospect_id = existing_prospect["id"]
print(f"Prospect {person.get('firstName')} {person.get('lastName')} already exists with ID: {prospect_id}")
else:
# Create a new prospect
print(f"Creating prospect for {person.get('firstName')} {person.get('lastName')}...")
prospect_response = outreach_service.create_prospect(prospect_data)
prospect_id = prospect_response["data"]["id"]
print(f"Created prospect with ID: {prospect_id}")

# Add the prospect to the sequence
print(f"Adding prospect {prospect_id} to sequence {sequence_id}...")
outreach_service.add_prospect_to_sequence(prospect_id, sequence_id, mailbox_id)
print(f"Successfully added prospect to sequence")

success_count += 1

except Exception as e:
print(f"Error processing {person.get('firstName')} {person.get('lastName')}: {str(e)}")

print(f"Successfully added {success_count} prospects to Outreach sequence {sequence_id}")

except Exception as e:
print(f"Error: {str(e)}")

if __name__ == "__main__":
main()

Final Notes: Credits, Quotas, and Rate Limiting

Credits & Quotas

Surfe’s API uses a credit system for people enrichment. Retrieving email, landline, and job details consumes email credits, while retrieving mobile phone numbers consumes mobile credits. There are also daily quotas, such as 2,000 people enrichments per day and 200 organization look-alike searches per day. For more information on credits and quotas, please speak to a Surfe representative to discuss a tailored plan that works for you and your business needs. Quotas reset at midnight (local time), and additional credits can be purchased if needed. For full details, refer to the Credits & Quotas documentation.

Rate Limiting

Surfe enforces rate limits to ensure fair API usage. Users can make up to 10 requests per second, with short bursts of up to 20 requests allowed. The limit resets every minute. Exceeding this results in a 429 Too Many Requests error, so it’s recommended to implement retries in case of rate limit issues. Learn more in the Rate Limits documentation.

Surfe is trusted by 30000 sales people wordwide

Webinar’s done. Leads are in. Let’s make them count.

Go on—give Surfe a spin and turn those Zoom leads into actual pipeline.

Contact Enrichment API FAQs

What’s the Benefit of Enriching Zoom Webinar Leads?

Webinar registrants are warm leads, but they’re often missing key details like email validation, phone numbers, or job titles. Enriching this data means your sales team can follow up faster, more accurately, and more personally—without wasting time on research or bad contact info.

How Does This Script Help with Webinar Follow-Up?

This script fetches webinar registrants directly from Zoom, enriches them using Surfe’s API, and pushes them into Outreach as fully-formed prospects. That means no CSV exports, manual copy-pasting, or delayed follow-ups—it’s one streamlined flow from signup to sequence.

Do I Need API Access for Zoom and Outreach?

Yes. You’ll need access to the Zoom API (via JWT or OAuth) and Outreach’s API (via OAuth token). Setting this up usually takes just a few minutes through their developer portals. We walk you through everything you need in the tutorial.

Can I Run This Script Without a Developer?

If you’re comfortable with basic Python or know how to follow setup instructions, you can absolutely run this on your own. The tutorial is written for non-devs and includes environment setup, API key loading, and all required packages.

What Kind of Data Does Surfe’s API Enrich for Webinar Leads?

Surfe can return verified email addresses, mobile numbers, job titles, seniority, LinkedIn URLs, and more. The better your input data (e.g., name + company), the more complete and accurate your enrichment results will be.

What Happens If a Prospect Already Exists in Outreach?

The script includes a check to avoid creating duplicates. If a registrant’s email already exists in Outreach, it simply skips creation and moves straight to sequence assignment—saving time and keeping your CRM clean.

How Often Should I Run the Script?

That’s up to your workflow. You can run it after every webinar, on a weekly schedule, or as soon as new registrants appear. Just make sure to monitor your API credit usage if you’re processing large lists frequently.