NetwarmNetwarmAPI & MCP
Get an API key
Getting startedAuthenticationConventionsREST APIAccountGET/meGET/profilesPeopleGET/peopleGET/readyGET/people/{person}PATCH/people/{person}GET/people/{person}/engagementsPOST/people/{person}/notesPATCH/people/{person}/notes/{id}DELETE/people/{person}/notes/{id}POST/people/bulkGET/people/{person}/openersEngagementsGET/engagementsContentGET/postsGET/posts/{id}GET/audienceGET/topicsSetupGET/targetsPOST/targetsPATCH/targets/{id}DELETE/targets/{id}GET/stagesRevealsGET/revealsGET/reveals/{id}/unlocksSchedulingGET/scheduled-postsPOST/mediaPOST/media/completePOST/media/from-urlPOST/scheduled-postsPATCH/scheduled-posts/{id}DELETE/scheduled-posts/{id}AI assistantsMCP server
Developers

Netwarm API & MCP

Everyone who engages with your LinkedIn posts, how warm they are, which target they match and where they are in your pipeline. Use it from your own code (REST), or let an AI assistant use it (MCP): “who should I reach out to today, and what do I say?”

REST APIFor scripts, a CRM sync, Zapier, Make or n8n.MCP serverFor Claude, ChatGPT, Cursor and other assistants.

Authentication

Create an API key in Netwarm, Settings › API & MCP. A key acts as you in your workspace, with the permissions you gave it. Send it in the Authorization header.

cURL
$ curl https://app.netwarm.com/api/v1/ready \
  -H "Authorization: Bearer nw_live_…"
Permissions
readRead. People, warmth, engagements, posts, targets, stages, topics and reveals.
writeUpdate people. Move people between stages and targets, approve, dismiss or snooze them, add and edit notes, manage targets.
leadsContact details. Emails and phone numbers: reveal unlocks and the ones saved on people. Find and update people by email.
postsSchedule posts. Schedule, edit and cancel LinkedIn posts, published on your LinkedIn at the time set.

Conventions

Base URLhttps://app.netwarm.com/api/v1JSON in and out. Dates are ISO 8601.
PaginationOne object comes as { data: {…} }, a list as { data: […], next_cursor }. Pass next_cursor back as cursor for the next page (null on the last one).
PeopleTake an id, a LinkedIn profile URL or a handle. A workspace can track several profiles: pass profile, else your own. On the free plan, some people are locked: they come without who they are until you upgrade.
Errors{ error: { code, message } }
400Invalid request
401Missing or invalid key
402Locked on the free plan
403Missing permission
404Not found
409Conflict
429Over the workspace’s limits
LimitsPer workspace, shared by all keys and connected apps. Over a limit, requests get a 429 until the window moves on.
Plan15 min24 h30 days
Free301001,000
Creator3005,00030,000
Agency50010,000100,000
Machine-readable: OpenAPI 3.1 ↗

Account

GET/meread

The workspace, the key's member, its permissions, this month's usage and the tracked profiles.

Response · 200
{
  "data": {
    "workspace": {
      "id": "042f20f4-5e38-4bcc-8632-c9324ce03ac6",
      "name": "Lumen",
      "plan": "creator"
    },
    "user": {
      "id": "acfd0aaf-95cd-4c02-bea8-31064e87f36a",
      "name": "Max Sawyer",
      "email": "max@example.com"
    },
    "scopes": [
      "read",
      "write"
    ],
    "usage": {
      "engagements": 1840,
      "allowance": 5000,
      "since": "2026-10-01T00:00:00Z"
    },
    "profiles": [
      {
        "id": "361aeda8-e471-4092-bb9c-d79bd7795162",
        "name": "Max Sawyer",
        "slug": "max-sawyer",
        "headline": "Founder · Patient onboarding",
        "linkedin_url": "https://www.linkedin.com/in/max-sawyer",
        "avatar_url": null,
        "followers": 12800,
        "is_own": true,
        "last_synced_at": "2026-10-27T06:00:00Z"
      }
    ]
  }
}
GET/profilesread

The workspace's tracked LinkedIn profiles.

Response · 200
{
  "data": [
    {
      "id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "name": "Max Sawyer",
      "slug": "max-sawyer",
      "headline": "Founder · Patient onboarding",
      "linkedin_url": "https://www.linkedin.com/in/max-sawyer",
      "avatar_url": null,
      "followers": 12800,
      "is_own": true,
      "last_synced_at": "2026-10-27T06:00:00Z"
    }
  ]
}

People

GET/peopleread

