LinkedIn Member Data Portability API

An official LinkedIn API that gives EU members their own data on demand, thanks to the Digital Markets Act.

03 Oct 2026

For once, a piece of European regulation that I can only applaud.

LinkedIn has no public API for members. The Sales Navigator API is closed to new partners, and the other APIs cover ads, company pages and "Sign in with LinkedIn". For years, the only official way to get your own data out was the "Download your data" zip: request it, wait up to 3 days for the email, unzip, repeat next month.

The EU's Digital Markets Act (DMA) changed that. It forces the largest platforms, the "gatekeepers", to let users take their data out continuously and in real time, not only as a one-off download. LinkedIn complies with the Member Data Portability API: an official, free, read-only API that returns your own LinkedIn data as JSON, whenever you ask.

It works only for members located in the EU/EEA or Switzerland, based on the location on your LinkedIn profile. Everyone else gets an error. For once, being in Europe is the advantage.

Why it exists: the Digital Markets Act

  • The European Commission designated Microsoft as a gatekeeper on 6th September 2023, with LinkedIn as one of its core platform services.
  • Gatekeepers had 6 months to comply, so the obligations apply since March 2024.
  • Article 6(9) of the DMA requires gatekeepers to give end users effective portability of their data, free of charge, including continuous and real-time access. A download button once a month doesn't meet that bar, hence an API.
  • LinkedIn runs 2 variants: one for members (you fetch your own data with your own app) and one for third parties (an app fetches a member's data with that member's consent).

I wrote about the DMA when it was announced (!random/eu-dma). 4 years later, this API is the first tangible result I use every day.

What the API gives you

2 endpoints carry the data:

Endpoint What it returns
Member Snapshot API Your full history, per data domain, as of the moment you call it
Member Changelog API Every action since you consented (messages, comments, reactions...), kept 28 days

The snapshot covers about 60 domains. The ones that matter most:

Domain Content
INBOX Every message sent and received, full history
CONNECTIONS Name, position, company and date of each 1st-degree connection
INVITATIONS Invitations sent and received, with the note (last 6 months)
ALL_COMMENTS, ALL_LIKES Your comments and reactions
MEMBER_SHARE_INFO Your posts and reposts
PREMIUM_NOTES Your private notes on connections
SEARCHES Your recent searches
PROFILE, POSITIONS, SKILLS Your own profile, section by section

Plus learning history, endorsements, recommendations, groups, follows, saved jobs, ad targeting and more.

What it does not give you:

  • Other people's profiles. CONNECTIONS gives a name, a title and a company, nothing more.
  • Any write access. You can't send a message or an invitation.

For business people

What it changes: your LinkedIn activity becomes data you own, live, not a monthly zip.

  • Your inbox in your own tools. Every DM, back to the first one (mine go back to 2007), searchable next to your CRM and email.
  • No more lost replies. The changelog shows a reply within hours. Combined with a list of who accepted your invitation, you see who wrote and never got an answer.
  • Follow-up you can measure. Who accepted, who you messaged, who replied, per campaign or event.
  • No account risk. Scraping tools and browser extensions break LinkedIn's User Agreement and get accounts restricted. This is LinkedIn's own API, used with your own consent.

Cost: free. Effort: 10 minutes of setup, then 1 click a year to renew the token.

The main limitation: it is your data only. Prospecting data on people you don't know still comes from enrichment providers.

For technical people

Setup

  1. Create an app on LinkedIn Developers. Use the company page "Member Data Portability (Member) Default Company". Creating your own page blocks the access request.
  2. On the app's Products tab, request Member Data Portability API (Member). Access is granted immediately after you accept the terms.
  3. Get a token with the scope r_dma_portability_self_serve: either with the OAuth Token Tools in the developer portal, or with a standard 3-legged OAuth flow and a redirect URL such as http://localhost:8799/callback.
  4. Call POST /rest/memberAuthorizations with {} to start the changelog archiving (the consent usually does it already).

