100 free credits. No credit card required.Start building
Logo
Back to blog

LinkedIn Post History API: Full Archive, 100/Page

·15 min read

LinkedIn post history API: 100/page at 5 credits each. Two no-cache calls matched published_at to the millisecond; limit=100 returned 97 posts and a cursor.

LinkedIn Post History API: Full Archive, 100/Page

GET /v1/linkedin/profile/posts/archive is the LinkedIn post history API that walks a public member's posts 100 a page, with a cursor until nothing older is left. That LinkedIn profile posts archive returns member-authored rows with exact timestamps.

On 2026-09-08 against williamhgates, limit=100 returned 97 posts, 485 credits, has_more=true, and a non-null sc. cursor. Two no-cache archive calls 74 seconds apart matched published_at on all 5 overlapping ids to the millisecond (2026-09-05T19:09:50.123Z).

Microsoft's Posts API is partner create/retrieve of your posts. Self-serve is Sign In plus Share on LinkedIn — w_member_social is write, not a public archive read (getting access, Posts API). LinkedIn Help will download your data and nobody else's. Longer official-API write-up: LinkedIn API in 2026.

Start at cheap GET /v1/linkedin/profile/posts (up to 100 for a flat 5 credits) — the cheap 100-post LinkedIn profile feed. Archive is the lane you pay per delivered post when you need the end of the profile, exact times, or a guaranteed member-authored row.

How do you retrieve a LinkedIn member's complete post history?

Follow pagination.next_cursor on limit=100 pages until has_more is false — that is the complete public history. A LinkedIn post history API call at limit=5 is the cheap way to see the envelope before you spend 485 credits on a continuable page. Same public member, same day: https://www.linkedin.com/in/williamhgates/.

bash
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" -H "Cache-Control: no-cache" \
  "https://www.socialcrawl.dev/v1/linkedin/profile/posts/archive?url=https://www.linkedin.com/in/williamhgates/&limit=5"
CallItemscredits_usedhas_morenext_cursorpage_sizeNewest published_at
archive limit=5525 (5 × 5)falsenull52026-09-05T19:09:50.123Z

First id: 7502080571335155713 (activity-shaped). Author williamhgates / "Bill Gates". First-item engagement: likes 1741, comments 437, shares 86. views and saves were null. ext.published_at_epoch is 1788635390123. ext.post_type is regular. Two of the five member posts, trimmed:

json
{
  "success": true,
  "platform": "linkedin",
  "endpoint": "/v1/linkedin/profile/posts/archive",
  "credits_used": 25,
  "cached": false,
  "pagination": { "next_cursor": null, "has_more": false, "page_size": 5 },
  "data": {
    "dropped": 0,
    "items": [
      {
        "post": {
          "id": "7502080571335155713",
          "published_at": "2026-09-05T19:09:50.123Z",
          "author": { "username": "williamhgates", "display_name": "Bill Gates" },
          "engagement": { "views": null, "likes": 1741, "comments": 437, "shares": 86, "saves": null },
          "ext": { "published_at_epoch": 1788635390123, "post_type": "regular" }
        }
      },
      {
        "post": {
          "id": "7501738402128715777",
          "published_at": "2026-09-04T20:30:10.627Z",
          "author": { "username": "williamhgates", "display_name": "Bill Gates" },
          "engagement": { "views": null, "likes": 6870, "comments": 668, "shares": 595, "saves": null },
          "ext": { "published_at_epoch": 1788553810627, "post_type": "regular" }
        }
      }
    ]
  }
}

request_id: req-pq0QiJ0yYh8J765b. credits_used=25 is 5 credits per post delivered, not per limit asked. has_more=false / next_cursor=null at limit=5 is expected — only a limit=100 request is continuable. The objects sit in the unified schema (dev.socialcrawl.post.v1); the SocialCrawl API does not hand you a vendor-shaped blob.

Lane choice: cheap /v1/linkedin/profile/posts first (flat 5 credits, at most 100, always terminal) → /v1/linkedin/search/posts?from_member= for a deeper index → archive only when you need the end of the profile, exact times, or a member-authored row. Do not start a full walk here.

Same member, cheap lane, one contrast row from this harvest (limit=20): 20 posts, flat 5 credits, has_more=false, date-only published_at (2026-09-06T00:00:00.000Z). That is why archive exists.

A receding accordion of cream document cards with one clay-amber card at the front, the depth a LinkedIn profile posts archive walk covers at 100 per page.