Everyone who engaged with a profile, with warmth, target, stage and triage. Filter, sort and page through them.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
warmthstringhot, interested, curious (comma-separated).
targetstringTarget id or name, or none.
stagestringStage id, key (new, contacted, conversation, client, not_a_fit) or name.
statusenumactive | approved | dismissed | snoozed
readybooleanOnly people on (or off) the Ready list.
qstringSearch in name, headline, title and company.
engaged_sincestringLast engaged on or after this date (ISO 8601).
emailstringExact email, to match a CRM contact (needs the leads permission).
sortenumrecent (default): last engaged first; warmth: warmest first.
limitintegerPage size, 1 to 100 (default 25).
cursorstringnext_cursor from the previous page.
Response · 200
{
  "data": [
    {
      "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "access": "full",
      "name": "Amara Okafor",
      "headline": "CEO at Lumen Health · Building patient-first care",
      "title": "CEO",
      "company": "Lumen Health",
      "company_domain": "lumenhealth.com",
      "industry": "Hospitals and Health Care",
      "company_size": "51–200",
      "location": "London, United Kingdom",
      "country_code": "GB",
      "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
      "avatar_url": "https://media.licdn.com/…",
      "followers": 4120,
      "warmth": "hot",
      "warmth_score": 86,
      "target": {
        "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
        "name": "Healthcare founders"
      },
      "stage": {
        "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
        "key": "new",
        "name": "New"
      },
      "status": "active",
      "snoozed_until": null,
      "on_ready": true,
      "engagement_count": 4,
      "first_engaged_at": "2026-09-30T08:02:00Z",
      "last_engaged_at": "2026-10-26T09:12:00Z",
      "became_hot_at": "2026-10-26T09:12:00Z",
      "last_engagement": {
        "kind": "comment",
        "comment_type": "substantive"
      }
    }
  ],
  "next_cursor": "eyJvIjoyNX0",
  "total": 412
}
GET/readyread

Who to reach out to now: the Ready list (in a target, engaged in the last 90 days, still in New), warmest first.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
targetstringOnly this target (id or name).
limitintegerPage size, 1 to 100 (default 25).
Request
$ curl https://app.netwarm.com/api/v1/ready?limit=1 \
  -H "Authorization: Bearer nw_live_…"
Response · 200
{
  "data": [
    {
      "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "access": "full",
      "name": "Amara Okafor",
      "headline": "CEO at Lumen Health · Building patient-first care",
      "title": "CEO",
      "company": "Lumen Health",
      "company_domain": "lumenhealth.com",
      "industry": "Hospitals and Health Care",
      "company_size": "51–200",
      "location": "London, United Kingdom",
      "country_code": "GB",
      "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
      "avatar_url": "https://media.licdn.com/…",
      "followers": 4120,
      "warmth": "hot",
      "warmth_score": 86,
      "target": {
        "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
        "name": "Healthcare founders"
      },
      "stage": {
        "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
        "key": "new",
        "name": "New"
      },
      "status": "active",
      "snoozed_until": null,
      "on_ready": true,
      "engagement_count": 4,
      "first_engaged_at": "2026-09-30T08:02:00Z",
      "last_engaged_at": "2026-10-26T09:12:00Z",
      "became_hot_at": "2026-10-26T09:12:00Z",
      "last_engagement": {
        "kind": "comment",
        "comment_type": "substantive"
      }
    }
  ],
  "total": 12,
  "locked": 0
}
GET/people/{person}read

