API review

HeyReach API review

Cloud LinkedIn outreach sequencer built for many sender accounts: per-sender pricing, unified inbox, a full REST API including campaign build and launch, webhooks, and an official hosted MCP. API and MCP are on every plan. Best for multi-sender LinkedIn campaigns with automatic sender rotation and hard per-account limits.

Verified 25 Oct 2026 · 88 endpoints listed · Official MCP server

What a call costs

The actions you pay for, as HeyReach prices them.

ActionCostPer
Multi-brand white-label (Unlimited)$500per add-on brand

Pricing, plan by plan

US dollars, as HeyReach's pricing page shows them on 25 Oct 2026. Monthly and annual billing are shown apart.

Free tier Growth: 14-day free trial, no card, with 3 LinkedIn accounts; Agency and Unlimited: 30-day free trial on request (pricing FAQ). Early stage program: heavily discounted plan if under $250,000 ARR, fewer than 5 people and not yet a customer (price not published).

Growth

$79/mo

billed monthly

$64/mo

billed annually

per sender per month (1-9 senders); quarterly $72/seat/mo ($214 billed quarterly), yearly $64/seat/mo ($759 billed yearly); Growth is capped at 50 senders; 100 enrichment credits per sender (a one-time allocation, top-ups available); unlimited campaigns; API, webhooks and MCP included

API included
Plan details

add senders

Growth, 10-50 senders (volume rate)

$59/mo

billed monthly

$48/mo

billed annually

per sender per month once 10 or more senders are selected (page calculator: rate2 $59, tierBreak 10, max 50); yearly price = ceil($59 x 0.8) as computed by the page; quarterly ceil($59 x 0.9) = $54

API included
Plan details

add senders

Agency (25 senders)

$999/mo

billed monthly

$800/mo

billed annually

25 senders; quarterly $900/mo ($2,698 billed quarterly), yearly $800/mo ($9,591 billed yearly); 1,000 enrichment credits (one-time); white-label included; bring your own proxies; API, webhooks and MCP included

API included

Agency (50 senders)

$1,399/mo

billed monthly

$1,120/mo

billed annually

50 senders; 1,000 enrichment credits (one-time); white-label; bring your own proxies. $1,399/mo from the page JSON-LD offer; quarterly ceil($1,399 x 0.9) = $1,260/mo and yearly ceil($1,399 x 0.8) = $1,120/mo as computed by the page script

API included

Unlimited

$2,999/mo

billed monthly

$2,399/mo

billed annually

unlimited senders under a fair-use cap of 300 senders; quarterly $2,699/mo ($8,097 billed quarterly), yearly $2,399/mo ($28,790 billed yearly); 3,000 enrichment credits (one-time); multi-brand white-label add-on $500 each

API included

Done for you

Custom quote

managed service, custom pricing

Rate limits

300 requests per minute, all workspace-API requests share one limit; 429 when exceeded.

More on limitsLess

The Organization API has its own separate 300/min limit.

How to get an API key

HeyReach uses API key. The steps below follow HeyReach's own docs.

  1. Create a HeyReach account. API access starts on the Growth, 10-50 senders (volume rate) plan.
  2. Workspace API key from HeyReach settings (keys never expire, can be deleted or deactivated). Organization API (workspaces, users, keys) needs a separate Organization API key from Organization settings, admins only.
  3. Send it with every request: header (X-API-KEY).
  4. Make a first call: CheckApiKey, Check If your API key is working. Keep the key in an environment variable, never in the command.
    curl -X GET "https://api.heyreach.io/api/public/auth/CheckApiKey" \
      -H "X-API-KEY: $HEYREACH_API_KEY"

Where the docs live

WhatWhere
Documentationdocs.heyreach.io/hey-reach-api
API referencedocs.heyreach.io/llms.txt
OpenAPI specdocs.heyreach.io/openapi.json
llms.txtdocs.heyreach.io/llms.txt
Base URLhttps://api.heyreach.io/api/public
MCP serverhttps://mcp.heyreach.io/mcp
SDKsheyreach CLI