How far back does the LinkedIn profile posts archive go?

Ask for 100. This public-member LinkedIn archive API has no fixed depth. A continuable page is limit=100; follow pagination.next_cursor as pagination_token until has_more is false. There is no page= param on this lane.

bash
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" -H "Cache-Control: no-cache" \
  "https://www.socialcrawl.dev/v1/linkedin/profile/posts/archive?url=https://www.linkedin.com/in/williamhgates/&limit=100"
This harvest (2026-09-08)2026-09-07 measured walk (not re-run)
What we didone limit=100 pagecomplete walk
Posts97 (asked 100)851 posts / 10 pages
Credits485 (5 × 97)(not re-measured)
has_moretrueuntil a page with no cursor
Cursornon-null sc. (257 chars)followed to the end
Oldest on this page2026-04-27T18:58:34.713ZMarch 2022 (that member)
Wall clock~5.8s~49s for 10 pages; ~5s/page

First id on the page: 7502080571335155713 at 2026-09-05T19:09:50.123Z. Last id: 7454604928066486273 at 2026-04-27T18:58:34.713Z. post_type: 80 regular, 17 quote. All 97 author williamhgates. Pagination object plus first two items and the last one (request_id: req-2etbGBAiw3xDCQk9):

json
{
  "success": true,
  "endpoint": "/v1/linkedin/profile/posts/archive",
  "credits_used": 485,
  "cached": false,
  "pagination": {
    "next_cursor": "sc.eyJ2IjoyLCJjIjoic2MyLmV5SnpJam9pZGlJc0ltTWlPaUprV0VwMVQyMTRjRTl0Um1wa1Iyd3lZVmhTTlU5cVl6Qk9WRkV5VFVSUk5VMXFaM2RPYWxrd1QwUlplVTU2VFhSTlZHTXpUbnBOZUU1cVRYaE9SRmsxVGxFOVBTSjkiLCJlIjoibGlua2VkaW4vcHJvZmlsZS9wb3N0cy9hcmNoaXZlIiwicCI6InBhZ2luYXRpb25fdG9rZW4ifQ",
    "has_more": true,
    "page_size": 97
  },
  "data": {
    "dropped": 0,
    "items": [
      {
        "post": {
          "id": "7502080571335155713",
          "published_at": "2026-09-05T19:09:50.123Z",
          "author": { "username": "williamhgates" },
          "engagement": { "likes": 1741, "comments": 437, "shares": 86 },
          "ext": { "published_at_epoch": 1788635390123, "post_type": "regular" }
        }
      },
      {
        "post": {
          "id": "7501738402128715777",
          "published_at": "2026-09-04T20:30:10.627Z",
          "author": { "username": "williamhgates" },
          "engagement": { "likes": 6870, "comments": 668, "shares": 595 },
          "ext": { "published_at_epoch": 1788553810627, "post_type": "regular" }
        }
      },
      {
        "post": {
          "id": "7454604928066486273",
          "published_at": "2026-04-27T18:58:34.713Z",
          "author": { "username": "williamhgates" },
          "engagement": { "likes": 1421, "comments": 130, "shares": 54 },
          "ext": { "published_at_epoch": 1777316314713, "post_type": "quote" }
        }
      }
    ]
  }
}

94 of 97 items omitted. Page 2 was not followed this run, so there is no page-2 envelope to print. The 851 / 10 pages / ~49s figure, and a more prolific member that passed 1,800 posts back to 2017, are the 2026-09-07 measured walk. This harvest proved page 1 of a high-volume public profile. It did not prove 851.

The non-obvious contract: a limit=100 page can return fewer than 100 rows and still hand you a cursor (97 items, has_more=true). Stop on pagination.has_more, not on items.length === 100. A naive loop that treats a short page as the end of the archive would have dropped everything older than 2026-04-27T18:58:34.713Z on this member and called the job done.

A limit below 100 returns that many of the newest posts and no cursor (limit=5 this harvest: has_more=false, next_cursor=null). The contract will not pretend a partial page is continuable — that would silently skip the rest of the archive. To walk, pass the previous pagination.next_cursor as pagination_token on the next limit=100 request. A page with no cursor is the end of that member's public archive. Private / logged-in-only activity is out of scope.

Two matching analog clocks with clay-amber hands at the same instant, the exact publish time a LinkedIn post history archive keeps across recrawls.

Why do archive timestamps stay exact across calls?