One person: who they are, their LinkedIn profile as last read, recent engagements (with comment text) and timeline. {person} is an id, a LinkedIn URL (URL-encoded) or a handle.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 200
{
  "data": {
    "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "access": "full",
    "name": "Amara Okafor",
    "headline": "CEO at Lumen Health · Building patient-first care",
    "title": "CEO",
    "company": "Lumen Health",
    "company_domain": "lumenhealth.com",
    "industry": "Hospitals and Health Care",
    "company_size": "51–200",
    "location": "London, United Kingdom",
    "country_code": "GB",
    "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
    "avatar_url": "https://media.licdn.com/…",
    "followers": 4120,
    "warmth": "hot",
    "warmth_score": 86,
    "target": {
      "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
      "name": "Healthcare founders"
    },
    "stage": {
      "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
      "key": "new",
      "name": "New"
    },
    "status": "active",
    "snoozed_until": null,
    "on_ready": true,
    "engagement_count": 4,
    "first_engaged_at": "2026-09-30T08:02:00Z",
    "last_engaged_at": "2026-10-26T09:12:00Z",
    "became_hot_at": "2026-10-26T09:12:00Z",
    "last_engagement": {
      "kind": "comment",
      "comment_type": "substantive"
    },
    "linkedin_profile": {
      "about": "Building patient-first care at Lumen Health.",
      "current_job": {
        "title": "CEO",
        "company": "Lumen Health"
      },
      "jobs": [
        {
          "title": "CEO",
          "company": "Lumen Health",
          "current": true,
          "since": "2021-03"
        }
      ],
      "schools": [
        "Imperial College London"
      ],
      "languages": [
        "English",
        "French"
      ]
    },
    "engagements": [
      {
        "id": "9f2c1b7e-5d0a-4c11-9a51-0b1f6f1d8e21",
        "kind": "comment",
        "at": "2026-10-26T09:12:00Z",
        "reaction": null,
        "comment": "We had the exact same problem with our onboarding: how did you measure the drop-off?",
        "comment_type": "substantive",
        "in_conversation_with_creator": false,
        "post": {
          "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
          "title": "Most onboarding flows lose half their users at step 2",
          "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297",
          "topic": "Onboarding"
        },
        "reveal": null
      }
    ],
    "timeline": [
      {
        "id": "581377c1-893a-4ed9-a0af-2455c02091e3",
        "kind": "note",
        "at": "2026-10-26T10:02:00Z",
        "text": "Asked about the drop-off: follow up with the case study.",
        "via": "Claude",
        "edited": false
      }
    ]
  }
}
PATCH/people/{person}write

Change a person's stage or target, or triage them (approve, dismiss, snooze).

Body (JSON)
stagestringStage id, key or name.
targetstring | nullTarget id or name; null or none takes them out of their target.
statusenumTriage: approved, dismissed, snoozed (hidden from Ready for snooze_days), or active to undo.
snooze_daysintegerWith status snoozed: for how many days (default 14).
emailstring | nullEmail saved on the person; null clears it (needs the leads permission).
phonestring | nullPhone number saved on the person; null clears it (needs the leads permission).
Response · 200
{
  "data": {
    "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "access": "full",
    "name": "Amara Okafor",
    "headline": "CEO at Lumen Health · Building patient-first care",
    "title": "CEO",
    "company": "Lumen Health",
    "company_domain": "lumenhealth.com",
    "industry": "Hospitals and Health Care",
    "company_size": "51–200",
    "location": "London, United Kingdom",
    "country_code": "GB",
    "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
    "avatar_url": "https://media.licdn.com/…",
    "followers": 4120,
    "warmth": "hot",
    "warmth_score": 86,
    "target": {
      "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
      "name": "Healthcare founders"
    },
    "stage": {
      "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
      "key": "new",
      "name": "New"
    },
    "status": "active",
    "snoozed_until": null,
    "on_ready": true,
    "engagement_count": 4,
    "first_engaged_at": "2026-09-30T08:02:00Z",
    "last_engaged_at": "2026-10-26T09:12:00Z",
    "became_hot_at": "2026-10-26T09:12:00Z",
    "last_engagement": {
      "kind": "comment",
      "comment_type": "substantive"
    }
  }
}
GET/people/{person}/engagementsread

A person's engagements with the profile, newest first.

Query
limitintegerPage size, 1 to 100 (default 50).
cursorstringnext_cursor from the previous page.
Response · 200
{
  "data": [
    {
      "id": "9f2c1b7e-5d0a-4c11-9a51-0b1f6f1d8e21",
      "kind": "comment",
      "at": "2026-10-26T09:12:00Z",
      "reaction": null,
      "comment": "We had the exact same problem with our onboarding: how did you measure the drop-off?",
      "comment_type": "substantive",
      "in_conversation_with_creator": false,
      "post": {
        "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
        "title": "Most onboarding flows lose half their users at step 2",
        "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297",
        "topic": "Onboarding"
      },
      "reveal": null
    }
  ],
  "next_cursor": null
}
POST/people/{person}/noteswrite

Add a note to a person's timeline.

Body (JSON)
textrequiredstringThe note, up to 4,000 characters.
Response · 201
{
  "data": {
    "id": "581377c1-893a-4ed9-a0af-2455c02091e3",
    "person_id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
    "kind": "note",
    "text": "Asked about the drop-off: follow up with the case study.",
    "at": "2026-10-26T10:02:00Z"
  }
}
PATCH/people/{person}/notes/{id}write

Edit a note you wrote (notes are changed by their author only).

Body (JSON)
textrequiredstringThe note, up to 4,000 characters.
Response · 200
{
  "data": {
    "id": "581377c1-893a-4ed9-a0af-2455c02091e3",
    "person_id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
    "kind": "note",
    "text": "Asked about the drop-off: follow up with the case study.",
    "at": "2026-10-26T10:02:00Z"
  }
}
DELETE/people/{person}/notes/{id}write

