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

# Zapier

> Send booked calls, qualified leads, and won deals from any tool to DATALYR with a Zapier webhook.

When you finish, a Zap sends each sales stage from your booking tool or CRM to DATALYR, matched by email to the visit.

Use this when your tool has no DATALYR source. For HubSpot, see [HubSpot](/integrations/hubspot).

## What Zapier sends

You choose the trigger. DATALYR receives the event name in the body.

| Your trigger | DATALYR event | `event_id` | Money role |
| - | - | - | - |
| A call or demo is booked | `call_booked` | `zapier_<booking ID>_call_booked` | None |
| A lead is qualified | `lead_qualified` | `zapier_<lead ID>_lead_qualified` | None |
| A deal is won | `deal_won` | `zapier_<deal ID>_deal_won` | Contract value. Never revenue |

Only `deal_won` carries a value: the deal `amount`. Its `cash_role` is `non_cash_fact`, so no revenue report counts it. Cash comes from a payment source such as [Stripe](/revenue/stripe) or [Commas](/integrations/commas).

Each `event_id` is stable per record and stage. A Zap retry is a duplicate, not a second conversion. See [Duplicates](/api-reference/ingest#duplicates).

Events arrive with source `api`.

## Before you start

| Requirement | Detail |
| - | - |
| DATALYR access | Owner or admin, to create the write key |
| Write key | The `Write key` from **Settings → API**. See [API keys](/account/api-keys) |
| Zapier | A plan with multi-step Zaps and Webhooks by Zapier |
| Web tracking | The [tracking script](/getting-started/install-web-tracking) on your landing pages |

## The request

| Item | Value |
| - | - |
| Method | `POST` |
| URL | `https://ingest.datalyr.com/track` |
| Header | `X-API-Key: dk_YOUR_WRITE_KEY` |
| Header | `Content-Type: application/json` |

Replace each placeholder such as `{{email}}` with the matching field from your trigger. Keep `currency` and `cash_role` as written.

<CodeGroup>
  ```json call_booked theme={null}
  {
    "event": "call_booked",
    "user_id": "{{email}}",
    "event_id": "zapier_{{booking_id}}_call_booked",
    "properties": {
      "email": "{{email}}",
      "phone": "{{phone}}",
      "lead_source": "zapier"
    }
  }
  ```

  ```json lead_qualified theme={null}
  {
    "event": "lead_qualified",
    "user_id": "{{email}}",
    "event_id": "zapier_{{lead_id}}_lead_qualified",
    "properties": {
      "email": "{{email}}",
      "lead_source": "zapier"
    }
  }
  ```

  ```json deal_won theme={null}
  {
    "event": "deal_won",
    "user_id": "{{email}}",
    "event_id": "zapier_{{deal_id}}_deal_won",
    "timestamp": "{{close_date}}",
    "properties": {
      "email": "{{email}}",
      "value": "{{amount}}",
      "currency": "USD",
      "deal_id": "zapier_{{deal_id}}",
      "lead_source": "zapier",
      "cash_role": "non_cash_fact"
    }
  }
  ```
</CodeGroup>

The **Zapier** card in **Sources** has the same bodies.

<Warning>
  Keep the write key in Zapier only. Anyone holding it can write events into your workspace.
</Warning>

## Build the Zap

Build one Zap per stage.

<Steps>
  <Step title="Add the trigger">
    Pick the app and the trigger for the stage, such as a new booking or a deal moved to won.
  </Step>

  <Step title="Find the email">
    If the trigger has no email field, add a search step that finds the contact.
  </Step>

  <Step title="Add the request">
    Add **Webhooks by Zapier** with the **Custom Request** event. Set **Method** to `POST`.
  </Step>

  <Step title="Set the URL and headers">
    Paste the URL. Add the `X-API-Key` and `Content-Type` headers.
  </Step>

  <Step title="Paste the body">
    Paste the stage's body into **Data**. Map each placeholder to a field from an earlier step.
  </Step>

  <Step title="Test the step">
    Run the step test. Confirm the response contains `"success": true`.
  </Step>
</Steps>

<Tip>
  The **POST** event works too. Set **Payload Type** to `json` and **Unflatten** to `yes`. Name the nested keys `properties__email`, `properties__value`, and so on.
</Tip>

Map a real record ID into each `event_id`. A fixed text value makes every later request a duplicate.

## How leads match to ad clicks

Zapier events match by email alone. `user_id` and `properties.email` carry it.

An event joins an ad click only when DATALYR already knows that email from a tracked visit. That happens through an `identify()` call on your form, an [iClosed](/integrations/iclosed) or [Calendly](/integrations/calendly) booking, or a payment source. See [Identity](/advanced/identity).

## Set up conversion rules

Zapier has no starter rules. Create each rule in **Conversions** with **manage rules**.

| Trigger event | Destination | Value |
| - | - | - |
| `call_booked` | Meta `Schedule` | Set a fixed value: what a booked call is worth |
| `lead_qualified` | Meta `Lead` | Set a fixed value: what a qualified lead is worth |
| `deal_won` | Google Ads conversion action, or Meta `Purchase` | Dynamic, from `value` |

Meta and TikTok optimize on a 7-day window. Send them the stage that happens within a week of the click.

## Verify

1. Open your landing page in a private window with `?utm_source=doctest`.
2. Submit your form or book a call with a test email address.
3. Trigger the Zap for that record.
4. Open **Events**. Confirm the stage's row with source `api`.
5. Open **Users**. Find the test email. Confirm the `pageview` and the stage sit on one user.

## When it does not work

| Symptom | Cause | Check | Fix |
| - | - | - | - |
| The request returns `401` | The write key is wrong, or the header name is wrong | The `X-API-Key` header | Copy the `Write key` from **Settings → API** |
| The request returns `400` | The body is not valid JSON, or `event` or `user_id` is empty | The request in the Zap history | Map every placeholder. Remove stray quotes |
| Every request after the first returns `Duplicate event detected` | `event_id` holds a fixed value | The `event_id` in the Zap history | Map the record ID into `event_id` |
| `properties` arrives as flat keys | The **POST** event without **Unflatten** | The event in **Events** | Use **Custom Request**, or set **Unflatten** to `yes` |
| Events arrive, no campaign on them | DATALYR has never seen this email on a tracked visit | The email in **Users** | Call `identify()` on your form with the email |
| `deal_won` shows in revenue reports | `cash_role` was removed from the body | The `properties` object | Restore `"cash_role": "non_cash_fact"` |

## Next

* [HubSpot](/integrations/hubspot): the HubSpot triggers and the workflow route.
* [Ingest API](/api-reference/ingest): every field and status code on `/track`.
* [Lead generation](/use-cases/lead-generation): choose the stage to optimize toward.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.