Because the archive stores the instant, not a relative label. Two no-cache archive calls at limit=5, both X-Cache: MISS, 74 seconds apart: 5/5 ids matched to the millisecond.

Buffer's 2026 analysis of 4.8 million LinkedIn posts puts the problem in one line: LinkedIn Analytics will not show detailed timings after the fact; the best the timestamp will tell you is "3h" or "2d" (Buffer, 2026). A time-of-day study needs a clock that does not move when you recrawl.

idcall 3call 4match
75020805713351557132026-09-05T19:09:50.123Z2026-09-05T19:09:50.123Zyes
75017384021287157772026-09-04T20:30:10.627Z2026-09-04T20:30:10.627Zyes
75014667552618209282026-09-04T02:30:44.967Z2026-09-04T02:30:44.967Zyes
75014561937946337292026-09-04T01:48:46.917Z2026-09-04T01:48:46.917Zyes
75014551803962081282026-09-04T01:44:45.304Z2026-09-04T01:44:45.304Zyes

Same toilets post, two clocks (cheap lane vs archive, this harvest):

Laneidpublished_atlikes / comments / shares
/profile/posts75020805701815869442026-09-06T00:00:00.000Z (precision=day)1741 / 437 / 86
/profile/posts/archive75020805713351557132026-09-05T19:09:50.123Z (epoch=1788635390123)1741 / 437 / 86

The cheap-lane URL for that row is …/feed/update/urn:li:activity:7502080571335155713 — the archive id sits inside it. IDs are not the same field across lanes (ugcPost-shaped vs activity-shaped). Same post, two ids.

The calendar day disagrees (6 Sep midnight vs 5 Sep 19:09:50 UTC) because the cheap lane recomputes from a relative label (ext.published_at_precision was day on 7/20 cheap rows and week on 13/20). Archive: 97/97 millisecond instants, 0 midnight. Midnight is a rounding artifact, not a lifestyle. Search-lane drift was not re-measured on 2026-09-08; the sibling harvest on 2026-09-06 saw created_at move from 22:50:19 to 22:52:27 on the same row (LinkedIn post API).

Does the LinkedIn archive API return share counts?

Yes. If you want a LinkedIn share count API field you can chart, it is engagement.shares, sitting next to likes and comments.

This harvest, 2026-09-08:

  • Archive limit=100: 97/97 numeric engagement.shares.
  • Archive limit=5: 5/5 numeric shares.
  • Cheap /profile/posts limit=20: 20/20 numeric shares.

A 2026-09-07 product note called archive the only LinkedIn lane with share counts. This harvest contradicts that for /profile/posts. Live harvest wins. What archive uniquely showed here is exact timestamps, a working cursor, and depth past the cheap window.

views and saves were null on every archive row. Official r_member_postAnalytics (impressions plus shares on your posts, 3-legged OAuth) is not a public-member read (Increasing Access). shares: 86 on the toilets post, shares: 595 on id 7501738402128715777.

How many credits does a LinkedIn archive walk cost?

Five credits per post delivered. Not per limit asked. Opposite of the cheap lane.

CallHTTPPostscredits_usedNotes
archive limit=52005255 × delivered
archive limit=100200974855 × 97, not 5 × 100
archive limit=1014000names the limit
fake profile20000empty list, not 404
cheap /profile/posts limit=20200205 (flat)sibling lane

limit=101 (req-5f79V4LhCyjNSZKX) is a free named error:

json
{
  "success": false,
  "error": {
    "type": "INVALID_REQUEST",
    "message": "Invalid value for 'limit': '101'. Must be an integer >= 1 and <= 100.",
    "status": 400,
    "doc_url": "https://www.socialcrawl.dev/docs/errors#invalid-request"
  },
  "credits_used": 0,
  "request_id": "req-5f79V4LhCyjNSZKX"
}

A missing profile is not a 404. URL used: https://www.linkedin.com/in/this-profile-does-not-exist-zzz999/ (req-UoV4dWgSvJ9sOGDX):

json
{
  "success": true,
  "platform": "linkedin",
  "endpoint": "/v1/linkedin/profile/posts/archive",
  "data": { "items": [], "total": 0, "dropped": 0 },
  "credits_used": 0,
  "cached": false,
  "pagination": { "next_cursor": null, "has_more": false, "page_size": 0 },
  "request_id": "req-UoV4dWgSvJ9sOGDX"
}

HTTP 200, empty list, 0 credits.