Delete a note you wrote.

Response · 200
{
  "data": {
    "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
    "deleted": true
  }
}
POST/people/bulkwrite

The same stage, target or triage change on up to 100 people of a profile. Each one says whether it was changed.

Body (JSON)
peoplerequiredarrayPerson ids (up to 100), all of one profile.
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
stagestringStage id, key or name.
targetstring | nullTarget id or name; null or none takes them out of their target.
statusenumTriage: approved, dismissed, snoozed, or active to undo.
snooze_daysintegerWith status snoozed: for how many days (default 14).
Response · 200
{
  "data": {
    "updated": 2,
    "results": [
      {
        "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
        "ok": true
      },
      {
        "id": "9776ed4e-35f7-4f76-9f7d-748d113528ed",
        "ok": true
      },
      {
        "id": "00000000-0000-0000-0000-000000000000",
        "ok": false,
        "error": "Not a person of this profile."
      }
    ]
  }
}
GET/people/{person}/openersread

The coach's suggested first DMs and connection request notes for this person. fresh=true writes new ones.

Query
freshbooleantrue writes a new set (an AI call) instead of returning the saved one.
Response · 200
{
  "data": {
    "person_id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
    "messages": [
      "Hi Amara, you asked how we measured the drop-off at step 2: we tagged each screen in the funnel. Is onboarding something you're working on at Lumen right now?"
    ],
    "connection_notes": [
      "Hi Amara, the step-2 drop-off question was a good one. Are you looking at your own onboarding right now?"
    ]
  }
}

Engagements

GET/engagementsread

New likes, comments, reposts and reveal unlocks as they're captured, oldest first: for syncing a CRM or an automation. Keep the last next_cursor and poll with it.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
sincestringCaptured on or after this date (default: 24 hours ago). Ignored with a cursor.
kindstringlike, comment, repost, reveal (comma-separated).
limitintegerPage size, 1 to 200 (default 50).
cursorstringnext_cursor from the previous page.
Response · 200
{
  "data": [
    {
      "id": "9f2c1b7e-5d0a-4c11-9a51-0b1f6f1d8e21",
      "kind": "comment",
      "at": "2026-10-26T09:12:00Z",
      "reaction": null,
      "comment": "We had the exact same problem with our onboarding: how did you measure the drop-off?",
      "comment_type": "substantive",
      "in_conversation_with_creator": false,
      "post": {
        "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
        "title": "Most onboarding flows lose half their users at step 2",
        "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297"
      },
      "reveal": null,
      "captured_at": "2026-10-26T09:20:00Z",
      "person": {
        "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
        "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
        "access": "full",
        "name": "Amara Okafor",
        "headline": "CEO at Lumen Health · Building patient-first care",
        "title": "CEO",
        "company": "Lumen Health",
        "company_domain": "lumenhealth.com",
        "industry": "Hospitals and Health Care",
        "company_size": "51–200",
        "location": "London, United Kingdom",
        "country_code": "GB",
        "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
        "avatar_url": "https://media.licdn.com/…",
        "followers": 4120,
        "warmth": "hot",
        "warmth_score": 86,
        "target": {
          "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
          "name": "Healthcare founders"
        },
        "stage": {
          "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
          "key": "new",
          "name": "New"
        },
        "status": "active",
        "snoozed_until": null,
        "on_ready": true,
        "engagement_count": 4,
        "first_engaged_at": "2026-09-30T08:02:00Z",
        "last_engaged_at": "2026-10-26T09:12:00Z",
        "became_hot_at": "2026-10-26T09:12:00Z",
        "last_engagement": {
          "kind": "comment",
          "comment_type": "substantive"
        }
      }
    }
  ],
  "next_cursor": "eyJhdCI6Ij…"
}

Content

GET/postsread

The profile's LinkedIn posts, newest first, with their stats and topic.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
sincestringPosted on or after this date.
limitintegerPage size, 1 to 100 (default 25).
cursorstringnext_cursor from the previous page.
Response · 200
{
  "data": [
    {
      "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "title": "Most onboarding flows lose half their users at step 2",
      "text": "Most onboarding flows lose half their users at step 2.\n\nHere's what we changed…",
      "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297",
      "posted_at": "2026-10-24T07:30:00Z",
      "topic": "Onboarding",
      "stats": {
        "likes": 212,
        "comments": 38,
        "reposts": 6,
        "impressions": 18400
      }
    }
  ],
  "next_cursor": null
}
GET/posts/{id}read