Strengths and limits

Where it fits

  • Multi-sender LinkedIn campaigns with automatic sender rotation and hard per-account limits
  • Programmatic campaign build: list -> leads -> campaign/Create -> UpdateSequence -> StartCampaign
  • Reply capture via webhooks into a CRM or Supabase
  • LinkedIn + email multichannel through native Instantly / Smartlead / EmailBison steps

Where it falls short

  • Email sending itself (it hands leads to Instantly, Smartlead or EmailBison)
  • Clients who have churned off it
  • Restructuring a running campaign's sequence: the structure is frozen once started

Worth knowing

  • The published OpenAPI servers entry is broken (''), and its paths start with '//api/public'. The real base is api.heyreach.io/api/public.
  • Workspace keys and Organization keys are different. Workspace-management endpoints reject the normal key. Each has its own 300/min limit.
  • Connecting LinkedIn accounts by API (Connect / ConnectWithCookies) requires the separate 'Account Login API' feature.
  • Lead adds are capped at 100 per request; use the V2 endpoints, which return added/updated/failed counts.
  • GetConversationsV2 hits a deep-paging limit on large inboxes; V3 is cursor-based.
13 moreShow fewer
  • Terms s.2.4(a)-(b) bar renting, providing access to or sublicensing the Services to a third party and incorporating them into any product or service provided to a third party; s.2.5 lets HeyReach monitor and limit API calls if it believes usage breaches the agreement or harms the service.
  • Our experience: variables are SINGLE braces {FIRST_NAME}; {{double}} ships the literal braces to the prospect. Always set fallbackMessage.
  • Our experience: campaign/Create needs linkedInUserListId (not listId); the sequence is a nested node tree, not a steps array; every node after an action needs actionDelay >= 3 HOUR or UpdateSequence returns 400/500.
  • Our experience: AddLeadsToListV2 can return addedLeadsCount:0, failedLeadsCount:0 and add nothing (2 of 519 silently dropped). Always reconcile the list count and URL-decode /in/<slug> before diffing.
  • Our experience: custom-field shapes differ. List write is customUserFields [{name,value}], campaign write is [{fieldName,fieldValue}], read-back is top-level customFields [{name,value}].
  • Our experience: the sequence structure is frozen once a campaign has ever started; only payload text can be edited while PAUSED.
  • Our experience: the sender check endpoint is /li_account/GetAll (/linkedinaccount/GetAll 404s); verify authIsValid and isValidNavigator before InMail steps. A campaign silently goes FAILED when all senders disconnect.
  • Our experience: webhook recent_messages is an oldest-first rolling window that can carry several new messages and repeats old ones with slightly different creation_time. Dedupe on content + direction within ~90 s; is_reply is the authoritative direction.
  • Docs now list POST /campaign/StartCampaign. Our 2026-08-04 note said there was no REST start (we launched via the heyreach CLI), so this endpoint is newer than that note.
  • GET /auth/CheckApiKey returns 200 with an EMPTY body (content-length 0); the status code is the only signal. Responses carry no X-RateLimit-* headers, so the 300/min budget must be tracked client-side.
  • Docs pages and the OpenAPI spec are generated and mark nearly every body field 'required' (e.g. keyword on li_account/GetAll); our GetAll calls with keyword '' worked. Treat the required flags as unreliable.
  • Enrichment credits are a ONE-TIME allocation per subscription (100 per Growth sender, 1,000 Agency, 3,000 Unlimited), not a monthly refill; top-ups are sold separately.
  • campaign/GetAll items: the live response carries excludeInOtherCampaigns, excludeHasOtherAccConversations, excludeContactedFromSenderInOtherCampaign, excludeFromLeadBlacklist, excludeFromCompanyBlacklist, organizationUnitId and startedAt, while the docs' item type still lists excludeAlreadyMessagedGlobal / excludeFirstConnection* / excludeNoProfilePicture. Code against the live field names.

Our take