Reshares of other people's posts are dropped and not billed. This harvest asked 100, received 97, billed 485 = 5 × 97. data.dropped was 0 (that counter is schema-repair loss, not the reshare filter). The 3-post shortfall is consistent with the filter. Those omitted rows were not in the payload to inspect, so this is inferred, not a counted reshare tally.

Cache caveat: this harvest sent Cache-Control: no-cache and every paid response was cached: false. A normal client without that header can be served a 10-minute cache hit at 0 credits. The cheap lane bills the call, not the row count. Archive bills the opposite: you pay for what came back.

How do you start using this?

  1. Get a key. New accounts get free credits, no card. Keep it out of git. Export it as $SOCIALCRAWL_API_KEY.

  2. Start cheap. GET /v1/linkedin/profile/posts?url=…&limit=20 (flat 5 credits) — see the cheap 100-post lane. limit=100 is the same 5 credits. That lane is always one terminal page (has_more=false); if you get fewer rows than you asked, that is the whole cheap window. This member filled limit=20, and archive page 1 already had 97.

  3. If you need the rest of the profile, exact times, or a cursor past that window, switch to archive at limit=100. Follow pagination.next_cursor as pagination_token until has_more is false. Expect ~5 credits × posts delivered (this harvest: 97 posts → 485 credits on page 1). One API key, same envelope.

  4. Open the Explorer to see the envelope before writing a single line of the loop. Contract: LinkedIn docs. Platform family: /platforms/linkedin. Public pages; the User Agreement still forbids scraping; this is an API read, not a scrape tutorial — see how to scrape LinkedIn.

Minimal first archive call (expect 5 posts / 25 credits):

bash
curl -s -H "x-api-key: $SOCIALCRAWL_API_KEY" -H "Cache-Control: no-cache" \
  "https://www.socialcrawl.dev/v1/linkedin/profile/posts/archive?url=https://www.linkedin.com/in/williamhgates/&limit=5"

The contract is on the LinkedIn docs; the envelope is easier to read in the Explorer than in a log. If 100 recent posts is enough, use the cheap lane and keep the 485 credits.

Frequently asked questions

Does the official LinkedIn API return a public member's full post history?

No. Self-serve is Sign In with LinkedIn plus Share on LinkedIn, and w_member_social is write (getting access, Share on LinkedIn). Posts API retrieve is partner-scoped: r_organization_social for a page you admin, r_member_social restricted (Posts API). LinkedIn Help will only give your data. The official-API overview is LinkedIn API in 2026. This endpoint is the public-data archive read.

What is the difference between /v1/linkedin/profile/posts and /archive?

Cheap lane: one terminal page, limit 1–100, flat 5 credits, day/week-precision timestamps. Archive: cursor at limit=100, 5 credits per post delivered, millisecond published_at that does not drift (5/5 ids matched this harvest). Share counts were numeric on both lanes this harvest, so do not call archive the only shares lane.

How many LinkedIn posts does the archive return per page?

You may ask for 1–100. A continuable page is limit=100. This harvest: limit=5 → 5 posts, no cursor; limit=10097 posts, has_more=true. Stop on has_more, not length===100. 851 / 10 pages is the 2026-09-07 measured walk.

Can you get LinkedIn share counts from the profile posts archive?

Yes — 97/97 numeric engagement.shares on the limit=100 page. Also present on 20/20 cheap-lane rows this harvest, so do not call archive the only shares lane. views / saves were null.

Are reshares of other people's posts included in the archive?

Documented as dropped and not billed. This harvest asked 100, received 97, billed 485. data.dropped was 0. Infer the 3-post shortfall; those omitted rows were not in the payload to inspect.

What happens if the LinkedIn profile is empty, missing, or you set limit above 100?

Fake profile: HTTP 200, empty list, 0 credits (not 404). limit=101: HTTP 400 INVALID_REQUEST, 0 credits, message names the 1–100 bound.

Is walking the archive the cheapest way to get 100 recent posts?

No. /profile/posts is flat 5 credits for up to 100. Archive page 1 this harvest was 485 credits for 97 posts. Use archive when you need the end of the profile, exact times, or a cursor.

Topics
#linkedin-profile-posts-archive#linkedin-post-history-api#linkedin-archive-api#linkedin-profile-posts-api#linkedin-member-posts-archive#linkedin-posts-pagination#linkedin-share-count-api#linkedin-activity-archive

Related posts

🤖 AI agent or LLM? Read this page as markdown