Calls

Every request needs the header Linkedin-Version: 202312. It's the only version these endpoints accept; any other returns 426 NONEXISTENT_VERSION.

# full history of one domain, page by page (start=0, 1, 2...)
curl -s "https://api.linkedin.com/rest/memberSnapshotData?q=criteria&domain=INBOX&start=0" \
  -H "Authorization: Bearer $TOKEN" -H "Linkedin-Version: 202312"

# new activity since a timestamp (epoch ms), max 50 per call, 28 days back at most
curl -s "https://api.linkedin.com/rest/memberChangeLogs?q=memberAndApplication&startTime=1790929912000&count=50" \
  -H "Authorization: Bearer $TOKEN" -H "Linkedin-Version: 202312"

# is archiving on, and since when
curl -s "https://api.linkedin.com/rest/memberAuthorizations?q=memberAndApplication" \
  -H "Authorization: Bearer $TOKEN" -H "Linkedin-Version: 202312"

Learnings from my setup (October 2026)

  • The snapshot is built after you consent, not before. Every domain answered 404 No data found at first. PROFILE and CONNECTIONS were ready after 21 minutes, INBOX after about 1 hour. Comments, likes and posts took 1 to 2 days.
  • The fields match the CSV export. CONNECTIONS returns "First Name", "Connected On", "URL"; INBOX returns "CONVERSATION ID", "FROM", "CONTENT". A parser written for the "Download your data" zip works on the API unchanged, and rows dedupe across both sources.
  • Paging ends with an error. Loop on start until the API answers "No data found"; the total field is not reliable.
  • The changelog is thin. A message event carries the thread ID and person URNs, not names. Resolve the name from the conversation you already hold.
  • startTime is inclusive. The last event comes back on every call; dedupe on the event id.
  • Some listed domains don't work. EVENTS is in the documentation but returns 400 not supported. ARTICLES comes back as broken HTML lines.
  • The token lasted 1 year (expires_in in the token response), although the app page shows 2 months. There is no refresh token: plan a yearly re-consent.
  • The conversation ID opens the thread. https://www.linkedin.com/messaging/thread/{CONVERSATION ID}/ goes straight to the conversation in your inbox.

How I use it

A small Python script pulls the changelog every 4 hours and a full snapshot once a week, into the SQLite database that already holds my LinkedIn export. A dashboard on top lists everyone who accepted my invitation and never got a message, with a draft ready per person, and ticks each row when the API sees my message or their reply. See also Linkedin for other LinkedIn resources.


Step by step: get access as an EU member

04 Oct 2026 added: the full walkthrough, from zero to the first API call. About 15 minutes of clicks, then a wait while LinkedIn builds your data. The Setup section above is the short version.

Before you start

Check Why
Profile location Must be in the EU/EEA or Switzerland. LinkedIn reads the location on your profile, not your IP
A normal member account The API returns the data of the account that gives consent. No Premium needed
A logo image Creating a developer app asks for one. Any square image works

If your profile location is outside Europe, the consent screen fails with an error. Fix the location first.

1. Create a developer app

  1. Open LinkedIn Developers and click Create app.
  2. App name: anything. Mine is "NicAI".
  3. LinkedIn Page: search for and select "Member Data Portability (Member) Default Company" (its LinkedIn page; you can also paste this URL in the field). This is the step everyone gets wrong. Don't create a page for your app, and don't pick your employer's page: only the default page unlocks the product in step 2, and an app's page can't be changed later.
  4. Upload the logo, accept the legal agreement, click Create app.

2. Request the product

  1. In the app, open the Products tab.
  2. Find Member Data Portability API (Member) and click Request access.
  3. Accept the terms. Access is granted on the spot, no review.
  4. Check: the product's Endpoints view now lists memberAuthorizations, memberChangeLogs and memberSnapshotData, all with the scope r_dma_portability_self_serve.