One post, and who engaged with it: by kind, warmth and target, and the warmest people.

Response · 200
{
  "data": {
    "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "title": "Most onboarding flows lose half their users at step 2",
    "text": "Most onboarding flows lose half their users at step 2.\n\nHere's what we changed…",
    "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297",
    "posted_at": "2026-10-24T07:30:00Z",
    "topic": "Onboarding",
    "stats": {
      "likes": 212,
      "comments": 38,
      "reposts": 6,
      "impressions": 18400
    },
    "engagement": {
      "by_kind": {
        "like": 212,
        "comment": 38,
        "repost": 6
      },
      "people": 231,
      "by_warmth": {
        "hot": 9,
        "interested": 41,
        "curious": 181
      },
      "by_target": [
        {
          "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
          "name": "Healthcare founders",
          "people": 27
        },
        {
          "id": null,
          "name": "Not in a target",
          "people": 204
        }
      ],
      "warmest": [
        {
          "id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
          "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
          "access": "full",
          "name": "Amara Okafor",
          "headline": "CEO at Lumen Health · Building patient-first care",
          "title": "CEO",
          "company": "Lumen Health",
          "company_domain": "lumenhealth.com",
          "industry": "Hospitals and Health Care",
          "company_size": "51–200",
          "location": "London, United Kingdom",
          "country_code": "GB",
          "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
          "avatar_url": "https://media.licdn.com/…",
          "followers": 4120,
          "warmth": "hot",
          "warmth_score": 86,
          "target": {
            "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
            "name": "Healthcare founders"
          },
          "stage": {
            "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
            "key": "new",
            "name": "New"
          },
          "status": "active",
          "snoozed_until": null,
          "on_ready": true,
          "engagement_count": 4,
          "first_engaged_at": "2026-09-30T08:02:00Z",
          "last_engaged_at": "2026-10-26T09:12:00Z",
          "became_hot_at": "2026-10-26T09:12:00Z",
          "last_engagement": {
            "kind": "comment",
            "comment_type": "substantive"
          }
        }
      ]
    }
  }
}
GET/audienceread

What happened over the last days: engagements, new and newly hot people, warmth, targets, top posts and topics.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
daysintegerPeriod in days, 1 to 90 (default 30).
Response · 200
{
  "data": {
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "period": {
      "days": 30,
      "since": "2026-09-27T00:00:00Z"
    },
    "engagements": {
      "total": 1840,
      "by_kind": {
        "like": 1502,
        "comment": 281,
        "repost": 57
      },
      "people": 912
    },
    "new_people": 388,
    "became_hot": 21,
    "warmth": {
      "everyone": {
        "hot": 34,
        "interested": 160,
        "curious": 1210
      },
      "in_targets": {
        "hot": 12,
        "interested": 48,
        "curious": 230
      }
    },
    "targets": [
      {
        "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
        "name": "Healthcare founders",
        "people": 290,
        "hot": 12
      }
    ],
    "top_posts": [
      {
        "id": "adc7fb8d-f8db-4e90-bbd4-889c4352e239",
        "title": "Most onboarding flows lose half their users at step 2",
        "url": "https://www.linkedin.com/feed/update/urn:li:activity:7520057447361847297",
        "engagements": 256
      }
    ],
    "topics": [
      {
        "name": "Onboarding",
        "engagements": 640
      }
    ]
  }
}
GET/topicsread

The profile's post topics.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 200
{
  "data": [
    {
      "id": "9ab75739-6765-4e9b-bfb5-ac179671d92b",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "name": "Onboarding",
      "posts": 20
    }
  ]
}

Setup

GET/targetsread

The profile's targets and their criteria.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 200
{
  "data": [
    {
      "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "name": "Healthcare founders",
      "description": "Founders and CEOs of healthcare companies, 11–200 people, in Europe.",
      "color": "#8b87f7",
      "deal_size": 4000,
      "criteria": {
        "titles": [
          "Founder",
          "CEO"
        ],
        "industry": [
          "Hospitals and Health Care"
        ],
        "size": [
          "11–50",
          "51–200"
        ],
        "location": [
          "Europe"
        ]
      },
      "exclude": {
        "titles": [
          "Intern"
        ]
      },
      "people": 290
    }
  ]
}
POST/targetswrite

Create a target from criteria, or from a plain description that Netwarm's AI turns into criteria. The profile's people are matched again.

