Scraping is asynchronous: submit a run → poll → fetch data. The full flow is in Quick Start; the shared response envelope / run state machine / billing / error codes are in Auth & Error Handling. This page only lists each endpoint's submit target fields and output fields.
Common Conventions
| Item | Value |
|---|---|
| Base URL | https://api.antsdata.com/v1 |
| Method | POST (submit run) |
| Auth | Authorization: Bearer ants_xxxxxxxxxxxx |
| Content-Type | application/json |
The submit body is always { "deliveryMode": "async", "recordLimit": 1000, "targets": [ … ] }; the fields of each targets[] element are listed in the "Target fields" table for each endpoint below. Submit returns HTTP 201 + { "code": 0, "message": "ok", "data": { "id": <run id>, "status": "queued" } }. Then poll GET /v1/scraper/runs/{id} until succeeded and fetch records via GET /v1/scraper/runs/{id}/records.
💡 You can also use
deliveryMode: "sync"(small jobs block until terminal, auto fallback to polling on timeout) — see quick-start · Sync mode.
Endpoints:
| Endpoint | Path | Description |
|---|---|---|
| Profile | /v1/scraper/linkedin/profile |
Personal profile (with experience / education / skills / languages / certifications) |
| Company | /v1/scraper/linkedin/company |
Company page details |
| Jobs | /v1/scraper/linkedin/jobs |
Job listing search |
| Profile Posts | /v1/scraper/linkedin/posts |
Posts from a personal profile |
| Company Posts | /v1/scraper/linkedin/posts-company |
Posts from a company page |
Profile
Extract a profile's public information by URL (including work experience, education, and skills). Each URL is one target; submit multiple in a single run for batching.
Endpoint: POST /v1/scraper/linkedin/profile
Target fields (each targets[] element):
| Field | Type | Required | Description |
|---|---|---|---|
profileUrl |
string | ✅ Required | Profile URL (one per row; must contain /in/<vanity>) |
Output fields (each record):
| Field | Type | Description |
|---|---|---|
fullName |
string | Full name |
headline |
string | Headline |
location |
string | City |
industry |
string | Industry |
summary |
string | Detailed bio |
profileUrl |
string | Profile URL |
profileImageUrl |
string | Avatar URL |
bannerImageUrl |
string | Banner image URL |
connections |
number | Number of connections |
followersCount |
number | Follower count |
experience |
array | Work experience |
experience.title |
string | Job title |
experience.company |
string | Company name |
experience.companyUrl |
string | Company URL on LinkedIn |
experience.dateRange |
string | Date range of the position |
experience.location |
string | Location of the position |
experience.description |
string | Description of the position |
experience.isCurrent |
boolean | Whether this is the current position |
education |
array | Education |
education.school |
string | School name |
education.degree |
string | Degree |
education.fieldOfStudy |
string | Field of study |
education.dateRange |
string | Date range of the education entry |
skills |
array | Skill tags |
languages |
array | Languages |
languages.name |
string | Language name |
languages.proficiency |
string | Proficiency level |
certifications |
array | Certifications |
certifications.name |
string | Certification name |
certifications.authority |
string | Issuing authority |
certifications.issueDate |
string | Issue date |
Submit example (one run scraping 2 profiles):
curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/profile" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deliveryMode": "async",
"recordLimit": 1000,
"targets": [
{ "profileUrl": "https://www.linkedin.com/in/williamhgates/" },
{ "profileUrl": "https://www.linkedin.com/in/satyanadella/" }
]
}'
Returns
201→{ "code": 0, "data": { "id": 1287345, "status": "queued" } }. Record theid, pollGET /v1/scraper/runs/1287345untilsucceeded, then fetch records.
Company
Extract a company page's public information by URL. Each URL is one target; submit multiple in a single run for batching.
Endpoint: POST /v1/scraper/linkedin/company
Target fields (each targets[] element):
| Field | Type | Required | Description |
|---|---|---|---|
companyUrl |
string | ✅ Required | Company page URL (one per row; must contain /company/<slug>) |
Output fields (each record):
| Field | Type | Description |
|---|---|---|
companyId |
string | Internal LinkedIn company ID |
name |
string | Full company name |
description |
string | Company description |
website |
string | Official website URL |
industry |
string | Industry |
companySize |
string | Company size range |
foundedYear |
number | Founded year |
headquarters |
object | Headquarters |
headquarters.city |
string | HQ city |
headquarters.country |
string | HQ country |
headquarters.address |
string | HQ street address |
followers |
number | Follower count on LinkedIn |
employeesOnLinkedIn |
number | Number of employees registered on LinkedIn |
specialties |
array | Business specialty tags |
locations |
array | Office locations |
locations.city |
string | City |
locations.country |
string | Country |
locations.address |
string | Street address |
companyUrl |
string | Company URL |
Submit example:
curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/company" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deliveryMode": "async",
"recordLimit": 1000,
"targets": [
{ "companyUrl": "https://www.linkedin.com/company/microsoft/" }
]
}'
Returns
201→{ "code": 0, "data": { "id": 1287346, "status": "queued" } }. Poll thatiduntilsucceeded, then fetch records.
Jobs
Search job listings by keywords, location, experience level, and more. One search condition is one target.
Endpoint: POST /v1/scraper/linkedin/jobs
Target fields (each targets[] element):
| Field | Type | Required | Description |
|---|---|---|---|
keywords |
string | — | Search keywords (e.g. software engineer; passing keywords is recommended, otherwise a trending list is returned) |
location |
string | — | Location (e.g. United States / Berlin) |
resultsLimit |
number | — | Max jobs to return (1–1000, default 100, capped by the max_count billing limit) |
experienceLevel |
string | — | Experience level: INTERNSHIP / ENTRY_LEVEL / ASSOCIATE / MID_SENIOR / DIRECTOR / EXECUTIVE |
jobType |
string | — | Employment type: FULL_TIME / PART_TIME / CONTRACT / TEMPORARY / VOLUNTEER / INTERNSHIP / OTHER |
workplaceType |
string | — | Workplace type: ON_SITE / REMOTE / HYBRID |
postedWithinDays |
number | — | Posted within (days; only 1 / 7 / 30 valid) |
companyNames |
array | — | Filter by an array of company names (the spider resolves company IDs via typeahead first) |
salaryMin |
number | — | Minimum annual salary (USD) |
country |
string | — | Country ISO code (e.g. US / DE) |
Output fields (each record):
| Field | Type | Description |
|---|---|---|
jobUrl |
string | Job detail page URL |
jobId |
string | LinkedIn job ID |
title |
string | Job title |
description |
string | Job description (extracted from HTML) |
applyUrl |
string | Application URL (may be empty) |
postAt |
string | Published time (may be empty) |
company |
object | Company info |
company.name |
string | Company name |
company.link |
string | Company URL on LinkedIn |
company.logo |
string | Company logo URL (may be empty) |
company.industries |
string | Industry of the company |
location |
string | Location |
jobLevel |
string | Seniority level (e.g. Mid-Senior; may be empty) |
jobType |
string | Employment type (e.g. Full-time; may be empty) |
jobFunction |
string | Job function (e.g. Engineering; may be empty) |
applicantsCount |
string | Number of applicants as a numeric string (may be empty) |
requirements |
object | Requirements |
requirements.skills |
string | Skill requirements (may be an empty string) |
requirements.education |
string | Education requirements |
requirements.experience |
string | Experience requirements (may be missing) |
salary |
object | Salary range |
salary.currency |
string | Salary currency |
salary.minAmount |
number | Lower bound of the salary range |
salary.maxAmount |
number | Upper bound of the salary range |
salary.payPeriod |
string | Pay period (e.g. YEAR) |
Submit example:
curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/jobs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deliveryMode": "async",
"recordLimit": 1000,
"targets": [
{
"keywords": "data engineer",
"location": "United States",
"resultsLimit": 100,
"experienceLevel": "MID_SENIOR",
"jobType": "FULL_TIME",
"workplaceType": "REMOTE"
}
]
}'
Returns
201→{ "code": 0, "data": { "id": 1287347, "status": "queued" } }. Poll thatiduntilsucceeded, then page through the job list.
Profile Posts
Extract posts published by a person. At least one of profileUrls / companyUrls must be non-empty.
Endpoint: POST /v1/scraper/linkedin/posts
Target fields (each targets[] element):
| Field | Type | Required | Description |
|---|---|---|---|
profileUrls |
array | either/or | Profile URL list (containing linkedin.com/in/…); at least one of profileUrls / companyUrls non-empty |
companyUrls |
array | either/or | Company URL list (containing linkedin.com/company/…) |
resultsLimit |
number | — | Max posts per URL (1–200, default 25, capped by the max_count billing limit) |
includeComments |
boolean | — | Fetch top-level comments per post (off by default, output has no comments field; roughly doubles cost when on) |
country |
string | — | Export country ISO code (e.g. us); omit for global mix |
Output fields (each record):
| Field | Type | Description |
|---|---|---|
postId |
string | Post URN (urn:li:activity:<id> format) |
permalink |
string | Post permalink |
text |
string | Body text |
createdAt |
string | Posted time (ISO 8601 UTC) |
author |
object | Author info (type always matches the entry side, person or company) |
author.type |
string | Author type (person / company) |
author.name |
string | Author display name |
author.url |
string | Author profile URL |
metrics |
object | Engagement metrics |
metrics.reactionsCount |
number | Total reaction count |
metrics.commentsCount |
number | Comment count |
media |
array | Post media (a reshared original post is classified as article, url points to that original post) |
media.type |
string | Media type (image / video / article / document) |
media.url |
string | Media URL |
media.thumbnailUrl |
string | Video thumbnail URL (present only when type=video) |
media.title |
string | Article/document title (present only when type=article/document) |
comments |
array | Top-level comments (present only when includeComments=true) |
comments.commentId |
string | Comment ID |
comments.text |
string | Comment content |
comments.authorName |
string | Comment author name |
comments.createdAt |
string | Comment time |
Submit example:
curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deliveryMode": "async",
"recordLimit": 1000,
"targets": [
{
"profileUrls": ["https://www.linkedin.com/in/williamhgates/"],
"resultsLimit": 25,
"includeComments": false
}
]
}'
Returns
201→{ "code": 0, "data": { "id": 1287348, "status": "queued" } }. Poll thatiduntilsucceeded, then fetch post records.
Company Posts
Extract posts published by a company page, using the company page URL as the main entry. At least one of companyUrls / profileUrls must be non-empty.
Endpoint: POST /v1/scraper/linkedin/posts-company
Target fields (each targets[] element):
| Field | Type | Required | Description |
|---|---|---|---|
companyUrls |
array | either/or | Company URL list (containing linkedin.com/company/…); at least one of companyUrls / profileUrls non-empty |
profileUrls |
array | either/or | Profile URL list (containing linkedin.com/in/…) |
resultsLimit |
number | — | Max posts per URL (1–200, default 25, capped by the max_count billing limit) |
includeComments |
boolean | — | Fetch top-level comments per post (off by default, output has no comments field; roughly doubles cost when on) |
country |
string | — | Export country ISO code (e.g. us); omit for global mix |
Output fields (each record, same as Profile Posts):
| Field | Type | Description |
|---|---|---|
postId |
string | Post URN (urn:li:activity:<id> format) |
permalink |
string | Post permalink |
text |
string | Body text |
createdAt |
string | Posted time (ISO 8601 UTC) |
author |
object | Author info (type always matches the entry side, person or company) |
author.type |
string | Author type (person / company) |
author.name |
string | Author display name |
author.url |
string | Author profile URL |
metrics |
object | Engagement metrics |
metrics.reactionsCount |
number | Total reaction count |
metrics.commentsCount |
number | Comment count |
media |
array | Post media (a reshared original post is classified as article, url points to that original post) |
media.type |
string | Media type (image / video / article / document) |
media.url |
string | Media URL |
media.thumbnailUrl |
string | Video thumbnail URL (present only when type=video) |
media.title |
string | Article/document title (present only when type=article/document) |
comments |
array | Top-level comments (present only when includeComments=true) |
comments.commentId |
string | Comment ID |
comments.text |
string | Comment content |
comments.authorName |
string | Comment author name |
comments.createdAt |
string | Comment time |
Submit example:
curl -X POST "https://api.antsdata.com/v1/scraper/linkedin/posts-company" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"deliveryMode": "async",
"recordLimit": 1000,
"targets": [
{
"companyUrls": ["https://www.linkedin.com/company/microsoft/"],
"resultsLimit": 25,
"includeComments": false
}
]
}'
Returns
201→{ "code": 0, "data": { "id": 1287349, "status": "queued" } }. Poll thatiduntilsucceeded, then fetch post records.
Fetching Data & Polling
After submitting, every endpoint follows the same run lifecycle to retrieve data:
- Poll
GET /v1/scraper/runs/{id}(back off 1s→2s→5s) untilsucceeded/failed(terminal). - Page through records via
GET /v1/scraper/runs/{id}/records?page=1&pageSize=20;items[]matches the "Output fields" above. - Or download the full result via
GET /v1/scraper/runs/{id}/download?format=csv.
An end-to-end example (Python submit / poll / fetch) is in Quick Start; the envelope, state machine, billing, and error codes are in Auth & Error Handling.
FAQ
Q: Does the call return data directly?
No. Scraping is asynchronous: submit to get a run id, poll until succeeded, then fetch records by id.
Q: Can I scrape multiple profiles / companies in one run?
Yes. For Profile / Company, each URL is one target, and a single run can hold multiple targets; per-target success or failure is in the run object's tasks[] (see Auth & Error Handling).
Q: Which endpoint should I use for profile vs company posts?
Use /posts (main entry profileUrls) for personal profile posts; use /posts-company (main entry companyUrls) for company page posts. Both endpoints share the same output fields.
Q: Do I need to log into the target account?
No. Only public data is extracted; private accounts cannot be scraped.
Next Steps
- Platform guides: TikTok · X · Instagram · Facebook · Google · YouTube · Amazon
- Synchronous search: Google SERP
- Auth & Error Handling — Unified envelope, run state machine, billing & error codes
