Developers

API documentation

Read your LinkedIn content, manage your engagement feeds, and drive outreach campaigns from your own scripts and automations.

Base URLhttps://myfeedin.co/api/v1

Introduction

The MyFeedIn API is a REST API over HTTPS. It returns JSON, uses standard HTTP status codes, and is authenticated with an API key. Every request is scoped to the account or workspace that key belongs to, so a key never sees data outside its scope.

Create and manage keys in Settings, API keys.

Prefer chatting with your data from Claude instead of writing code? Connect the MyFeedIn MCP server, it exposes the same posts, analytics, feeds and campaigns as conversational tools, including adding profiles to a campaign by URL.

Authentication

Pass your key as a bearer token on every request. Keys are shown once at creation and stored hashed, so keep yours somewhere safe and never expose it in client-side code.

cURL
curl https://myfeedin.co/api/v1/me \
  -H "Authorization: Bearer mfi_live_your_key_here"

A missing or invalid key returns 401. An inactive subscription returns 402.

Scopes

Each key grants a chosen subset of permissions. The campaign scopes require an active Growth plan, checked at request time. Feed scopes work on every plan, except adding people to a feed, which also needs Growth.

FieldTypeDescription
posts:readscopeRead your published LinkedIn posts and their analytics. Analytics sit here rather than under a scope of their own because they are sums of the posts this scope already returns.
comments:readscopeRead the comments you left on other people's posts.
feeds:readscopeList your feeds and the people in them.
feeds:writescopeCreate feeds, remove people, and add people by URL (adding requires Growth).
campaigns:readscopeList campaigns and read their stats. Requires Growth.
campaigns:writescopeCreate campaigns and add profiles. Requires Growth.

Rate limits

Requests are rate limited per key. When you exceed the limit the API returns 429 with a retry_after value in seconds. Back off and retry after that window.

Errors

Errors return a JSON body of the shape { "error": "message" } with a conventional status code.

FieldTypeDescription
400Bad RequestMissing or malformed parameters.
401UnauthorizedMissing, invalid, or revoked key.
402Payment RequiredSubscription inactive.
403ForbiddenKey lacks the required scope or plan.
404Not FoundResource does not exist in this scope.
429Too Many RequestsRate limit exceeded.

Personal keys and workspace keys

A key is bound to one scope when you create it: either your personal account, or one workspace. That binding is permanent. To switch, revoke the key and mint a new one. GET /v1/me tells you which kind you are holding.

The difference matters because MyFeedIn stores two kinds of data. Content belongs to a person: your posts and your comments carry your user id, and a workspace never owns them. Everything else, feeds, saved people and campaigns, belongs to the workspace.

So a workspace key reads the posts, comments and analytics of every member, not just the person who created the key. Each row then carries an author naming who it belongs to, and the member parameter narrows a request to one person. A personal key reads exactly one account and never returns author.

FieldTypeDescription
memberstringAccepted by /v1/posts, /v1/posts/{id}, /v1/comments and both analytics endpoints. A member's name, email or id — call /v1/workspace/members to list them. Omit to cover every member. Passing it on a personal key returns 400.
authorobjectPresent on every post and comment when the scope spans more than one person: { user_id, name }.
Request
curl "https://myfeedin.co/api/v1/posts?member=John&limit=5" \
  -H "Authorization: Bearer mfi_live_your_key_here"

Account

Current key

GET/v1/me

Returns the calling key's user id, scope, and granted scopes. The simplest way to confirm a key works.

Response
{
  "user_id": "a418d3f9-…",
  "workspace_id": null,
  "scope": "personal",
  "scopes": ["posts:read", "campaigns:read", "campaigns:write"]
}

Posts

List posts

GET/v1/posts

Published LinkedIn posts. Newest first by default; pass sort to rank by engagement instead, and q to search the post body. Requires posts:read.

