Integration Guide
Scrape B2B leads from Apollo, Google Maps, or the Lead Database and push them into Lemlist campaigns. Each contact enters your multichannel sequences with email, phone, LinkedIn URL, and custom variables for personalization - ready for outreach within minutes.
ScraperCity pulls B2B contacts with verified emails, phone numbers, job titles, company names, and LinkedIn URLs. Lemlist accepts new leads via its REST API. Connect the two and scraped contacts flow directly into your multichannel sequences - email, LinkedIn, and phone call steps all personalized with the scraped data.
The core flow has three stages. First, query a ScraperCity endpoint to collect contacts that match your ideal customer profile. Second, validate emails through the ScraperCity Email Validator ($0.0036/email) to remove invalid and risky addresses before they reach your sending domain. Third, POST each clean contact to the Lemlist campaign endpoint and let your sequence take over.
This same pattern works whether you run it as a one-off script, a scheduled cron job, or a no-code workflow in n8n, Zapier, Make, or Pipedream. The ScraperCity and Lemlist APIs are both REST-based with straightforward authentication, so any environment that can make HTTP requests can automate this pipeline.
Log into ScraperCity and open app.scrapercity.com/dashboard/api-docs. Copy your API key - you will pass it as a Bearer token in every request.
ScraperCity plans start at $49/mo. All plans include API access to all 25 scrapers. The Lead Database endpoint (3M+ B2B contacts, instant results) requires the $649/mo plan.
In Lemlist, go to Settings, then Integrations, then API. Name the key (for example, "ScraperCity Import") and click Create Key. Copy it immediately - Lemlist only shows the key once after generation. Store it in an environment variable, never in source code.
The Lemlist API uses HTTP Basic authentication for most endpoints. Your username is empty and your password is the API key. The shorthand in curl is -u ":YOUR_LEMLIST_API_KEY".
Query any ScraperCity endpoint for your target audience. The example below fetches Apollo contacts with verified emails for Heads of Growth at internet companies:
curl -X GET "https://app.scrapercity.com/api/v1/database/leads?title=Head%20of%20Growth&industry=internet&hasEmail=true&limit=50" \
-H "Authorization: Bearer YOUR_SCRAPERCITY_KEY"The Lead Database returns up to 100 leads per page and supports filters including title, industry, location, company size, and more. Apollo scrapes take 11-48+ hours to deliver. Lead Database queries are instant.
Run each email through the ScraperCity Email Validator before sending to Lemlist. This removes invalid addresses and protects your sending domain reputation:
curl -X POST "https://app.scrapercity.com/api/v1/email-validator" \
-H "Authorization: Bearer YOUR_SCRAPERCITY_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'Only import leads where the validator returns a valid or safe result. Validation costs $0.0036/email. Skipping this step risks bounces that degrade your Lemlist warm-up progress.
You need the campaign ID before adding leads. Two ways to get it:
curl -X GET "https://api.lemlist.com/api/campaigns" \
-u ":YOUR_LEMLIST_API_KEY"POST each contact to the Lemlist campaign leads endpoint. Map ScraperCity fields directly to Lemlist lead fields:
curl -X POST "https://api.lemlist.com/api/campaigns/CAMPAIGN_ID/leads/" \
-u ":YOUR_LEMLIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"firstName": "Jane",
"lastName": "Smith",
"companyName": "Acme Corp",
"jobTitle": "Head of Growth",
"phone": "+15551234567",
"linkedinUrl": "https://linkedin.com/in/janesmith",
"timezone": "America/New_York"
}'Replace CAMPAIGN_ID with the cam_XXXXX value from Step 5. If the lead does not already exist in Lemlist, the API creates and adds them in one call. All fields except email are optional but improve personalization in your sequence templates.
ScraperCity returns a consistent set of fields across most scrapers. Here is how they map to the Lemlist lead object:
| ScraperCity field | Lemlist field | Notes |
|---|---|---|
| Required. Validate before import. | ||
| firstName | firstName | Used in {{firstName}} merge tags. |
| lastName | lastName | Used in {{lastName}} merge tags. |
| company | companyName | Used in {{companyName}} merge tags. |
| title | jobTitle | Good for personalized openers. |
| phone | phone | Enables phone call tasks in sequences. |
| linkedinUrl | linkedinUrl | Powers LinkedIn visit, invite, and message steps. |
| industry | custom variable | Pass as any extra field; accessible as {{industry}} in templates. |
For recurring cold outreach automation, a short script ties the two APIs together. The example below fetches a page of ScraperCity leads and posts each one to Lemlist with a small delay to stay well under the Lemlist rate limit of 20 requests per 2 seconds.
import time, requests
SC_KEY = "YOUR_SCRAPERCITY_KEY"
LL_KEY = "YOUR_LEMLIST_KEY"
CAMPAIGN_ID = "cam_XXXXX"
# 1. Fetch leads from ScraperCity Lead Database
sc_resp = requests.get(
"https://app.scrapercity.com/api/v1/database/leads",
headers={"Authorization": f"Bearer {SC_KEY}"},
params={"title": "Head of Growth", "industry": "saas", "hasEmail": "true", "limit": 50},
)
leads = sc_resp.json().get("data", [])
for lead in leads:
email = lead.get("email")
if not email:
continue
# 2. Validate email
val = requests.post(
"https://app.scrapercity.com/api/v1/email-validator",
headers={"Authorization": f"Bearer {SC_KEY}", "Content-Type": "application/json"},
json={"email": email},
).json()
if val.get("status") not in ("valid", "safe"):
continue
# 3. Add to Lemlist campaign
payload = {
"email": email,
"firstName": lead.get("firstName", ""),
"lastName": lead.get("lastName", ""),
"companyName": lead.get("company", ""),
"jobTitle": lead.get("title", ""),
"phone": lead.get("phone", ""),
"linkedinUrl": lead.get("linkedinUrl", ""),
}
r = requests.post(
f"https://api.lemlist.com/api/campaigns/{CAMPAIGN_ID}/leads/",
auth=("", LL_KEY),
json=payload,
)
print(r.status_code, email)
time.sleep(0.15) # ~6-7 req/sec - well inside the 20 req/2s limitStore both API keys in environment variables. Never commit them to source control.
Once the basic API connection is working, you can build more advanced sales outreach automation pipelines by combining ScraperCity scrapers with different Lemlist campaign types.
Lemlist can push activity events back to any URL via webhooks, so you can keep your CRM or database in sync without polling. Register a webhook with a single API call and choose which events to subscribe to.
Useful events include emailsReplied, emailsBounced, linkedinInterested, interested, and campaignComplete. You can also scope a webhook to a single campaign so you only receive events relevant to a particular sequence.
# Register a webhook for reply events
curl -X POST "https://api.lemlist.com/api/hooks" \
-u ":YOUR_LEMLIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targetUrl": "https://your-server.com/lemlist-webhook",
"type": "emailsReplied"
}'
# The response includes the webhook ID you can use to delete it later
# { "_id": "hoo_XXXXX", "targetUrl": "...", "type": "emailsReplied" }When a reply comes in, Lemlist POSTs a JSON payload to your endpoint. A typical use case: on emailsReplied, mark the contact as "replied" in HubSpot or Airtable, then pause them in other active campaigns so they do not receive duplicate outreach.
Always return HTTP 200 from your webhook endpoint immediately, then process the event asynchronously. Lemlist may retry failed deliveries, so store processed event IDs to skip duplicates.
You do not need to write a script to run this integration. Both n8n and Zapier have built-in Lemlist nodes, and ScraperCity is callable via an HTTP Request node with a Bearer token header. A typical no-code workflow looks like this:
n8n has a native Lemlist integration that handles authentication automatically. In Make (Integromat), the Lemlist module includes an "Add a lead" action that accepts all standard fields. Pipedream offers a pre-built Lemlist component you can drop into any workflow.
Validate before you import. Run every email through ScraperCity Email Validator ($0.0036/email). Remove invalid and catch-all addresses. Only send verified emails to Lemlist to preserve your sender reputation and warm-up progress.
Ramp batch sizes during warm-up. Import 50-100 leads per day while your sending domain is warming up. Lemlist manages sending limits internally, but flooding a fresh inbox with 1,000 new leads at once can stall your warm-up score.
Populate the LinkedIn URL field. ScraperCity returns LinkedIn profile URLs for most Apollo contacts. When this field is populated in Lemlist, your sequences can automate LinkedIn profile visits, connection requests, and direct messages alongside email steps.
Use custom variables for personalization. Any field you POST to the Lemlist lead endpoint beyond the standard fields is accessible as a merge variable in your sequence templates. Pass industry, company size, or a scraped snippet as a custom field and reference it as {{industry}} in your email body.
Respect the rate limit. The Lemlist API allows 20 requests per 2 seconds per API key. If you receive a 429 response, read the Retry-After header and wait that many seconds before retrying. Implement exponential backoff in any automation script.
401 Unauthorized from Lemlist API
Cause: The API key is missing, incorrect, or passed using the wrong authentication method.
Fix: Lemlist uses HTTP Basic auth for most endpoints. Pass the key as the password with an empty username: -u ":YOUR_API_KEY". Do not pass it as a Bearer token or in the JSON body.
404 Not Found on the add-lead endpoint
Cause: The campaign ID in the URL is wrong or the campaign has been deleted.
Fix: Double-check the campaign ID from the Lemlist URL or from GET /api/campaigns. Campaign IDs follow the pattern cam_XXXXX.
429 Too Many Requests from Lemlist
Cause: You are exceeding 20 requests per 2 seconds.
Fix: Add a sleep between requests (150ms between calls keeps you at ~6-7 req/sec). Read the X-RateLimit-Remaining and Retry-After response headers and pause when remaining hits zero.
Lead already exists in campaign
Cause: A lead with the same email is already in this campaign.
Fix: The Lemlist API returns a 4xx error when you try to add a duplicate. Check for this response and skip or update the lead rather than failing the whole batch.
ScraperCity Apollo job still pending after several hours
Cause: Apollo scrapes are asynchronous and take 11-48+ hours depending on the size of the request.
Fix: Poll the ScraperCity status endpoint with the runId returned from the initial request, or configure a webhook at app.scrapercity.com/dashboard/webhooks to receive a notification when the job completes. Then trigger the Lemlist import step automatically.
High bounce rate after import
Cause: Emails were not validated before being sent to Lemlist.
Fix: Pass every email through the ScraperCity Email Validator before adding leads to a campaign. Only import addresses with a valid or safe status. A bounce rate above 2-3% can cause inbox providers to throttle your sending domain.
ScraperCity operates on a credit-based model billed monthly. All plans include API access to all 25 scrapers.
| Plan | Monthly | Lead Database | Good for |
|---|---|---|---|
| Starter | $49/mo | Not included | Apollo and Google Maps scrapes for targeted lists |
| Growth | $149/mo | Not included | Larger Apollo runs, multi-source scraping, email validation at scale |
| Scale | $649/mo | Included (3M+ contacts, instant) | Agencies and teams running high-volume cold outreach automation |
Per-lead costs
Delivery times