Body (JSON)
namestring2 to 4 words, e.g. SaaS CEOs. Required with criteria; built from the description otherwise.
descriptionstringWho they are, in plain words. Alone (no criteria), Netwarm's AI builds the criteria from it.
criteriaobjecttitles, seniority (Owner, C-level, VP, Director, Manager, Senior, Entry), industry, size (1–10 … 10,001+), location.
excludeobjectSame fields: values that rule someone out.
deal_sizenumber | nullTypical deal size in euros, for the pipeline value.
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 201
{
  "data": {
    "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "name": "Healthcare founders",
    "description": "Founders and CEOs of healthcare companies, 11–200 people, in Europe.",
    "color": "#8b87f7",
    "deal_size": 4000,
    "criteria": {
      "titles": [
        "Founder",
        "CEO"
      ],
      "industry": [
        "Hospitals and Health Care"
      ],
      "size": [
        "11–50",
        "51–200"
      ],
      "location": [
        "Europe"
      ]
    },
    "exclude": {
      "titles": [
        "Intern"
      ]
    },
    "people": 290
  }
}
PATCH/targets/{id}write

Change a target. criteria and exclude replace the whole lists when given. The profile's people are matched again.

Body (JSON)
namestring2 to 4 words, e.g. SaaS CEOs. Required with criteria; built from the description otherwise.
descriptionstringWho they are, in plain words. Alone (no criteria), Netwarm's AI builds the criteria from it.
criteriaobjecttitles, seniority (Owner, C-level, VP, Director, Manager, Senior, Entry), industry, size (1–10 … 10,001+), location.
excludeobjectSame fields: values that rule someone out.
deal_sizenumber | nullTypical deal size in euros, for the pipeline value.
Response · 200
{
  "data": {
    "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
    "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
    "name": "Healthcare founders",
    "description": "Founders and CEOs of healthcare companies, 11–200 people, in Europe.",
    "color": "#8b87f7",
    "deal_size": 4000,
    "criteria": {
      "titles": [
        "Founder",
        "CEO"
      ],
      "industry": [
        "Hospitals and Health Care"
      ],
      "size": [
        "11–50",
        "51–200"
      ],
      "location": [
        "Europe"
      ]
    },
    "exclude": {
      "titles": [
        "Intern"
      ]
    },
    "people": 290
  }
}
DELETE/targets/{id}write

Delete a target. Its people go to the next target that fits them.

Response · 200
{
  "data": {
    "id": "b935e243-dba2-41ba-ab9c-27f37434f4ed",
    "deleted": true
  }
}
GET/stagesread

The profile's pipeline stages, in order.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 200
{
  "data": [
    {
      "id": "03ba58e5-aec0-4219-9ec7-32fb83e041c8",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "key": "new",
      "name": "New",
      "color": "#d4d4d8"
    }
  ]
}

Reveals

GET/revealsread

The profile's reveals (gated resources) and their unlock counts.

Query
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 200
{
  "data": [
    {
      "id": "7d4e3f2a-1b0c-4d5e-8f9a-0b1c2d3e4f5a",
      "profile_id": "361aeda8-e471-4092-bb9c-d79bd7795162",
      "title": "The onboarding checklist",
      "description": "The 14 steps we use with every clinic.",
      "kind": "Checklist",
      "resource": "file",
      "url": "https://netwarm.com/r/onboarding-checklist",
      "published_at": "2026-10-10T09:00:00Z",
      "created_at": "2026-10-09T16:00:00Z",
      "unlocks": {
        "completed": 132,
        "started": 41
      }
    }
  ]
}
GET/reveals/{id}/unlocksleads

Who unlocked a reveal, newest first, with the contact details they gave.

Query
sincestringUnlocked on or after this date (ISO 8601).
limitintegerPage size, 1 to 200 (default 50).
cursorstringnext_cursor from the previous page.
Response · 200
{
  "data": [
    {
      "id": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
      "reveal_id": "7d4e3f2a-1b0c-4d5e-8f9a-0b1c2d3e4f5a",
      "status": "completed",
      "first_name": "Amara",
      "last_name": "Okafor",
      "email": "amara@lumenhealth.com",
      "phone": null,
      "linkedin_url": "https://www.linkedin.com/in/amara-okafor",
      "person_id": "0c33e15e-c42e-4071-af6d-c2ce076575f5",
      "at": "2026-10-26T11:40:00Z",
      "updated_at": "2026-10-26T11:40:00Z"
    }
  ],
  "next_cursor": null
}

Scheduling

GET/scheduled-postsposts

Your scheduled, published and failed LinkedIn posts, and whether your LinkedIn is connected.