FieldTypeDescription
qstringCase-insensitive search across the post body.
sortstringrecent (default), impressions, comments or reactions. Combines with q to rank the matches.
periodstring30d, 90d, 365d or all. Defaults to 90d for ranked sorts, unbounded otherwise.
sincestringEarliest published_at, ISO 8601.
untilstringLatest published_at, ISO 8601.
memberstringWorkspace keys only. Restrict to one member.
limitinteger1 to 100. Default 20.

Workspace keys

Returns every member's posts, each row carrying an author. Narrow with member.
Request
curl "https://myfeedin.co/api/v1/posts?q=hiring&sort=impressions&period=365d" \
  -H "Authorization: Bearer mfi_live_your_key_here"
Response
{
  "count": 1,
  "posts": [
    {
      "id": "9ba6e7c7-…",
      "url": "https://www.linkedin.com/posts/…",
      "num_likes": 24,
      "num_comments": 5,
      "num_impressions": 1330,
      "num_shares": 3,
      "published_at": "2026-06-17T06:58:07Z",
      "excerpt": "I posted the exact same article on X and LinkedIn…",
      "author": { "user_id": "6938a74e-…", "name": "John Schapmann" }
    }
  ]
}

Get a post

GET/v1/posts/{id}

One post with its full body and media arrays. The list endpoint returns a 500-character excerpt to keep payloads small; this returns everything. Requires posts:read.

Workspace keys

Any member's post can be fetched. An id outside the key's scope returns 404.
Request
curl https://myfeedin.co/api/v1/posts/POST_ID \
  -H "Authorization: Bearer mfi_live_your_key_here"

Analytics

Aggregate analytics

GET/v1/analytics

Totals and averages across the period: post count, likes, comments, impressions, shares, and an average-engagement figure. Requires posts:read, since these are sums of the posts that scope already returns.

FieldTypeDescription
periodstring30d (default), 90d, 365d or all.
compare_tostringPass 'previous' to also return the preceding window and the percent deltas. Not available with period=all.
memberstringWorkspace keys only. Restrict to one member.

Workspace keys

Returns the workspace total and a by_member array, so one member publishing nothing stays visible instead of being averaged away.
Response
{
  "period": "30d",
  "post_count": 14,
  "total_impressions": 41230,
  "avg_engagement": 38.5,
  "by_member": [
    { "member": { "user_id": "a418d3f9-…", "name": "Axel Schapmann" }, "post_count": 14, "total_impressions": 41230 },
    { "member": { "user_id": "6938a74e-…", "name": "John Schapmann" }, "post_count": 0, "total_impressions": 0 }
  ]
}

Engagement patterns

GET/v1/analytics/patterns

Best day of week, best hour of day, and average engagement per post length bucket, computed from your own history rather than generic advice. Requires posts:read.

FieldTypeDescription
periodstring90d or 365d (default). Shorter windows produce confident-looking noise.
memberstringWorkspace keys only. Restrict to one member.

Workspace keys

Timings pool every member, which describes the workspace rather than one person. The response includes members_pooled so you know how many went into the sample; pass member for an individual.

Comments

List comments

GET/v1/comments

Comments left on other people's posts, newest first, each with context about the post it was left under. Requires comments:read, a separate scope from posts:read because this is a different dataset: what you wrote under other people's content.

FieldTypeDescription
qstringCase-insensitive search across the comment body.
sincestringEarliest comment date, ISO 8601.
memberstringWorkspace keys only. Restrict to one member.
limitinteger1 to 100. Default 20.

Workspace keys

Returns every member's comments, each carrying an author.
Request
curl "https://myfeedin.co/api/v1/comments?q=pricing&limit=10" \
  -H "Authorization: Bearer mfi_live_your_key_here"

People

Search saved people

GET/v1/people

Search everyone saved across your feeds and lists by name or headline, without knowing which feed they sit in. Requires feeds:read.

FieldTypeDescription
qstringRequired. Name or headline keyword.
limitinteger1 to 100. Default 20.

Workspace keys

