Run HeyReach LinkedIn outreach from a workflow: campaigns, lead lists, leads, senders, inbox and blacklist.
HeyReach ships in the w6w first-party pack. It declares 30 actions, 3 health checks, and the host runs its code in a sandbox that never sees the credential.
io.w6w.heyreachHeyReach is a LinkedIn outreach and automation platform for sales teams, and this app exposes the half of it a workflow can act on: the leads, lists and campaigns that outreach runs on.
Leads are looked up by profile URL, tagged, and pushed in bulk into either a lead list or directly into a campaign paired with the sending LinkedIn account — which is HeyReach’s own unit of work, since a lead is always worked by a specific sender. Campaigns can be listed, read, created as drafts, started, paused, resumed, and their sequence read back, so a workflow can drive outreach state rather than only inspect it.
Around that, the app covers the supporting surfaces a scaling operation needs: the connected LinkedIn sender accounts and their live connection status, the lead and company lists those campaigns draw from, inbox conversations and message sending, workspace-wide statistics per day and per campaign, webhook registration for reacting to replies and connections instead of polling, and the blacklist that keeps leads out of every campaign.
Authorization is HeyReach’s own single X-API-KEY header, and the app ships a health check that reads the API’s own auth answer rather than trusting an HTTP status alone.
Three routes to the same 30 actions. The Workflow tab is generated from HeyReach's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.
blacklist-add-leads Blacklist up to 100 leads by LinkedIn member id, profile URL, email or full name, so no campaign in this workspace contacts them (POST /api/public/blacklist/AddLeads).
blacklist-get-leads List the blacklisted leads in this workspace, newest first, filtered by search text or how the entry resolved (POST /api/public/blacklist/GetLeads).
campaign-add-leads Add leads to a campaign, each paired with the LinkedIn account that will work it (POST /api/public/campaign/AddLeadsToCampaignV2).
campaign-create Create a campaign in DRAFT status, optionally with its schedule and sequence (POST /api/public/campaign/Create). Start it separately with Start Campaign.
campaign-get Fetch one campaign with its status, progress statistics, sender accounts and exclusion rules (GET /api/public/campaign/GetById).
campaign-get-leads List the leads queued in a campaign, with their per-lead campaign, connection and message status (POST /api/public/campaign/GetLeadsFromCampaign).
campaign-get-sequence Read a campaign's sequence node object — the exact shape the campaign runs (GET /api/public/campaign/GetCampaignSequence).
campaign-list List campaigns with their status, progress and sender accounts, filtered by keyword, status or account (POST /api/public/campaign/GetAll).
campaign-start Activate a DRAFT campaign so its sequence begins running (POST /api/public/campaign/StartCampaign).
check-api-key Verify the connection's HeyReach API key (GET /api/public/auth/CheckApiKey). Returns `connected: false` when HeyReach rejects the key, and throws when the API itself fails.
inbox-get-conversations List LinkedIn conversations, cursor-paged, filtered by sender, campaign, lead, tag or read state (POST /api/public/inbox/GetConversationsV3).
inbox-send-message Send a message into an existing LinkedIn conversation (POST /api/public/inbox/SendMessage).
lead-add-tags Add tags to a lead by profile URL or LinkedIn id, optionally creating tags that do not exist yet (POST /api/public/lead/AddTags).
lead-get Fetch the LinkedIn profile details HeyReach holds for a lead, by profile URL (POST /api/public/lead/GetLead).
lead-get-tags Read the tags on a lead. HeyReach's document publishes no response schema for this operation, so the body is returned verbatim (POST /api/public/lead/GetTags).
linkedin-account-get Fetch one sender LinkedIn account by id, including its per-action limits (GET /api/public/li_account/GetById).
linkedin-account-list List the workspace's sender LinkedIn accounts, with their active flag and auth validity (POST /api/public/li_account/GetAll).
linkedin-account-status Read one sender account's live connection status, failure reason, and Sales Navigator / Recruiter authentication (GET /api/public/li_account/GetAccountStatus/{accountId}).
list-add-leads Add up to 100 leads to a lead list, creating or updating each one (POST /api/public/list/AddLeadsToListV2).
list-create Create an empty lead or company list (POST /api/public/list/CreateEmptyList).
list-get Fetch one lead or company list by id, with its lead count and the campaigns that use it (GET /api/public/list/GetById).
list-get-all List lead and company lists, filtered by keyword, type or the campaigns that use them (POST /api/public/list/GetAll).
list-get-leads Read the leads in a lead list, filtered by keyword, profile URL or LinkedIn id and by when they were added (POST /api/public/list/GetLeadsFromList).
stats-get-by-campaign Read outreach statistics for a date window broken down per campaign, per day and aggregated (POST /api/public/stats/GetOverallStatsByCampaign).
stats-get-overall Read outreach statistics for a date window, per day and aggregated, optionally scoped to particular senders or campaigns (POST /api/public/stats/GetOverallStats).
webhook-create Register a webhook for one HeyReach event type, optionally limited to specific campaigns (POST /api/public/webhooks/CreateWebhook).
webhook-list List the workspace's webhooks with their event type, target URL and campaigns (POST /api/public/webhooks/GetAllWebhooks).
A workflow step names the app and the action, and the editor fills in the
connection when you pick one. This is the Step shape from the
workflow spec, carrying HeyReach's real ids.
{
"manifestVersion": "2",
"name": "heyreach-example",
"steps": [
{
"id": "blacklist-add-leads",
"uses": {
"app": "io.w6w.heyreach",
"action": "blacklist-add-leads",
"connection": "conn_YOUR_CONNECTION_ID"
},
"with": {
"leads": "<leads>"
}
}
]
}blacklist-add-leads blacklist-get-leads campaign-add-leads campaign-create campaign-get +25 more actions available
Every app-specific value here is a blank you have to fill in. An
app action is reached through the connection that authenticates it, so the
address is a connection id, not the app id — and connections belong to your account,
so a public page cannot know yours. Create one for HeyReach, then fill in
the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the
parameters that action declares. The call itself is real — the shape is transcribed
from the studio's own snippet builder, which prints the same kind of blanks — but
nothing in it is specific to HeyReach. The Workflow tab is where this app's
real ids are.
npm install @w6w/sdkyarn add @w6w/sdkpnpm add @w6w/sdkdeno add npm:@w6w/sdkimport { W6wClient, isActionRun } from "@w6w/sdk";
// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();
const envelope = await client.run({
urn: "conn_YOUR_CONNECTION_ID",
action: "blacklist-add-leads",
payload: {
leads: "<value>",
},
});
if (isActionRun(envelope)) console.log(envelope.value); npm install -g @w6w/cli w6w run conn_YOUR_CONNECTION_ID --action blacklist-add-leads --payload '{"leads":"<value>"}' Give an AI agent HeyReach — without giving it HeyReach's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.
One tool call{
"name": "w6w_invoke",
"arguments": {
"ref": "app:io.w6w.heyreach#blacklist-add-leads",
"input": {
"leads": "<leads>"
}
}
}
Every tool names its target with a single ref. The
app: form above doesn't name a connection at all — the
host resolves which of the caller's HeyReach connections to sign
with, and refuses rather than guesses when the answer is ambiguous.
The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.
Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.
Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.
HeyReach's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.
The MCP surface is part of the hosted platform. HeyReach itself is MIT, and the runtime that executes it is source-available (FSL).
HeyReach declares its own checks, so its health is a property of the app rather than something the host guesses at.
Calls GET /api/public/auth/CheckApiKey with this connection's key and reads the API's own auth answer. A 401 carrying `Missing API key`/`Invalid API key` is proof HeyReach is reachable — the credential itself is the derived auth:api-key check's verdict.
No machine-readable status surface: status.heyreach.io is real but UptimeRobot-hosted, and its only JSON routes are keyed by a token scraped from the page itself.
Not exposed: HeyReach's document declares a 429 on every operation but no rate-limit header and no quota endpoint.