Query
statusenumscheduled | publishing | published | failed
Response · 200
{
  "data": [
    {
      "id": "5b0d2c1e-8f1a-4b6e-9a3c-2f6e7d8c9b10",
      "text": "Three things I learned shipping onboarding to 10,000 patients…",
      "publish_at": "2026-11-03T08:00:00Z",
      "status": "scheduled",
      "first_comment": "Full write-up: https://example.com/onboarding",
      "topic": "Onboarding",
      "images": [
        "c1d2e3f4-0000-4a5b-8c9d-0e1f2a3b4c5d"
      ],
      "document": null,
      "video": null,
      "published_at": null,
      "url": null,
      "error": null,
      "created_at": "2026-10-27T10:00:00Z"
    }
  ],
  "linkedin": {
    "connected": true,
    "name": "Max Sawyer",
    "expires_at": "2026-12-20T10:00:00.000Z"
  }
}
POST/mediaposts

Start uploading a file for a post (JPG, PNG or GIF image, PDF, or MP4 video, 50 MB at most): returns a one-time upload URL. PUT the bytes there, then call POST /media/complete.

Body (JSON)
typerequiredenumimage/jpeg | image/png | image/gif | application/pdf | video/mp4
namerequiredstringThe file's name.
sizerequiredintegerIts size in bytes.
Response · 201
{
  "data": {
    "path": "042f20f4-…/acfd0aaf-…/1f2e…/funnel.png",
    "upload_url": "https://<project>.supabase.co/storage/v1/object/upload/sign/post-media/…?token=…",
    "method": "PUT",
    "headers": {
      "Content-Type": "image/png"
    },
    "expires_in": 7200,
    "next": "PUT the file's bytes to upload_url with this Content-Type, then POST /media/complete with path, type and name."
  }
}
POST/media/completeposts

Finish an upload: checks the stored file and returns its media id, for a scheduled post's images, document or video.

Body (JSON)
pathrequiredstringpath from POST /media.
typerequiredstringThe same type as in POST /media.
namerequiredstring
Response · 201
{
  "data": {
    "id": "c1d2e3f4-0000-4a5b-8c9d-0e1f2a3b4c5d",
    "type": "image/png",
    "name": "funnel.png",
    "compressed": false
  }
}
POST/media/from-urlposts

Attach a file from a public https URL in one step (an image, a PDF or an MP4, 50 MB at most): returns its media id.

Body (JSON)
urlrequiredstring
namestringA file name (default: from the URL).
Response · 201
{
  "data": {
    "id": "c1d2e3f4-0000-4a5b-8c9d-0e1f2a3b4c5d",
    "type": "image/png",
    "name": "funnel.png",
    "compressed": false
  }
}
POST/scheduled-postsposts

Schedule a LinkedIn post, with images, a PDF carousel or a video from POST /media, published on your connected LinkedIn at publish_at.

Body (JSON)
textrequiredstringThe post, up to 3,000 characters.
publish_atrequiredstringWhen to publish, ISO 8601 with a time zone, at least 2 minutes ahead.
first_commentstringPosted as the first comment right after the post.
topicstringOne of the profile's topics, by name.
imagesarrayUp to 9 image ids from POST /media.
documentstring | nullA PDF id from POST /media, posted as a document carousel.
document_titlestringThe carousel's title.
videostring | nullAn MP4 id from POST /media.
profilestringTracked profile id or LinkedIn handle. Default: the workspace's own profile.
Response · 201
{
  "data": {
    "id": "5b0d2c1e-8f1a-4b6e-9a3c-2f6e7d8c9b10",
    "text": "Three things I learned shipping onboarding to 10,000 patients…",
    "publish_at": "2026-11-03T08:00:00Z",
    "status": "scheduled",
    "first_comment": "Full write-up: https://example.com/onboarding",
    "topic": "Onboarding",
    "images": [
      "c1d2e3f4-0000-4a5b-8c9d-0e1f2a3b4c5d"
    ],
    "document": null,
    "video": null,
    "published_at": null,
    "url": null,
    "error": null,
    "created_at": "2026-10-27T10:00:00Z"
  }
}
PATCH/scheduled-posts/{id}posts

Edit a scheduled or failed post (a failed one goes back in the queue).

