> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revyops.com/llms.txt
> Use this file to discover all available pages before exploring further.

# HeyReach

> Connect HeyReach to RevyOps to track LinkedIn connections, messages, InMails, and lead tags.

## Overview

HeyReach is RevyOps's LinkedIn outreach integration. It lives under the **LinkedIn** channel in Integrations (separate from the email sequencer integrations like Instantly or SmartLead) and is currently the only LinkedIn platform RevyOps supports.

Once connected, RevyOps ingests LinkedIn campaign events from HeyReach — connection requests, messages, InMails, replies, and lead tags — in near real time and writes them to each contact's LinkedIn message timeline. It can also push your RevyOps Do Not Contact list back into HeyReach, and pull a one-time historical import of every lead in your HeyReach lists.

## Prerequisites

* An active HeyReach account with an API key (**HeyReach Settings → API → Copy API Key**)
* Admin access to the client workspace in RevyOps
* Your RevyOps `client_id` (find it under **Settings → Workspace**) if you're setting up the webhook manually

## Connecting Your HeyReach Account

<Steps>
  <Step title="Open the HeyReach integration">
    In RevyOps, go to **Integrations**, switch to the **LinkedIn** channel, and open **HeyReach**.
  </Step>

  <Step title="Paste your API key">
    Copy your key from **HeyReach Settings → API → Copy API Key** and paste it into the **HeyReach API Key** field, then click **Verify & Connect**. RevyOps validates the key live against HeyReach before continuing.
  </Step>

  <Step title="Webhook registration">
    If the key is valid, RevyOps attempts to register the webhook automatically (see below). If automatic registration fails, you'll be dropped into manual setup instead.
  </Step>
</Steps>

## Webhook Setup

RevyOps registers a webhook per HeyReach event type, all pointed at one URL:

```
https://api.revyops.com/api/public/heyreach-webhook/{client_id}
```

Replace `{client_id}` with your RevyOps workspace ID.

<Steps>
  <Step title="RevyOps creates the webhook automatically">
    After your API key verifies, RevyOps calls HeyReach's webhook API and registers one webhook per event type below, all pointed at your client's webhook URL. You don't need to do anything in the HeyReach dashboard for this step.
  </Step>

  <Step title="Re-checks for existing webhooks first">
    Before creating anything, RevyOps lists your account's existing webhooks and skips any event type that's already registered against the same URL. Reopening the integration panel or retrying setup won't create duplicate webhooks.
  </Step>

  <Step title="Fall back to manual setup if needed">
    If automatic registration fails (for example, an API key with restricted permissions), RevyOps shows an error and drops you into a manual step: copy the webhook URL, then in HeyReach go to **Settings → Webhooks → Add Webhook** and paste it in yourself.
  </Step>
</Steps>

RevyOps registers these HeyReach event types against your webhook URL:

| Event Type                        |
| --------------------------------- |
| `CONNECTION_REQUEST_SENT`         |
| `CONNECTION_REQUEST_ACCEPTED`     |
| `MESSAGE_SENT`                    |
| `INMAIL_SENT`                     |
| `INMAIL_REPLY_RECEIVED`           |
| `EVERY_MESSAGE_REPLY_RECEIVED`    |
| `FOLLOW_SENT`                     |
| `LIKED_POST`                      |
| `VIEWED_PROFILE`                  |
| `CAMPAIGN_COMPLETED`              |
| `LEAD_TAG_UPDATED`                |
| `LEAD_AUTO_TAGGED_INTERESTED`     |
| `LEAD_AUTO_TAGGED_NOT_INTERESTED` |
| `LEAD_AUTO_TAGGED_GENERIC`        |

Of these, RevyOps actively processes message events (connection/message/InMail sent, replies) and `LEAD_TAG_UPDATED` as full timeline/disposition updates. `FOLLOW_SENT`, `LIKED_POST`, `VIEWED_PROFILE`, and `CAMPAIGN_COMPLETED` are received but currently only used to upsert a basic contact record (name, LinkedIn URL, and any list custom fields) — they don't write timeline entries.