We run LinkedIn campaigns on HeyReach for several clients and build them through the API in a fixed order: create the list, add the leads, create the campaign, then set the sequence. What we learned: variables use single braces such as {FIRST_NAME} and double braces ship literal braces to the prospect, every step after an action needs a delay of at least 3 hours, and the add-leads call can accept a request while adding nobody, so we reconcile the list count and send one test message to a team profile before every launch. Reply webhooks carry a rolling window of recent messages, so the same message arrives more than once and has to be deduplicated.

Who should use it

Use HeyReach for
Multi-sender LinkedIn campaigns with automatic sender rotation and hard per-account limits
Look elsewhere for
Email sending itself (it hands leads to Instantly, Smartlead or EmailBison)

If HeyReach is not the answer

Other LinkedIn outreach tools in this directory, each with its own review.

Before you build

Four things to settle first, each read off HeyReach's own pages.

  • Confirm the API is on your planAPI access starts on the Growth, 10-50 senders (volume rate) plan. Free tier: Growth: 14-day free trial, no card, with 3 LinkedIn accounts.
  • Keep the key out of your codeAPI key. It is sent as: header (X-API-KEY).
  • Design around the rate limit300 requests per minute, all workspace-API requests share one limit; 429 when exceeded.
  • Know the catch before you scaleThe published OpenAPI servers entry is broken (''), and its paths start with '//api/public'. The real base is api.heyreach.io/api/public.

Want us to build it for you?

Tell us what you want HeyReach to do in your stack. We will show you how we would wire it into your data, outbound or CRM, and what we would check first.

Read from heyreach.io/pricing, docs.heyreach.io/llms.txt and docs.heyreach.io/hey-reach-api. Verified 25 Oct 2026.

All 88 endpointsFor developers: method, path, what it does and what it costs.

Base URL: api.heyreach.io/api/public

Bulk and async: Lead add 100 per request (V2 returns added/updated/failed counts); list/campaign lead reads up to 1000 per page.

Webhooks: One eventType per webhook, optionally filtered to campaignIds. Delivered payload event_type arrives lowercase snake_case. Must deactivate (isActive:false) before delete. Events: CONNECTION_REQUEST_SENT, CONNECTION_REQUEST_ACCEPTED, MESSAGE_SENT, MESSAGE_REPLY_RECEIVED, INMAIL_SENT, INMAIL_REPLY_RECEIVED, FOLLOW_SENT, LIKED_POST, VIEWED_PROFILE, CAMPAIGN_COMPLETED, LEAD_TAG_UPDATED, EVERY_MESSAGE_REPLY_RECEIVED

