Update: January 2025 - Proxycurl officially shut down after LinkedIn filed a federal lawsuit for "unauthorized creation of hundreds of thousands of fake accounts." If you're reading this, you're probably scrambling to find an alternative.
Good news: LinkdAPI is not only a superior replacement—it's actually BETTER than Proxycurl ever was, and you can migrate in 2-3 hours.
This guide provides everything you need for a smooth, zero-downtime migration from Proxycurl to LinkdAPI.
Why This Migration Guide Exists
January 24, 2025: LinkedIn filed lawsuit against Proxycurl
July 2025: Proxycurl officially shut down
Today: Thousands of companies need to migrate URGENTLY
If you're one of them, you're in the right place.
What you'll get from this guide:
- ✅ Complete endpoint mapping (Proxycurl → LinkdAPI)
- ✅ Code migration examples (copy-paste ready)
- ✅ Response format differences explained
- ✅ Zero-downtime migration strategy
- ✅ Performance improvements you'll gain
- ✅ Cost comparison (you'll save money)
- ✅ Timeline: 2-3 hours total migration time
By the end of this guide, your application will be:
- Running on LinkdAPI (more reliable)
- Faster than before (3-5x speed improvement)
- More compliant (zero account risk)
- Cheaper (better pricing)
- Future-proof (LinkdAPI won't get shut down)
Let's get you migrated.
Why LinkdAPI is Better Than Proxycurl
Let's be honest about why Proxycurl shut down and why LinkdAPI won't.
The Proxycurl Problem
What went wrong:
- Used hundreds of thousands of fake LinkedIn accounts
- Violated LinkedIn Terms of Service at scale
- Got sued by LinkedIn
- Forced to shut down
- Left customers stranded
The risk you took:
- Your data came from fake accounts
- Legal exposure (using ToS-violating service)
- No guarantee of uptime
- Could disappear any day (it did)
The LinkdAPI Difference
Why we're different:
- ✅ Zero LinkedIn accounts - We don't use ANY accounts (fake or real)
- ✅ Cannot be shut down - No ToS violation = no lawsuit risk
- ✅ More compliant - Based on hiQ Labs precedent (LinkedIn lost)
- ✅ Better performance - 3-5x faster than Proxycurl
- ✅ Lower cost - Better pricing, more transparent
- ✅ More features - 40+ endpoints vs Proxycurl's limited set
- ✅ Better reliability - 99.9% uptime SLA
- ✅ AsyncLinkdAPI - 100x faster concurrent processing
Bottom line: LinkdAPI is what Proxycurl should have been—compliant, reliable, and here to stay.
Feature Comparison
| Feature | Proxycurl | LinkdAPI |
|---|---|---|
| Account Risk | ❌ HIGH (fake accounts) | ✅ ZERO (no accounts) |
| Legal Risk | ❌ HIGH (ToS violation) | ✅ LOW (hiQ precedent) |
| Shutdown Risk | ❌ Already happened | ✅ Not possible |
| Response Time | 1.5-3 seconds | 0.3-0.9 seconds |
| Uptime SLA | None | 99.9% |
Winner: LinkdAPI in every category.
Quick Start: Get Running in 30 Minutes
Need to get something working RIGHT NOW? Here's the fastest path:
Step 1: Sign Up (2 minutes)
- 100 free credits
- No credit card required
- Instant API key
Step 2: Install SDK (10 seconds)
1# Remove Proxycurl (if you used their SDK)
2pip uninstall proxycurl
3
4# Install LinkdAPI
5pip install linkdapiStep 3: Replace Your Code (5 minutes)
Before (Proxycurl):
1from proxycurl import Proxycurl
2
3proxycurl = Proxycurl(api_key='YOUR_PROXYCURL_KEY')
4person = proxycurl.linkedin.person.get(url='https://www.linkedin.com/in/ryanroslansky')After (LinkdAPI):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def get_profile():
5 client = AsyncLinkdAPI("YOUR_LINKDAPI_KEY")
6 profile = await client.get_full_profile("ryanroslansky")
7 return profile
8
9# Run it
10profile = asyncio.run(get_profile())That's it. You're now running on LinkdAPI.
Step 4: Test (5 minutes)
1# Test with a known profile
2profile = asyncio.run(get_profile())
3
4print(f"Name: {profile['firstName']} {profile['lastName']}")
5print(f"Headline: {profile['headline']}")
6print(f"Company: {profile['position'][0]['companyName']}")
7
8# If this works, you're good to goStep 5: Deploy (10 minutes)
- Update environment variables (
LINKDAPI_API_KEY) - Deploy to staging
- Run smoke tests
- Deploy to production
Total time: 30 minutes to get running.
Now let's do a proper migration.
Complete Endpoint Mapping
Here's how Proxycurl endpoints map to LinkdAPI:
Person/Profile Endpoints
| Proxycurl Endpoint | LinkdAPI Endpoint | Notes |
|---|---|---|
| GET /linkedin/profile | get_full_profile(username) | BETTER: One call gets everything |
| GET /linkedin/profile/contact | get_profile_contact(username) | Contact info |
| GET /linkedin/profile/experiences | Included in get_full_profile() | No separate call needed |
| GET /linkedin/profile/education | Included in get_full_profile() | No separate call needed |
| GET /linkedin/profile/skills | get_profile_skills(username) | Or use get_full_profile() |
Key Difference: LinkdAPI's get_full_profile() returns EVERYTHING in one call:
- Basic info
- Complete work history
- Education
- Skills
- Certifications
- Languages
- Profile pictures (all sizes)
- And more
Proxycurl required 5+ API calls. LinkdAPI needs ONE.
Company Endpoints
| Proxycurl Endpoint | LinkdAPI Endpoint | Notes |
|---|---|---|
| GET /linkedin/company | get_company_overview(company_id) | Company details |
| GET /linkedin/company/employees | get_company_employees(company_id) | Employee list |
| GET /linkedin/company/updates | get_company_posts(company_id) | Company posts |
Search Endpoints
| Proxycurl Endpoint | LinkdAPI Endpoint | Notes |
|---|---|---|
| GET /linkedin/search/person | Not available - Use company employees or similar profiles | Alternative approach |
| GET /linkedin/search/company | company_name_lookup(query) | Company search by name |
Posts/Activity Endpoints
| Proxycurl Endpoint | LinkdAPI Endpoint | Notes |
|---|---|---|
| GET /linkedin/profile/posts | get_all_posts(urn) | User posts (requires URN) |
| GET /linkedin/post | get_post_info(urn) | Post details |
| GET /linkedin/post/comments | get_post_comments(urn) | Post comments |
| GET /linkedin/post/likes | get_post_likes(urn) | Post reactions |
Job Endpoints
| Proxycurl Endpoint | LinkdAPI Endpoint | Notes |
|---|---|---|
| GET /linkedin/job | get_job_details(job_id) | Job posting details |
| GET /linkedin/search/job | search_jobs(keywords, filters) | Job search |
LinkdAPI has 40+ total endpoints. If Proxycurl had something we don't have listed, contact support - we probably have it or can add it quickly.
Code Migration Examples
Let's migrate real code patterns from Proxycurl to LinkdAPI.
Pattern 1: Get Person Profile
Before (Proxycurl):
1from proxycurl import Proxycurl
2
3proxycurl = Proxycurl(api_key='YOUR_KEY')
4
5# Get basic profile
6person = proxycurl.linkedin.person.get(
7 url='https://www.linkedin.com/in/ryanroslansky'
8)
9
10print(person['first_name'])
11print(person['headline'])After (LinkdAPI - Sync):
1from linkdapi import LinkdAPI
2
3client = LinkdAPI("YOUR_KEY")
4
5# Get FULL profile in one call
6profile = client.get_full_profile("ryanroslansky")
7
8print(profile['firstName'])
9print(profile['headline'])After (LinkdAPI - Async - RECOMMENDED):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def get_profile():
5 client = AsyncLinkdAPI("YOUR_KEY")
6
7 # Get FULL profile in one call
8 profile = await client.get_full_profile("ryanroslansky")
9
10 return profile
11
12# Run it
13profile = asyncio.run(get_profile())
14
15print(profile['firstName'])
16print(profile['headline'])Improvement:
- ✅ One call instead of multiple
- ✅ More data returned
- ✅ Async support for scale
- ✅ 3x faster response time
Pattern 2: Bulk Profile Enrichment
Before (Proxycurl):
1from proxycurl import Proxycurl
2import time
3
4proxycurl = Proxycurl(api_key='YOUR_KEY')
5
6usernames = ["ryanroslansky", "williamhgates", "jeffweiner08"] # 100 usernames
7profiles = []
8
9for username in usernames:
10 url = f"https://www.linkedin.com/in/{username}"
11 profile = proxycurl.linkedin.person.get(url=url)
12 profiles.append(profile)
13 time.sleep(1) # Rate limiting
14
15# Takes: 100 seconds for 100 profilesAfter (LinkdAPI - Async - GAME CHANGER):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def enrich_bulk(usernames):
5 client = AsyncLinkdAPI("YOUR_KEY")
6
7 # Process ALL concurrently
8 tasks = [client.get_full_profile(username) for username in usernames]
9 profiles = await asyncio.gather(*tasks)
10
11 return profiles
12
13# Run it
14usernames = ["ryanroslansky", "williamhgates", "jeffweiner08"] # 100 usernames
15profiles = asyncio.run(enrich_bulk(usernames))
16
17# Takes: 0.5 seconds for 100 profiles (200x faster!)Improvement:
- ✅ 200x faster (concurrent vs sequential)
- ✅ No manual rate limiting needed
- ✅ Cleaner code
- ✅ Production-ready
Pattern 3: Get Profile with Contact Info
Before (Proxycurl - Required 2 calls):
1from proxycurl import Proxycurl
2
3proxycurl = Proxycurl(api_key='YOUR_KEY')
4
5# Call 1: Get profile
6person = proxycurl.linkedin.person.get(
7 url='https://www.linkedin.com/in/ryanroslansky'
8)
9
10# Call 2: Get contact info (separate endpoint!)
11contact = proxycurl.linkedin.person.contact.get(
12 url='https://www.linkedin.com/in/ryanroslansky'
13)
14
15# Combine manually
16result = {**person, **contact}After (LinkdAPI - ONE call):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def get_profile_with_contact():
5 client = AsyncLinkdAPI("YOUR_KEY")
6
7 # ONE call gets everything
8 profile = await client.get_full_profile("ryanroslansky")
9
10 # All data already included:
11 # - Basic info
12 # - Experience
13 # - Education
14 # - Skills
15 # - Contact info (if available)
16
17 return profile
18
19profile = asyncio.run(get_profile_with_contact())Improvement:
- ✅ 1 call instead of 2 (50% cost reduction)
- ✅ 2x faster
- ✅ No manual combining
- ✅ Atomic operation (no race conditions)
Pattern 4: Get Company Data
Before (Proxycurl):
1from proxycurl import Proxycurl
2
3proxycurl = Proxycurl(api_key='YOUR_KEY')
4
5company = proxycurl.linkedin.company.get(
6 url='https://www.linkedin.com/company/linkedin'
7)
8
9print(company['name'])
10print(company['follower_count'])After (LinkdAPI):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def get_company():
5 client = AsyncLinkdAPI("YOUR_KEY")
6
7 # Use company_name (vanity name) not full URL
8 company = await client.get_company_info(name="linkedin")
9
10 return company
11
12company = asyncio.run(get_company())
13
14print(company['name'])
15print(company['followerCount'])Improvement:
- ✅ Simpler (use company name, not URL)
- ✅ More data returned
- ✅ Async support
Pattern 5: Get Posts from Profile
Before (Proxycurl):
1from proxycurl import Proxycurl
2
3proxycurl = Proxycurl(api_key='YOUR_KEY')
4
5posts = proxycurl.linkedin.profile.posts(
6 url='https://www.linkedin.com/in/ryanroslansky'
7)
8
9for post in posts['results']:
10 print(post['text'])After (LinkdAPI):
1from linkdapi import AsyncLinkdAPI
2import asyncio
3
4async def get_posts():
5 client = AsyncLinkdAPI("YOUR_KEY")
6
7 # First get the profile URN
8 profile = await client.get_profile_overview("ryanroslansky")
9 urn = profile['urn']
10
11 # Then get all posts using the URN
12 posts = await client.get_all_posts(urn)
13
14 return posts
15
16posts = asyncio.run(get_posts())
17
18for post in posts:
19 print(post.get('text', ''))Improvement:
- ✅ More post metadata
- ✅ Better pagination support
- ✅ Access to reactions and comments
Response Format Differences
Proxycurl and LinkdAPI return data in slightly different formats. Here's what to know:
Response Structure
Proxycurl:
1{
2 "first_name": "Ryan",
3 "last_name": "Roslansky",
4 "headline": "CEO at LinkedIn",
5 "experiences": [...]
6}LinkdAPI:
1{
2 "success": true,
3 "statusCode": 200,
4 "message": "Data retrieved successfully",
5 "errors": null,
6 "data": {
7 "firstName": "Ryan",
8 "lastName": "Roslansky",
9 "headline": "CEO at LinkedIn",
10 "position": [...]
11 }
12}Migration: Access data via response['data'] or use the SDK which handles this automatically:
1# SDK automatically extracts data
2profile = await client.get_full_profile("ryanroslansky")
3# profile is already the data object, not wrappedField Name Mapping
| Proxycurl Field | LinkdAPI Field | Notes |
|---|---|---|
| first_name | firstName | camelCase |
| last_name | lastName | camelCase |
| headline | headline | Same ✅ |
| experiences | position or fullPositions | More detailed |
| education | educations | Array |
| skills | skills | Same structure ✅ |
Quick Conversion Helper
1def convert_proxycurl_to_linkdapi_format(proxycurl_profile):
2 """
3 Convert Proxycurl response format to LinkdAPI format
4 Useful during migration for backward compatibility
5 """
6 return {
7 'firstName': proxycurl_profile.get('first_name'),
8 'lastName': proxycurl_profile.get('last_name'),
9 'headline': proxycurl_profile.get('headline'),
10 'summary': proxycurl_profile.get('summary'),
11 'profilePicture': proxycurl_profile.get('profile_pic_url'),
12 'position': proxycurl_profile.get('experiences', []),
13 'educations': proxycurl_profile.get('education', []),
14 'skills': proxycurl_profile.get('skills', []),
15 # Add more fields as needed
16 }Or create an adapter layer:
1class LinkdAPIProxycurlAdapter:
2 """
3 Adapter to make LinkdAPI responses look like Proxycurl
4 Use this for gradual migration
5 """
6 def __init__(self, linkdapi_key):
7 self.client = AsyncLinkdAPI(linkdapi_key)
8
9 async def get_person(self, url):
10 # Extract username from URL
11 username = url.split('/')[-1] if '/' in url else url
12
13 # Get profile from LinkdAPI
14 profile = await self.client.get_full_profile(username)
15
16 # Convert to Proxycurl format
17 return {
18 'first_name': profile.get('firstName'),
19 'last_name': profile.get('lastName'),
20 'headline': profile.get('headline'),
21 'summary': profile.get('summary'),
22 'profile_pic_url': profile.get('profilePicture'),
23 'experiences': profile.get('position', []),
24 'education': profile.get('educations', []),
25 'skills': profile.get('skills', []),
26 # Add more fields as needed
27 }
28
29# Usage
30adapter = LinkdAPIProxycurlAdapter("YOUR_KEY")
31person = await adapter.get_person("https://www.linkedin.com/in/ryanroslansky")
32# Returns Proxycurl-like formatMigration Timeline & Strategy
Here's a realistic timeline for migrating from Proxycurl to LinkdAPI:
Timeline: 2-3 Hours Total
Hour 1: Setup & Testing (60 minutes)
- Sign up for LinkdAPI (2 min)
- Install SDK (1 min)
- Test basic endpoint (10 min)
- Test bulk processing (15 min)
- Test with your actual data (30 min)
Hour 2: Code Migration (45-60 minutes)
- Map Proxycurl calls to LinkdAPI (15 min)
- Update API client initialization (5 min)
- Update endpoint calls (20 min)
- Update response parsing (15 min)
- Add error handling (10 min)
Hour 3: Testing & Deployment (30-45 minutes)
- Unit tests (15 min)
- Integration tests (15 min)
- Deploy to staging (5 min)
- Smoke tests (5 min)
- Deploy to production (5 min)
Total: 2 hours 45 minutes (realistic for most applications)
Migration Strategy Options
Option 1: Instant Cutover (Recommended for Simple Apps)
When to use:
- Small codebase (<1000 lines)
- Few Proxycurl calls
- Can afford brief downtime
Steps:
- Test LinkdAPI in development
- Update all Proxycurl calls to LinkdAPI
- Deploy during low-traffic period
- Monitor for issues
Downtime: 5-10 minutes
Risk: Low
Effort: 2-3 hours
Option 2: Adapter Pattern (Recommended for Complex Apps)
When to use:
- Large codebase
- Many Proxycurl calls
- Zero downtime required
- Want to test gradually
Steps:
- Create
LinkdAPIProxycurlAdapterclass - Replace Proxycurl client with adapter
- Adapter translates calls to LinkdAPI
- Test in production with real traffic
- Remove adapter once stable
Example:
1# Step 1: Create adapter
2class ProxycurlCompatAdapter:
3 """Drop-in replacement for Proxycurl that uses LinkdAPI"""
4
5 def __init__(self, api_key):
6 self.client = AsyncLinkdAPI(api_key)
7
8 async def get_person(self, url):
9 username = url.split('/')[-1]
10 profile = await self.client.get_full_profile(username)
11
12 # Convert to Proxycurl format
13 return self._convert_to_proxycurl_format(profile)
14
15 def _convert_to_proxycurl_format(self, linkdapi_profile):
16 return {
17 'first_name': linkdapi_profile.get('firstName'),
18 'last_name': linkdapi_profile.get('lastName'),
19 # ... rest of conversion
20 }
21
22# Step 2: Replace Proxycurl client
23# OLD: client = Proxycurl(api_key='...')
24# NEW: client = ProxycurlCompatAdapter(api_key='...')
25
26# Step 3: Your code works without changes!
27person = await client.get_person('https://www.linkedin.com/in/ryanroslansky')Start building with 100 free credits
Access profiles, companies, jobs, and more through our reliable, high-performance API. No credit card required.
Downtime: Zero
Risk: Very low
Effort: 3-4 hours
Option 3: Feature Flag Pattern (Enterprise)
When to use:
- Mission-critical application
- Need gradual rollout
- A/B testing desired
- Want instant rollback
Steps:
- Add feature flag (
use_linkdapi) - Implement both Proxycurl and LinkdAPI calls



