# Send Embers leads to Zapier

URL: https://useembers.com/help/integrations/zapier/
Category: Integrations
Plan: Solo and above
Updated: 2026-10-27
Last verified: 2026-10-27

> Set up Zapier from the Integrations page in three steps, then verify the signature in a Code step, map the lead fields, and send each lead onward.

Zapier puts an Embers lead into tools Embers has no destination for: a sheet, a sequencer, a CRM other than HubSpot, Salesforce, Pipedrive, or Attio. You point a [signed Embers webhook](/help/integrations/webhooks/) at a Zapier trigger, check the signature, and map the fields.

> **Warning: Solo and above, administrators only**
>
> Webhook endpoints require Solo or above, and only a workspace admin can create them. Embers has no Zapier app: on **Integrations** in the sidebar (`/integrations`), Zapier is a row on the **Build your own** shelf, and its **Set up** adds the HTTPS webhook for you. A member sees "Administrators only" with **Read the guide**, and below Solo the row reads "Solo and above" with **See plans**.

## Before you start

- A Zapier plan that includes Webhooks by Zapier, and Code by Zapier if you will verify signatures.
- Somewhere for the lead to go once Zapier has it.
- A free endpoint slot. A workspace can have up to 10 webhook endpoints.

## Connect Zapier

### Open Set up Zapier

In Embers, open **Integrations** in the sidebar and choose **Set up** on the **Zapier** row. A side sheet, **Set up Zapier**, opens with three steps.

### Copy a hook URL from Zapier

The sheet's first step: "In Zapier, start a Zap with Webhooks by Zapier, then Catch Hook, and copy its URL." Copy the hook URL, not the address of the page you are on.

If the Zap will verify signatures, as below, choose **Catch Raw Hook** instead of **Catch Hook**. Catch Hook parses the body before your steps see it, and the signature only matches the exact bytes Embers sent.

### Add the endpoint

The second step: "Paste the URL here. Embers sends it every new lead." Paste it under **Webhook URL** and choose **Add endpoint**. Embers creates an endpoint named Zapier, subscribed to **New ICP lead** (`lead.created`) only: one event per newly qualified lead, carrying the engagement that qualified them.

The sheet then shows the signing secret once, with **Copy**, and says Zapier does not need it. Copy the `whsec_` secret now if you will verify signatures; it is not shown again.

### Send a test so Zapier records the shape

The third step: "Send a test, then map name, company and email in your next Zap step." While Zapier waits for a request, choose **Send test**. The sample arrives as `webhook.test` with `data.is_test` set to `true` and a lead shaped like a real one, so Zapier records the fields and your filter can drop the sample later.

The row now reads "Sending to Zapier" with **Manage**, which opens the Webhooks page. Edit the endpoint there to add **New engagement** (`lead.engagement.added`), which fires each time an existing lead engages again; add it only if the Zap handles repeats of the same person.

### Verify the signature in a Code step

This step needs **Catch Raw Hook**. Add **Code by Zapier** with **Run JavaScript**. Under Input Data, map `body` to the raw body, `id`, `timestamp`, and `signature` to the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers from the trigger, and paste the signing secret as `secret`. Then use this code:

```js
const crypto = require('crypto');

const key = Buffer.from(inputData.secret.replace(/^whsec_/, ''), 'base64');
const expected = crypto
  .createHmac('sha256', key)
  .update(`${inputData.id}.${inputData.timestamp}.${inputData.body}`, 'utf8')
  .digest();

const age = Math.abs(Date.now() / 1000 - Number(inputData.timestamp));
const verified =
  age <= 300 &&
  String(inputData.signature || '')
    .split(' ')
    .some((entry) => {
      const received = Buffer.from(entry.split(',')[1] || '', 'base64');
      return received.length === expected.length && crypto.timingSafeEqual(received, expected);
    });

const event = verified ? JSON.parse(inputData.body) : {};
const data = event.data || {};

output = {
  verified,
  event_id: inputData.id,
  type: event.type || '',
  is_test: data.is_test === true,
  lead: data.lead || {},
};
```

Add **Filter by Zapier** after it: continue only if `verified` is true, and `is_test` is false once the Zap is live. [Verify webhook signatures](/help/integrations/verify-webhook-signatures/) explains each part of the check.

While you build, the trigger's sample may be more than five minutes old, so the step reports `verified: false`. Send a fresh test from Embers (**Send test** in the endpoint's **...** menu on the Webhooks page) and test the step again.

### Map the fields

Map from the Code step's `lead` output, or from `data.lead` in the trigger if the Zap uses Catch Hook without the check. The [webhook payload reference](/help/integrations/webhook-payload-reference/) lists every field; these are the ones most Zaps use:

| Field | Use it for |
| --- | --- |
| `linkedin_urn` | The key to find or update a person. Stable when a vanity URL changes |
| `name` | Full name. There is no first or last name field |
| `title`, `company` | Role and employer |
| `score`, `icp_confidence` | Both 0 to 100, as in the app |
| `icp_reason` | One sentence on why they matched |
| `contact.email`, `contact.phone` | Only when `contact.included` is true |

There is no grade field. Derive it from `score` the way [lead scoring](/help/leads/how-scoring-works/) does: A at 80 or above, B at 60, C at 40, D at 20, F below that.

## What reaches the Zap

A lead event fires when the person qualifies: a score above zero, an ICP match or a manual approval, and a company that is not blocklisted. Delivery rules do not filter webhooks, so add Zapier filters for anything narrower.

Delivery is at least once, so the Zap can see the same event twice. Deduplicate on `event_id` for exact repeats and on `linkedin_urn` for the person.

## Troubleshooting

**The Zap runs twice for one person.** Either the same event was retried, or a `lead.created` was followed by a `lead.engagement.added`. Filter or deduplicate on `event_id` and `linkedin_urn`.

**`verified` is always false.** The Input Data is not the raw body (use Catch Raw Hook, not Catch Hook), the secret was rotated, or the sample is older than five minutes.

**Embers paused the endpoint.** The Zapier row reads "Paused" with **Fix**. Zapier answered with a `4xx`, or eight attempts failed over about 6.3 days. Follow [a webhook endpoint is paused](/help/troubleshooting/webhook-endpoint-paused/).

**Email and phone are empty.** Contact fields carry only what Embers has stored, and only on a paid plan after the trial. See [reveal a lead's email and phone](/help/outreach/lead-enrichment-and-contact-info/).

## Related

- [Webhook payload reference](/help/integrations/webhook-payload-reference/): Every field in every event.

- [Send Embers leads to a Make scenario](/help/integrations/make/): The same recipe with a Make scenario.

- [A webhook endpoint is paused](/help/troubleshooting/webhook-endpoint-paused/): Resume delivery after Zapier rejects a request.

## Frequently asked questions

**Is there an Embers app in Zapier's directory?**

No. Zapier receives the same signed HTTPS webhook every receiver gets, through a Webhooks by Zapier trigger.

**Catch Hook or Catch Raw Hook?**

The setup sheet says Catch Hook, which is enough to receive and map leads. Catch Hook parses the body before your steps see it, though, and the signature can only be checked against the exact bytes Embers sent. Use Catch Raw Hook when the Zap verifies signatures.
