curl --request GET \
--url https://api.fetchin.io/api/v1/profile/articles \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.fetchin.io/api/v1/profile/articles"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.fetchin.io/api/v1/profile/articles', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fetchin.io/api/v1/profile/articles",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.fetchin.io/api/v1/profile/articles"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.fetchin.io/api/v1/profile/articles")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fetchin.io/api/v1/profile/articles")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"articles": [
{
"articleUrn": "urn:li:linkedInArticle:7280956270201704448",
"articleId": "7280956270201704448",
"title": "What I learned shipping software for thirty years",
"url": "https://www.linkedin.com/pulse/what-i-learned-shipping-software-thirty-years-williamhgates",
"description": "Every release teaches you something the last one could not. Here are the lessons that kept coming back, and the ones I had to...",
"publishedAt": "2026-07-14T08:12:03.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": 9,
"subtitle": "by Ada Lovelace • 9 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7264411902883401728",
"articleId": "7264411902883401728",
"title": "The energy transition is an engineering problem",
"url": "https://www.linkedin.com/pulse/energy-transition-engineering-problem-williamhgates",
"description": "We talk about climate in terms of pledges, but the hard part is industrial: steel, cement, fertiliser. None of them have a...",
"publishedAt": "2026-05-02T16:40:55.000Z",
"coverImageUrl": null,
"readTimeMinutes": 6,
"subtitle": "by Ada Lovelace • 6 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7231887450119684096",
"articleId": "7231887450119684096",
"title": "Notes from a year of reading",
"url": "https://www.linkedin.com/pulse/notes-from-year-reading-williamhgates",
"description": "Five books that changed how I think about measurement, and one that I gave up on halfway through without any regret at...",
"publishedAt": "2026-01-19T11:05:21.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": null,
"subtitle": "by Ada Lovelace"
}
],
"hasMore": true,
"nextStart": 10
}
{
"error": "Missing profileUrlOrUrn parameter",
"code": "MISSING_PARAMETER"
}
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
{
"error": "<human-readable reason>",
"code": "PROFILE_NOT_FOUND"
}
{
"error": "Quota exceeded. Upgrade your plan or wait for renewal.",
"code": "QUOTA_EXHAUSTED",
"details": {
"creditsRemaining": 0,
"subscriptionCreditsRemaining": 0,
"paygCreditsRemaining": 0,
"buyCreditsUrl": "https://fetchin.io/credits"
}
}
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
{
"error": "Service temporarily unable to serve this request. Please retry.",
"code": "SERVICE_UNAVAILABLE"
}
Get Profile Articles
Fetch the long-form articles a professional profile has published
curl --request GET \
--url https://api.fetchin.io/api/v1/profile/articles \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.fetchin.io/api/v1/profile/articles"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.fetchin.io/api/v1/profile/articles', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fetchin.io/api/v1/profile/articles",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.fetchin.io/api/v1/profile/articles"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.fetchin.io/api/v1/profile/articles")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fetchin.io/api/v1/profile/articles")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"articles": [
{
"articleUrn": "urn:li:linkedInArticle:7280956270201704448",
"articleId": "7280956270201704448",
"title": "What I learned shipping software for thirty years",
"url": "https://www.linkedin.com/pulse/what-i-learned-shipping-software-thirty-years-williamhgates",
"description": "Every release teaches you something the last one could not. Here are the lessons that kept coming back, and the ones I had to...",
"publishedAt": "2026-07-14T08:12:03.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": 9,
"subtitle": "by Ada Lovelace • 9 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7264411902883401728",
"articleId": "7264411902883401728",
"title": "The energy transition is an engineering problem",
"url": "https://www.linkedin.com/pulse/energy-transition-engineering-problem-williamhgates",
"description": "We talk about climate in terms of pledges, but the hard part is industrial: steel, cement, fertiliser. None of them have a...",
"publishedAt": "2026-05-02T16:40:55.000Z",
"coverImageUrl": null,
"readTimeMinutes": 6,
"subtitle": "by Ada Lovelace • 6 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7231887450119684096",
"articleId": "7231887450119684096",
"title": "Notes from a year of reading",
"url": "https://www.linkedin.com/pulse/notes-from-year-reading-williamhgates",
"description": "Five books that changed how I think about measurement, and one that I gave up on halfway through without any regret at...",
"publishedAt": "2026-01-19T11:05:21.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": null,
"subtitle": "by Ada Lovelace"
}
],
"hasMore": true,
"nextStart": 10
}
{
"error": "Missing profileUrlOrUrn parameter",
"code": "MISSING_PARAMETER"
}
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
{
"error": "<human-readable reason>",
"code": "PROFILE_NOT_FOUND"
}
{
"error": "Quota exceeded. Upgrade your plan or wait for renewal.",
"code": "QUOTA_EXHAUSTED",
"details": {
"creditsRemaining": 0,
"subscriptionCreditsRemaining": 0,
"paygCreditsRemaining": 0,
"buyCreditsUrl": "https://fetchin.io/credits"
}
}
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
{
"error": "Service temporarily unable to serve this request. Please retry.",
"code": "SERVICE_UNAVAILABLE"
}
Endpoint
GET /api/v1/profile/articles
Authentication
Include your API key in the request header:X-API-Key: your-api-key-here
Parameters
- Profile URN, recommended for consistency: a profile’s public identifier (slug) can change over time, the URN does not. Example:
urn:li:fsd_profile:ACoAAA8BYqEBCGLg_vT_ca6mMEqkpp9nVffJ3hc - Public identifier (slug), also fine. Example:
williamhgates - Profile URL. Example:
https://www.linkedin.com/in/williamhgates(a trailing slash makes no difference)
/in/ prefix.Member profiles only: a company page URL or URN is rejected with a 400 error, free of charge.- Minimum: 1 —
0or a negative value is rejected with400 - Maximum: 100 — a higher value is clamped, not rejected
- Default: 10
0 (or omit it) for the first page, then advance
it by the count you requested. The response hands you the next value as
nextStart. See Pagination.- Minimum: 0 — a negative value is rejected with
400 - Maximum: 100,000 — a higher value is capped, not rejected
Response
Show Article object
Show Article object
urn:li:linkedInArticle:72809562702017044487280956270201704448null when
the id is not decodable — never a guessed date.null when the article has none.null when it cannot be
read.by Ada Lovelace • 9 min readtrue while this page came back with articles, which means it is worth asking
for the next offset. The last populated page also reports true — the feed
signals its end with an empty page, so expect one final request that returns
articles: [] and hasMore: false. See Pagination.start value to request next. Present only when hasMore is true.Example Request
curl -X GET "https://api.fetchin.io/api/v1/profile/articles?profileUrlOrUrn=https://www.linkedin.com/in/williamhgates&count=5" \
-H "X-API-Key: your-api-key-here"
const response = await fetch(
'https://api.fetchin.io/api/v1/profile/articles?profileUrlOrUrn=https://www.linkedin.com/in/williamhgates&count=5',
{
headers: {
'X-API-Key': 'your-api-key-here'
}
}
);
const data = await response.json();
console.log(data.articles);
import requests
headers = {
'X-API-Key': 'your-api-key-here'
}
params = {
'profileUrlOrUrn': 'https://www.linkedin.com/in/williamhgates',
'count': 5
}
response = requests.get(
'https://api.fetchin.io/api/v1/profile/articles',
headers=headers,
params=params
)
data = response.json()
print(data['articles'])
<?php
$apiKey = 'your-api-key-here';
$profileUrl = 'https://www.linkedin.com/in/williamhgates';
$count = 5;
$url = "https://api.fetchin.io/api/v1/profile/articles?profileUrlOrUrn=" . urlencode($profileUrl) . "&count=" . $count;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $apiKey
]);
$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
print_r($data['articles']);
?>
Example Response
{
"articles": [
{
"articleUrn": "urn:li:linkedInArticle:7280956270201704448",
"articleId": "7280956270201704448",
"title": "What I learned shipping software for thirty years",
"url": "https://www.linkedin.com/pulse/what-i-learned-shipping-software-thirty-years-williamhgates",
"description": "Every release teaches you something the last one could not. Here are the lessons that kept coming back, and the ones I had to...",
"publishedAt": "2026-07-14T08:12:03.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": 9,
"subtitle": "by Ada Lovelace • 9 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7264411902883401728",
"articleId": "7264411902883401728",
"title": "The energy transition is an engineering problem",
"url": "https://www.linkedin.com/pulse/energy-transition-engineering-problem-williamhgates",
"description": "We talk about climate in terms of pledges, but the hard part is industrial: steel, cement, fertiliser. None of them have a...",
"publishedAt": "2026-05-02T16:40:55.000Z",
"coverImageUrl": null,
"readTimeMinutes": 6,
"subtitle": "by Ada Lovelace • 6 min read"
},
{
"articleUrn": "urn:li:linkedInArticle:7231887450119684096",
"articleId": "7231887450119684096",
"title": "Notes from a year of reading",
"url": "https://www.linkedin.com/pulse/notes-from-year-reading-williamhgates",
"description": "Five books that changed how I think about measurement, and one that I gave up on halfway through without any regret at...",
"publishedAt": "2026-01-19T11:05:21.000Z",
"coverImageUrl": "https://media.licdn.com/dms/image/...",
"readTimeMinutes": null,
"subtitle": "by Ada Lovelace"
}
],
"hasMore": true,
"nextStart": 10
}
{
"error": "Missing profileUrlOrUrn parameter",
"code": "MISSING_PARAMETER"
}
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
{
"error": "<human-readable reason>",
"code": "PROFILE_NOT_FOUND"
}
code, never on error: the code is a frozen contract, while the
error message is informational and may be reworded.{
"error": "Quota exceeded. Upgrade your plan or wait for renewal.",
"code": "QUOTA_EXHAUSTED",
"details": {
"creditsRemaining": 0,
"subscriptionCreditsRemaining": 0,
"paygCreditsRemaining": 0,
"buyCreditsUrl": "https://fetchin.io/credits"
}
}
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}
{
"error": "Service temporarily unable to serve this request. Please retry.",
"code": "SERVICE_UNAVAILABLE"
}
Errors
See Error Handling for the full list of error codes and recommended handling.400—MISSING_PARAMETER/INVALID_PARAMETER/INVALID_URN401—INVALID_API_KEY404—PROFILE_NOT_FOUND402—QUOTA_EXHAUSTED429—RATE_LIMITED500—INTERNAL_ERROR503—SERVICE_UNAVAILABLE
Pagination
This is the one profile feed paged by offset rather than by cursor, because upstream exposes no cursor for it. There is nopaginationToken on this
endpoint.
- Request the first page with
start=0(or omitstart). - If
hasMoreistrue, request the next page with thenextStartthe response gave you. - Continue until
hasMoreisfalse.
nextStart advances by the count you requested, not by the number of
articles you received. If you build the offset yourself, add your requested
count — prefer nextStart, which already holds that value.
count is a ceiling, not a quota: a page can come back with fewer articles than
you asked for (a requested 20 routinely delivers 19) because the window indexes
the underlying list and items it cannot represent are dropped from the page. A
short page is not the end of the feed — only an empty page is.
async function fetchAllArticles(profileUrl) {
const allArticles = [];
let start = 0;
let hasMore = true;
while (hasMore) {
const params = new URLSearchParams({
profileUrlOrUrn: profileUrl,
count: '20',
start: String(start)
});
const response = await fetch(
`https://api.fetchin.io/api/v1/profile/articles?${params}`,
{ headers: { 'X-API-Key': 'your-api-key-here' } }
);
const data = await response.json();
allArticles.push(...data.articles);
// Advance by nextStart, never by data.articles.length:
// a short page is normal and does not mean the feed is over.
start = data.nextStart ?? start + 20;
hasMore = data.hasMore;
}
return allArticles;
}
Notes
count parameter value. Errors are free — with one exception: a 404 not found costs 1 credit. See Quotas.hasMore: false, never on a short page. A page holding fewer
articles than the count you requested is normal, and a client that treats
the first short page as the end of the feed will silently miss articles.description is the opening of the
text, around 150 characters. Do not expect those fields to appear on an
article object.400 INVALID_PARAMETER.
For organizations, use
Get Company Posts.articleUrn you already stored, then
stop.Use Cases
Thought-leadership tracking
Expertise mapping
Content library
articleUrnOutreach personalisation
Authorizations
Query Parameters
The professional profile to fetch. Accepts a profile URN (recommended for consistency, since a profile's public identifier can change over time while the URN does not; example urn:li:fsd_profile:ACoAAA8BYqEBCGLg_vT_ca6mMEqkpp9nVffJ3hc), a public identifier/slug (also fine; example williamhgates), or a full profile URL (example https://www.linkedin.com/in/williamhgates; a trailing slash is ignored). The slug is the last path segment of a profile URL, so pass just the slug, not the /in/ prefix. Member profiles only: a company page URL or URN is rejected with a 400 error, free of charge.
"urn:li:fsd_profile:ACoAAA8BYqEBCGLg_vT_ca6mMEqkpp9nVffJ3hc"
Number of articles to fetch per page (default: 10). A value above 100 is clamped to 100, not rejected. The value is a ceiling: a page can come back with fewer articles than requested.
1 <= x <= 100Offset of the first article to return, counted from the newest. Supported on this endpoint: this feed is paged by offset, not by cursor. Pass 0 (or omit) for the first page, then advance by the count you requested - the response hands you that value as nextStart. Keep paging while hasMore is true.
x >= 020
Response
Successfully fetched profile articles
Published articles, newest first.
Show child attributes
Show child attributes
Whether the feed holds more articles behind this page. Stop paging when it is false; a short page is not the end of the feed.
The start value to request next. Present only when hasMore is true.
10