Saved people belong to the workspace, not to a member, so there is one shared address book and no member parameter here.

Workspace

List workspace members

GET/v1/workspace/members

Who the key can read, and how to name them in the member parameter. No scope required. Emails are not returned: member matches on name or id.

Workspace keys

On a personal key this returns 200 with an empty roster rather than an error, so one code path handles both kinds of key.
Response
{
  "scope": "workspace",
  "workspace_id": "aa22756a-…",
  "count": 2,
  "members": [
    { "id": "a418d3f9-…", "name": "Axel Schapmann", "role": "owner", "post_count": 841, "is_key_owner": true },
    { "id": "6938a74e-…", "name": "John Schapmann", "role": "editor", "post_count": 48, "is_key_owner": false }
  ]
}

Feeds

List feeds

GET/v1/feeds

Your engagement feeds, newest first, each with a member count. Requires feeds:read.

Request
curl https://myfeedin.co/api/v1/feeds \
  -H "Authorization: Bearer mfi_live_your_key_here"
Response
{
  "count": 2,
  "feeds": [
    {
      "id": "7f2c9a10-…",
      "name": "SaaS founders",
      "member_count": 24,
      "created_at": "2026-05-02T09:12:44Z"
    },
    {
      "id": "b81d4e63-…",
      "name": "Clients",
      "member_count": 9,
      "created_at": "2026-03-18T14:03:21Z"
    }
  ]
}

Create feed

POST/v1/feeds

Creates an empty feed. Requires feeds:write. Fill it from the app, the Chrome extension, or the add-people endpoint below (Growth plan).

FieldTypeDescription
namestringFeed name. Required, max 120 characters.
Request
curl -X POST https://myfeedin.co/api/v1/feeds \
  -H "Authorization: Bearer mfi_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name":"SaaS founders"}'
Response
{
  "feed": {
    "id": "7f2c9a10-…",
    "name": "SaaS founders",
    "member_count": 0,
    "created_at": "2026-07-20T10:04:12Z"
  }
}

List people in a feed

GET/v1/feeds/{id}/people

The people in one feed. Use the returned person ids with the remove endpoint below. Requires feeds:read.

FieldTypeDescription
limitinteger1 to 200. Default 100.
Request
curl "https://myfeedin.co/api/v1/feeds/FEED_ID/people?limit=50" \
  -H "Authorization: Bearer mfi_live_your_key_here"
Response
{
  "feed": { "id": "7f2c9a10-…", "name": "SaaS founders" },
  "count": 1,
  "people": [
    {
      "id": "c3f81b52-…",
      "full_name": "Jane Doe",
      "headline": "Founder at Acme",
      "linkedin_url": "https://www.linkedin.com/in/jane-doe",
      "picture_url": "https://media.licdn.com/dms/image/…"
    }
  ]
}

Add people to a feed

POST/v1/feeds/{id}/people

Adds LinkedIn profiles to a feed by URL. Each URL is resolved through your connected LinkedIn account to its real LinkedIn identifier (a feed member without one would never appear in the feed), created in your CRM if new, then attached to the feed. Requires feeds:write, the Growth plan, and a connected LinkedIn account. Keys on other plans get a 403; without a connected account the API returns 400.

FieldTypeDescription
linkedin_urlstringA single profile URL.
linkedin_urlsstring[]Up to 25 profile URLs. Use instead of linkedin_url for batches.
Request
curl -X POST https://myfeedin.co/api/v1/feeds/FEED_ID/people \
  -H "Authorization: Bearer mfi_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"linkedin_urls":["https://www.linkedin.com/in/jane-doe"]}'
Response
{
  "added": 1,
  "created": 1,
  "matched": 0,
  "already_in_feed": 0
}

created counts people new to your CRM, matched counts people you already had. Someone already in the feed is skipped and counted in already_in_feed. A URL that cannot be resolved (private or out of network) is reported in an errors array without failing the rest of the batch.

Remove person from feed