<Warning>
  Auto-tagging a lead as Interested or Not Interested in HeyReach may not reliably update that lead's status in RevyOps — this path hasn't been verified end-to-end. Manually tagging a lead (or tagging via a HeyReach automation rule) does work reliably and is the path described below. If you rely on HeyReach's built-in auto-tagging, verify in your own workspace that the resulting status actually shows up on the contact in RevyOps before depending on it.
</Warning>

<Note>
  RevyOps registers `EVERY_MESSAGE_REPLY_RECEIVED` and deliberately does **not** register `MESSAGE_REPLY_RECEIVED`. The latter only fires on a lead's first reply and registering both used to double-log that first reply. `EVERY_MESSAGE_REPLY_RECEIVED` alone captures every reply with no gaps.
</Note>

## Agency Setup (Global Webhook)

For agencies managing multiple client workspaces, register a single agency-wide webhook instead of one per client:

```
https://api.revyops.com/api/public/global-heyreach-webhook/{agency_id}
```

This single webhook fans events out to the correct client automatically, using two different routing strategies depending on the event:

* **Message events** (connection/message/InMail sent, replies) are routed by matching the HeyReach campaign name against each client's **Campaign Mapping** keywords.
* **`LEAD_TAG_UPDATED`** carries no campaign name, so it's routed by looking up which of the agency's HeyReach-connected clients already has a LinkedIn message history with that lead's profile URL. If more than one client has messaged the same lead, the event is fanned out to all of them. Auto-tag events are intended to route the same way, but see the note above about their reliability — an auto-tag event can also silently fail to route to any client.

## Status & Label Classification

HeyReach tag values are managed manually inside RevyOps — there's no live lookup of tag names from your HeyReach account. When a new tag arrives on a webhook event that RevyOps hasn't seen before, it's automatically registered under **Other Statuses** so you can classify it later.

From the HeyReach integration panel, click **Edit Labels** to sort tags into three buckets:

* **Interested Statuses** — leads with these tags count as interested in your reports
* **Blocked Statuses** — leads with these tags are pulled from active HeyReach campaigns (see below)
* **Other Statuses** — everything else, shown for visibility but not otherwise acted on

You can also add a label manually before HeyReach has ever sent it.

A separate toggle, **auto-map label to contact status**, controls whether assigning an interested or other tag also overwrites the contact's `contact_status` field in RevyOps, rather than only updating its disposition/label on the LinkedIn message timeline. This is enabled by default when you complete setup.

## Cross-Platform Do Not Contact Sync

RevyOps unifies Do Not Contact signals from every connected platform into one suppression list, then pushes it out to HeyReach so a lead suppressed anywhere is never contacted from HeyReach again.

* **Real-time sync**: when a contact is marked DNC anywhere in RevyOps — including by receiving a HeyReach tag you've classified as a Blocked status — RevyOps calls HeyReach's `GetCampaignsForLead` and `StopLeadInCampaign` APIs to pull that lead out of every HeyReach campaign where their status is `Pending` or `InSequence`.
* **Historical sync**: contacts marked DNC before the integration was connected aren't picked up by the real-time path. Use the **Sync Historical DNC List** button in the integration panel to push those retroactively.
* This sync can be turned off per integration with the DNC sync toggle in the integration panel.

## Historical Contact Backfill

RevyOps can do a one-time import of every lead across every HeyReach list into your workspace as LinkedIn contacts. This is triggered by a RevyOps super-admin, not from the client-facing Integrations page — ask your RevyOps contact to run it once your HeyReach API key is connected.

What it does:

* Paginates every HeyReach list and every lead in it, creating or updating a LinkedIn contact for each (name, company, position, headline, location, LinkedIn photo, and any HeyReach custom fields).
* If a lead has an email address on file in HeyReach, RevyOps also creates/finds a matching email contact and merges it with the LinkedIn contact into a single Person record, so the same prospect shows up as one entity across channels.
* Progress (lists completed, contacts processed, contacts/sec, ETA) is persisted as the backfill runs, so a failed or interrupted run resumes from where it left off rather than starting over.

## Data Mapped

Message and reply events write an entry to the contact's LinkedIn message timeline:

| HeyReach Field                                                                   | RevyOps Field                                                                            |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `lead.profile_url`                                                               | Contact LinkedIn URL                                                                     |
| `lead.first_name` / `lead.last_name`                                             | Contact first/last name                                                                  |
| `event_type`                                                                     | Message type (connection sent/accepted, message sent, InMail sent, message/InMail reply) |
| `sender.id` / `sender.full_name` / `sender.email_address` / `sender.profile_url` | Sender fields on the message                                                             |
| `campaign.id` / `campaign.name`                                                  | Campaign ID / name                                                                       |
| `recent_messages[].message` or `recent_inmails[].message`                        | Message text                                                                             |
| `recent_inmails[].subject`                                                       | InMail subject                                                                           |
| `conversation_id`, `correlation_id`, `external_reference`                        | Stored as-is for dedup/reference                                                         |
| `lead.lists[].custom_fields`                                                     | Contact custom fields                                                                    |

`LEAD_TAG_UPDATED` events (and, when they route correctly, the auto-tag events — see the note above) update the contact's disposition or label rather than writing a message:

| HeyReach Field               | RevyOps Behavior                                                           |
| ---------------------------- | -------------------------------------------------------------------------- |
| `updated_tags` / `auto_tag`  | Matched against your Interested / Blocked / Other classification           |
| `tag_action: ADDED`          | Sets the matching disposition (interested) or label (other) on the contact |
| `tag_action: DELETED`        | Clears the matching disposition or label                                   |
| Tag matches a Blocked status | Triggers DNC sync to HeyReach (if enabled)                                 |

## Managing Webhooks

* **No duplicates on reconnect**: before registering anything, RevyOps checks your account's existing webhooks and skips any event type already pointed at your webhook URL, so re-running setup never creates duplicate registrations.
* **Automatic disable on archive or reconfigure**: when a client is archived, or when you click reconfigure on an already-connected HeyReach integration, RevyOps finds the webhooks pointed at that client's URL and disables them in HeyReach.
* Listing and deleting individual webhooks by ID is available to RevyOps admins as an internal support tool, not from the client-facing integration panel.

## Troubleshooting

<AccordionGroup>
  <Accordion title="API key shows as invalid">
    RevyOps checks the key against HeyReach's `CheckApiKey` endpoint. A `401`/`403` response means the key is wrong or has been revoked — generate a new one from **HeyReach Settings → API**.
  </Accordion>

  <Accordion title="Automatic webhook setup failed">
    This is usually an API key without webhook-management permissions. Fall back to the manual step: copy the webhook URL from the integration panel and add it yourself under **HeyReach Settings → Webhooks**.
  </Accordion>

  <Accordion title="Tag events aren't updating contact status">
    Tag events only route correctly on the agency-wide webhook if the lead already has HeyReach message history with that client — RevyOps has no campaign name to match on for tag events, so it looks up ownership by matching the lead's LinkedIn URL against clients that have already messaged them. If the lead was tagged before HeyReach ever sent a message/connection event for them, the event has nowhere to route and is dropped. Adding a per-client webhook doesn't help here: a client mapped to the agency webhook has its per-client webhook events skipped by design, to avoid double-processing. Make sure the lead has at least one prior HeyReach message event logged for that client first.
  </Accordion>

  <Accordion title="A new tag shows up under Other Statuses instead of Interested/Blocked">
    This is expected — RevyOps doesn't know how to classify a tag it hasn't seen before, so it lands in Other Statuses until you reclassify it from **Edit Labels**.
  </Accordion>
</AccordionGroup>