If the product isn't in the list, the app uses the wrong company page. Create a new app with the default page.

3. Get an access token

2 ways. The first needs no code.

Option A: the token tool (no code)

  1. In the developer portal, open Docs and tools > OAuth Token Tools and click Create token.
  2. Select your app and tick the scope r_dma_portability_self_serve.
  3. Click Request access token, log in, read the consent screen and click Allow.
  4. Copy the token. Store it in a .env file or a password manager, never in a script you share.

Option B: your own OAuth flow (for a script that renews itself)

  1. On the app's Auth tab, note the Client ID and the Primary Client Secret.
  2. Under Authorized redirect URLs, add a local address such as http://localhost:8799/callback. Pick a port no other local app uses.
  3. Open this URL in your browser (replace the client ID), log in and click Allow:
https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A8799%2Fcallback&state=any-random-string&scope=r_dma_portability_self_serve
  1. LinkedIn redirects to your callback with ?code=.... Swap the code for a token within a few minutes:
curl -s -X POST https://www.linkedin.com/oauth/v2/accessToken \
  -d grant_type=authorization_code -d code=THE_CODE \
  -d redirect_uri=http://localhost:8799/callback \
  -d client_id=YOUR_CLIENT_ID -d client_secret=YOUR_CLIENT_SECRET

The answer holds access_token and expires_in (seconds). Mine came back with 1 year. There is no refresh token: when it expires, you repeat the consent.

4. Switch on the activity archive

The changelog only records activity from the moment archiving starts. The consent usually starts it; this call makes sure, and is harmless if it is already on:

curl -s -X POST https://api.linkedin.com/rest/memberAuthorizations \
  -H "Authorization: Bearer $TOKEN" -H "Linkedin-Version: 202312" \
  -H "Content-Type: application/json" -d '{}'

Then GET /rest/memberAuthorizations?q=memberAndApplication returns regulatedAt: the timestamp archiving started.

5. Make the first call, then wait

curl -s "https://api.linkedin.com/rest/memberSnapshotData?q=criteria&domain=PROFILE" \
  -H "Authorization: Bearer $TOKEN" -H "Linkedin-Version: 202312"

Expect 404 No data found at first: LinkedIn builds the snapshot after you consent. My timings:

Domain Ready after
PROFILE, CONNECTIONS, INVITATIONS 21 minutes
INBOX (all messages) about 1 hour
ALL_COMMENTS, ALL_LIKES, MEMBER_SHARE_INFO, SEARCHES, MEMBER_FOLLOWING 1 to 2 days
PREMIUM_NOTES, CONTACTS, INSTANT_REPOSTS not ready after 2 days

6. Keep it running

  • Changelog: poll memberChangeLogs at least every few days; it keeps 28 days only. I poll every 4 hours.
  • Snapshot: a full pull once a week fills any gap and picks up domains that were not ready earlier.
  • Token: put the expiry date in your calendar, a week early.
  • Dedupe what you fetch. The snapshot API repeats rows across pages (my INBOX came back as 25,276 rows for 12,736 messages). Key each row on its content before you store it.
  • The export and the API disagree on comment text. The CSV export truncates and escapes comments; the API returns the full text. Match a comment on its link and timestamp, not on its text, or you store it twice.

Troubleshooting

Symptom Cause and fix
Product missing on the Products tab Wrong LinkedIn Page on the app. Create a new app with the default company page
Error on the consent screen Profile location outside the EU/EEA/Switzerland
426 NONEXISTENT_VERSION Missing or wrong header: send Linkedin-Version: 202312
404 No data found Snapshot not built yet, or you paged past the last page
400 The following domain is not supported Some documented domains don't work, eg EVENTS. Skip them
401 Token expired or revoked: repeat step 3

Further Reading

NicAI
Written by NicAI, Nic's AI assistant, for his personal knowledge base. Researched and drafted by the model, not hand-written by Nic. Verify anything you plan to act on.