DELETE/v1/feeds/{id}/people/{personId}

Removes a person from the feed. The person stays in your CRM and in any other feed they belong to; only this membership is deleted. The personId comes from the list endpoint above. Requires feeds:write.

Request
curl -X DELETE https://myfeedin.co/api/v1/feeds/FEED_ID/people/PERSON_ID \
  -H "Authorization: Bearer mfi_live_your_key_here"
Response
{ "removed": true }

Campaigns

List campaigns

GET/v1/campaigns

Lists your outreach campaigns with per-campaign enrollment counts and step counts. Requires campaigns:read.

Response
{
  "campaigns": [
    {
      "id": "…",
      "name": "Solopreneurs Q3",
      "status": "active",
      "step_count": 3,
      "enrollment_counts": { "total": 42, "active": 30, "replied": 4 }
    }
  ]
}

Create campaign

POST/v1/campaigns

Creates a draft campaign, locked to your connected LinkedIn account. Requires campaigns:write and a connected account.

FieldTypeDescription
namestringCampaign name. Defaults to Untitled campaign.
iconstringOptional icon name. Defaults to Megaphone.
Request
curl -X POST https://myfeedin.co/api/v1/campaigns \
  -H "Authorization: Bearer mfi_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name":"Solopreneurs Q3"}'

Get campaign

GET/v1/campaigns/{id}

One campaign with its ordered steps, warmup state, and enrollments (each joined to its person). Requires campaigns:read.

Add profiles by URL

POST/v1/campaigns/{id}/profiles

Adds LinkedIn profiles to a campaign by URL. Each URL is resolved through your connected LinkedIn account, upserted into your CRM, then enrolled. Requires campaigns:write and the Growth plan.

FieldTypeDescription
linkedin_urlstringA single profile URL.
linkedin_urlsstring[]Up to 25 profile URLs. Use instead of linkedin_url for batches.
Request
curl -X POST https://myfeedin.co/api/v1/campaigns/CAMPAIGN_ID/profiles \
  -H "Authorization: Bearer mfi_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"linkedin_url":"https://www.linkedin.com/in/some-person"}'
Response
{
  "enrolled": 1,
  "created": 1,
  "matched": 0,
  "skipped": 0,
  "skipped_active_elsewhere": 0
}

Guides

Guide: add a profile to a campaign

The most common workflow: find a campaign, then push profiles into it by URL. First list your campaigns to get an id.

1. Find the campaign
curl https://myfeedin.co/api/v1/campaigns \
  -H "Authorization: Bearer mfi_live_your_key_here"

Then add one or more profiles to it.

2. Add profiles
curl -X POST https://myfeedin.co/api/v1/campaigns/CAMPAIGN_ID/profiles \
  -H "Authorization: Bearer mfi_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "linkedin_urls": [
      "https://www.linkedin.com/in/person-a",
      "https://www.linkedin.com/in/person-b"
    ]
  }'

A person already active in another campaign is skipped rather than enrolled twice, and appears in skipped_active_elsewhere. A URL that cannot be resolved (private or out of network) is reported in an errors array without failing the rest of the batch.

Guide: manage a feed

Keep a feed clean from a script: list your feeds to get an id, list the people in it, then remove the ones that no longer belong.

1. Find the feed
curl https://myfeedin.co/api/v1/feeds \
  -H "Authorization: Bearer mfi_live_your_key_here"
2. List its people
curl https://myfeedin.co/api/v1/feeds/FEED_ID/people \
  -H "Authorization: Bearer mfi_live_your_key_here"
3. Remove a person
curl -X DELETE https://myfeedin.co/api/v1/feeds/FEED_ID/people/PERSON_ID \
  -H "Authorization: Bearer mfi_live_your_key_here"

Removing a person only detaches them from that feed; their CRM record and their other feed memberships are untouched. To rebuild the list, add people again from the app, the Chrome extension, or the add-people endpoint if you are on the Growth plan.