88 endpoints
MethodPathWhat it doesCost
GET/auth/CheckApiKeyCheckApiKey, Check If your API key is working.Not stated
POST/li_account/GetAllGetAll, Get a paginated collection of all LinkedIn accounts. Get up to 100 accounts per request.Not stated
GET/li_account/GetByIdGetById, Get a LinkedIn account by idNot stated
DELETE/li_account/RemoveAccount/{accountId}RemoveAccount, Remove a LinkedIn account. With force=true the account is first removed from all active campaigns before deletion.Not stated
POST/li_account/ConnectConnect, Connect a LinkedIn account using username and password. Returns immediately; poll GetAccountStatus to track progress.requires the 'Account Login API' feature
POST/li_account/ConnectWithCookiesConnectWithCookies, Connect a LinkedIn account using session cookies. Member id is auto-extracted by authenticating with the cookies.requires the 'Account Login API' feature
GET/li_account/GetAccountStatus/{accountId}GetAccountStatus, Get the current connection status of a LinkedIn account. Cached for 10 seconds.Not stated
POST/li_account/SubmitPinSubmitPin, Submit a PIN for an account awaiting PIN verification. 409 if the account is not awaiting a PIN.Not stated
POST/li_account/ReconnectReconnect, Reconnect an existing LinkedIn account using its stored credentials. Returns immediately; poll GetAccountStatus.Not stated
POST/li_account/ReloginSalesNavigatorReloginSalesNavigator, Re-authenticate the Sales Navigator session. Account must be connected and have an active Sales Navigator subscription.Not stated
POST/li_account/ReloginRecruiterReloginRecruiter, Re-authenticate the Recruiter session. Account must be connected and have an active LinkedIn Recruiter subscription.Not stated
POST/li_account/ResyncResync, Resync the profile of a LinkedIn account. Returns immediately; poll GetAccountStatus.Not stated
GET/li_account/GetProxyCountriesGetProxyCountries, Get all supported proxy country codes usable when connecting an account.Not stated
GET/li_account/GetAccountProxy/{accountId}GetAccountProxy, Get the proxy assigned to a LinkedIn account. Returns only the country code for platform-managed proxies, or full connection details for custom proxies.Not stated
POST/li_account/UpdateProxyUpdateProxy, Update the proxy assigned to a LinkedIn account. Provide either proxyCountryCode (platform-managed) or customProxy (your own).Not stated
POST/li_account/UpdateInboxConfigurationUpdateInboxConfiguration, Update the inbox scrape configuration. Controls how far back inbox messages are synced when the account connects.Not stated
GET/list/GetByIdGetById, Get a lead or company list by IdNot stated
POST/list/GetAllGetAll, Get a paginated collection of all company and lead lists. Get up to 100 lists per request.Not stated
POST/list/GetLeadsFromListGetLeadsFromList, Get a paginated collection of leads from a lead list. Get up to 1000 leads per request.Not stated
DELETE/list/DeleteLeadsFromListDeleteLeadsFromList, Deletes the specified leads from a lead list.Not stated
DELETE/list/DeleteLeadsFromListByProfileUrlDeleteLeadsFromListByProfileUrl, Deletes the specified leads from a lead list by LinkedIn profile url.Not stated
POST/list/GetCompaniesFromListGetCompaniesFromList, Get a paginated collection of companies from a company list. Get up to 1000 companies per request.Not stated
POST/list/AddLeadsToListAddLeadsToList, Add leads to a lead list. Add up to 100 leads per request.Not stated
POST/list/AddLeadsToListV2AddLeadsToListV2, Add leads to a lead list. Add up to 100 leads per request.Not stated
POST/list/GetListsForLeadGetListsForLead, Retrieves the lists associated with a specific lead.Not stated
POST/list/CreateEmptyListCreateEmptyList, Create an empty lead or company list. You pass the list name and the list type (USER_LIST or COMPANY_LIST).Not stated
PATCH/list/UpdateLeadCustomFields/lists/{listId}/leads/custom-fieldsUpdateLeadCustomFields, Update (upsert) custom fields on a lead in a list. Keys are field names, values are field values.Not stated
POST/lead/GetLeadGetLead, Retrieves the details of a specific lead based on their LinkedIn profile URL.Not stated
POST/lead/AddTagsAddTags, Adds tags to the lead. Existing tags will not be changed.Not stated
POST/lead/GetTagsGetTags, Gets the tags for a lead.Not stated
POST/lead/ReplaceTagsReplaceTags, Removes the existing tags and replaces them with the new tags.Not stated
POST/lead_tags/CreateTagsCreateTags, Create one or multiple tags for your workspace. You can assign these tags to leads.Not stated
POST/campaign/GetAllGetAll, Get a paginated collection of all campaigns. Get up to 100 campaigns per request.Not stated
GET/campaign/GetByIdGetById, Get a Campaign by idNot stated
POST/campaign/ResumeResume, Resumes the specified campaign.Not stated
POST/campaign/PausePause, Pauses the specified campaign.Not stated
POST/campaign/AddLeadsToCampaignAddLeadsToCampaign, Add leads to a campaign. Add up to 100 leads per request.Not stated
POST/campaign/AddLeadsToCampaignV2AddLeadsToCampaignV2, Add leads to a campaign. Add up to 100 leads per request.Not stated
POST/campaign/StopLeadInCampaignStopLeadInCampaign, Stops the progression of a lead in a campaign.Not stated
POST/campaign/GetLeadsFromCampaignGetLeadsFromCampaign, Gets the leads in a campaign (the "Lead Analytics" screen); shows only Pending leads about to start executing actions.Not stated