Body (JSON)
textstringThe post, up to 3,000 characters.
publish_atstringWhen to publish, ISO 8601 with a time zone, at least 2 minutes ahead.
first_commentstringPosted as the first comment right after the post.
topicstringOne of the profile's topics, by name.
imagesarrayUp to 9 image ids from POST /media.
documentstring | nullA PDF id from POST /media, posted as a document carousel.
document_titlestringThe carousel's title.
videostring | nullAn MP4 id from POST /media.
Response · 200
{
  "data": {
    "id": "5b0d2c1e-8f1a-4b6e-9a3c-2f6e7d8c9b10",
    "text": "Three things I learned shipping onboarding to 10,000 patients…",
    "publish_at": "2026-11-03T08:00:00Z",
    "status": "scheduled",
    "first_comment": "Full write-up: https://example.com/onboarding",
    "topic": "Onboarding",
    "images": [
      "c1d2e3f4-0000-4a5b-8c9d-0e1f2a3b4c5d"
    ],
    "document": null,
    "video": null,
    "published_at": null,
    "url": null,
    "error": null,
    "created_at": "2026-10-27T10:00:00Z"
  }
}
DELETE/scheduled-posts/{id}posts

Cancel a scheduled or failed post. Published posts stay on LinkedIn.

Response · 200
{
  "data": {
    "id": "5b0d2c1e-8f1a-4b6e-9a3c-2f6e7d8c9b10",
    "cancelled": true
  }
}

MCP server

The same data and actions as tools for AI assistants (Claude, ChatGPT, Cursor…). Add a custom connector with this address and sign in with your Netwarm account (OAuth), or send an API key.

Server address
https://app.netwarm.com/api/mcp
Terminal
# Claude Code
claude mcp add --transport http netwarm https://app.netwarm.com/api/mcp

# With an API key
claude mcp add --transport http netwarm https://app.netwarm.com/api/mcp \
  --header "Authorization: Bearer nw_live_…"
Toolschanges data
whoamiThe workspace, its plan and usage this month, the permissions granted, and the tracked LinkedIn profiles.read
get_ready_listThe Ready list: people in a target who engaged in the last 90 days and are still in New, warmest first. Start here for outreach.read
search_peopleEveryone who engaged with a profile, filtered and sorted: by warmth, target, stage, triage status, Ready, text search, or last engagement date.read
get_personEverything about one person: who they are, their LinkedIn profile (about, jobs), warmth, target, stage, their recent engagements with the comment text, and the timeline (notes, stage changes).read
get_person_engagementsA person's engagements with the profile, newest first, with more history than get_person.read
get_openersNetwarm's coach: suggested first DMs and LinkedIn connection request notes for this person, written from what they engaged with. fresh=true writes new ones.read
list_new_engagementsLikes, comments, reposts and reveal unlocks as they were captured, oldest first since a date (default: the last 24 hours). Pass next_cursor to continue.read
list_postsThe profile's LinkedIn posts, newest first, with stats and topic.read
get_post_performanceOne post and who engaged with it: counts by kind, warmth and target, and the warmest people.read
audience_summaryWhat happened over the last days: engagements, new and newly hot people, warmth per target, top posts and topics.read
list_targets_and_stagesThe profile's targets (with their criteria), pipeline stages and post topics.read
list_revealsThe profile's reveals (gated resources people unlock with their details) and their unlock counts.read
list_reveal_leadsWho unlocked a reveal, newest first, with the contact details they gave. Needs the contact details permission.leads
update_personMove a person to another stage or target, triage them (approved, dismissed, snoozed for snooze_days, or active to undo), or save their email or phone (needs the contact details permission).write
update_peopleThe same stage, target or triage change on up to 100 people of one profile, by person id (from get_ready_list or search_people). Confirm the list with the user first.write
add_noteAdd a note to a person's timeline in Netwarm.write
edit_noteChange a note you wrote (its id is in get_person's timeline).write
delete_noteDelete a note you wrote.write
create_targetCreate a target: the kind of people to reach. Give a plain description alone and Netwarm's AI builds the criteria, or give a name and criteria. People are matched to it right away.write
update_targetRename a target or change its description, criteria, exclusions or deal size. criteria and exclude replace the whole lists when given.write
delete_targetDelete a target. Its people go to the next target that fits them. Confirm with the user first.write
attach_media_from_urlFetch a public https file (a JPG, PNG or GIF image, a PDF, or an MP4 video, 50 MB at most) for a LinkedIn post. Returns a media id for schedule_post's images, document or video.posts
list_scheduled_postsYour scheduled, published and failed LinkedIn posts, and whether your LinkedIn is connected.posts
schedule_postSchedule a post on your connected LinkedIn at publish_at (at least 2 minutes ahead), optionally with images, a PDF carousel or a video (media ids from attach_media_from_url). It will be published publicly at that time: confirm the text, media and time with the user first.posts
edit_scheduled_postChange the text, time, first comment or topic of a scheduled or failed post.posts
cancel_scheduled_postCancel a scheduled or failed post. Published posts stay on LinkedIn.posts
daily_outreach_brief prompt: who to reach out to today, with context and a suggested first message for each.