The LinkedIn API,
built for builders.
The complete LinkedIn record, fetched live. Other APIs resell a database crawled months ago with half the fields missing — Edges unmasks every data point at the moment you ask. Full work history, exact employee counts, funding rounds, Sales Navigator IDs, this morning’s posts. Two entities: People and Companies. One API key.
Edges is not related to LinkedIn and is not an official LinkedIn product.
curl -X POST \
https://api.edges.run/v1/actions/linkedin-extract-people/run/live \
-H "X-API-Key: $EDGES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"linkedin_profile_url":"linkedin.com/in/jane-doe"}}'read at request time
fields per person · 41 per company
people · 54M companies · any URL
read and write, same key
“We used to keep a fleet of LinkedIn accounts alive just to read public data — cookies expiring, profiles getting flagged, someone on-call for it every week. With Edges we pull profiles without connecting a single account, and when we do need to send an invite or a message, it’s the same API key. That deleted an entire class of problems for us.”
// used by
// What teams build
Five things people ship on Edges.
Every one is the same API key and the same runner endpoint. Pick the surface you need first — the rest is already unlocked.
Profile & company data
Complete Person and Company records, read at request time — CRM, warehouse and agent-ready payloads.
enrich · resolve · refresh→Search & lists
People search, company search and Sales Navigator filters — paginated, on our seats or your own licence.
search · lists · saved views→Messaging & outreach
Messages, InMail and connection requests through one integration surface, metered per identity.
send · reply · thread→Signals & timing
Schedule extracts, diff live reads, route on change — timing you build with Actions, not a packaged feed.
schedule · diff · callback→LinkedIn scraper
The alternative to running your own. No proxies, no cookie rotation, no on-call for a selector change.
replace · retire · sleep→All use cases
The full pillar map — which actions each motion uses, and what a working integration looks like end to end.
browse all→// 70+ endpoints
Read it, then act on it. Same access, same key.
The same access that unmasks the data lets you write with it — invites, messages, follows. Every action is a documented POST against api.edges.run/v1.
- Enrich profile1POST/v1/actions/linkedin-extract-people/run/liveProfile (38 fields)
- Batch enrich1×nPOST/v1/actions/linkedin-extract-people/run/liveProfile[ ] · up to 40 req/s
- Search people1×nPOST/v1/actions/linkedin-search-people/run/liveSearchResult<Profile>
- Enrich company1POST/v1/actions/linkedin-extract-company/run/liveCompany
- Post commenters1 / pagePOST/v1/actions/linkedin-extract-post-commenters/run/liveProfile[ ] who commented
- Send message0engagementPOST/v1/actions/linkedin-message-profile/run/liveMessageReceipt
// Two ways in
Use our access, or use yours.
Both modes hit the same actions, the same schema, the same key. The only difference is whose access the call runs on.
We bring the access.
No cookies, no LinkedIn account, no warmup, no seats to babysit. You send a URL, you get the complete record back. Most teams never build anything else.
// nothing to configure
const { data: profile } = await edges.linkedin.extractPeople({
input: { linkedin_profile_url: url }
})
// Sales Navigator search — our seats, not yours
const { data: leads } = await edges.salesnavigator.searchPeople({
input: { title: "VP Product", headcount: "51-200" }
})You bring the account.
Attach your own LinkedIn or Sales Navigator seats when the call has to come from a specific identity — messages, invites, your saved searches, your lead lists.
// 1 · register the identity once
await edges.core.createIdentity({
input: {
email: "alex@yourco.com",
password: "••••••••"
}
})
// 2 · same call, your identity
const { data } = await edges.linkedin.messageProfile({
input: { linkedin_profile_url: url, text },
identity: "alex@yourco.com"
})Managed Sales Navigator access is rare — almost every other LinkedIn API makes you supply your own seat.
// Entities
Two entities. Everything else derives from them.
People and Companies are the only records you have to model. Signals, posts, searches and messages are all things that happen to one of the two.
Identity, full role history, education, skills and network position — read from the source at request time, not a cache.
Firmographics plus what cached datasets never carry — exact employee counts, funding rounds, specialties, affiliated pages.
Signals→
A change between two reads — a new job_title, a jump in number_employees.
Search→
A query that returns People or Companies — including Sales Navigator filters.
Posts→
Activity published by a Person or Company, plus everyone who reacted or commented.
Messaging→
An action taken toward a Person from one of your connected identities.
// The difference
The same profile, from a database and from the source.
Resold datasets return what was true when they crawled it, minus every field their crawler couldn't see. Ours goes and gets it.
No stock of data to go stale. Highest freshness because it’s read now; highest coverage because nothing is masked.
See it on a profile you know.
100 free credits, no card. Paste any LinkedIn URL and compare the response to whatever you’re using today.
// Infrastructure
Getting this data is the hard part. That's our problem.
Access, pacing, anti-bot posture, breakage response — the work that makes unmasked live data possible, already done.
Managed access
Access health, rotation and pacing are handled on our side. You never touch a cookie or a credential.
Idempotent retries
Pass an idempotency key, retry safely on 429 / 5xx. SDK does exponential backoff with jitter.
Cursors + pagination
Stable cursors on list Actions; async runs can auto-paginate and deliver batches to your callback.
Action callbacks
Async and schedule modes POST results to your URL. Missed deliveries replay from callback history.
p50 1.2s · p99 2.4s
A live read against the source, every time. Even a cold profile lands inside 3 seconds.
SOC 2 Type II
Audited annually. 99%+ uptime. Region-pinned residency on enterprise plans.
// Developer ergonomics
TypeScript SDK on top. Plain REST underneath.
The TS SDK is the fastest path on Node. Every other runtime talks to the same REST surface with whatever HTTP client you already use.
Typed, retried, paginated, traced. Drop it into any Node service.
// npm i @edgesrun/sdk
import { Edges } from "@edgesrun/sdk"
const edges = new Edges({ apiKey })
const { data } = await edges.linkedin.extractPeople({ input })No dependency. Copy-paste from any docs page, run it in your shell.
# standard REST, JSON, X-API-Key auth
curl -X POST https://api.edges.run/v1/actions/linkedin-extract-people/run/live \
-H "X-API-Key: $EDGES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"linkedin_profile_url":"linkedin.com/in/jane-doe"}}'No SDK to install, no version to keep up with. It's plain HTTP, so it already works in whatever you write. Ask us for the OpenAPI spec if you want a typed client.
# plain HTTP — no client library,
# no version to keep up with
POST /v1/actions/{action}/run/live// Beyond requests
Async jobs, cron schedules, full workflows.
Live REST is one mode. The same API runs jobs asynchronously, on a schedule, or as multi-step workflows that trigger, enrich and engage on their own — one key, one schema, four execution modes.
Live REST
Request in, response out. The mode you start with.
// blocking call
const { data } = await edges.linkedin
.extractPeople({
input: { linkedin_profile_url: url }
})Async jobs
Run any action async — poll outputs or receive callbacks.
// fire-and-forget
const { data: job } = await edges.linkedin
.extractPeople({
input,
mode: "async",
callback: { url: "https://…/done" }
})
// → run_uid · poll /runs/{uid}/outputsCron schedules
Schedule mode is set on the action run itself.
// every Mon 09:00 UTC
await edges.linkedin.extractCompany({
input: { company_url },
schedule: { cron: "0 9 * * 1" }
})Workflows
Compose trigger → enrich → filter → engage.
// trigger → … → engage
const { data } = await edges
.linkedin.extractPostCommenters(input)
for (const c of data.commenters) {
await edges.linkedin.connectProfile(…)
}Get the full record in an afternoon.
100 free credits. No card, no cookies, no LinkedIn account required.