TrueMetriks documentation: Webhooks https://docs.truemetriks.com/integrations/webhooks/ Generated from the TrueMetriks documentation. Paste the whole of this file into ChatGPT, Claude, Gemini, Cursor or any other AI. I use TrueMetriks, a server-side tracking and conversion attribution platform. It tracks my website visitors, ties every sale back to the ad that produced it, and sends those conversions back to my ad platforms. Help me with this specific task: Webhooks. Receive conversions into TrueMetriks from any tool, and send your conversions with full attribution to any URL - GoHighLevel, a CRM, or a custom backend. HOW TO GUIDE ME - This file has three parts: THE GUIDE is today's task, BACKGROUND is a prerequisite to confirm with me before you start THE GUIDE, not optional reading, and LINK MAP is the only place a real link comes from. - Ask me ONE thing at a time and wait for my answer before moving on. - At the start of every step, ask me: "do you want the written steps, or the video?" If I pick the video, give me the exact link from the LINK MAP at the bottom and wait until I tell you I have watched it. If I pick the written steps, give them to me from this file. - Only ever give me links that appear in the LINK MAP below. Never invent a URL, never guess an anchor, and if I ask for something that has no link here, say so and point me at https://docs.truemetriks.com/ instead. - Never ask me for my password, my API key, my MCP key, or any card details. You are reading me the steps; I am the one clicking in my own account. - Confirm each step worked before starting the next one. - Keep it short. I am doing this while looking at my screen, not reading an essay. - Everything you need is in this file. You do not need to browse the web. =============================================================================== THE GUIDE: Webhooks https://docs.truemetriks.com/integrations/webhooks/ =============================================================================== Webhooks move conversions in and out of TrueMetriks. Open **Settings > Integrations > Webhooks** and you get two tabs: **Receive webhooks** brings conversions in, **Send webhooks** pushes them back out with attribution attached. ## Receive webhooks Bring conversions in from any tool - Zapier, a WordPress form, GoHighLevel, or your own backend. Each webhook gets its own secret URL. Paste that URL into the tool and it sends Leads, booked calls, Purchases or custom events into this site's analytics. ### Step 1 - Create a receiving webhook On the **Receive webhooks** tab, click **Add receiving webhook**. Name it after the tool that will send to it, then pick the **event type**: - **Lead**, **Schedule**, or **Purchase** for a standard conversion. - **Custom event name** for your own event (for example `ApplicationSubmitted`). Custom events show in analytics and can trigger sending webhooks. You cannot change the event type later, because tools send to this URL expecting it. If you need a different type, create a second webhook. Click **Create webhook**. ### Step 2 - Copy the URL into your tool Copy the webhook URL and paste it into the tool that will send to it. That is the whole setup. The URL is the only credential, there are no API keys. ### Step 3 - Send a payload POST JSON to the URL (form-encoded works too). We read the common field names, and we find them inside nested payloads too, so most tools work with no setup at all: ```bash curl -X POST 'https://q.your-domain/api/webhooks/in/YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"email":"jane@example.com","first_name":"Jane","value":49.99,"currency":"USD"}' ``` The fields we read are `email`, `phone`, `first_name`, `last_name`, `value`, `currency` and `order_id`. Anything else you send is kept as event properties. If it works you get **HTTP 200** back, with a summary of what we found. The event then shows in your analytics like any other integration. It only gets credited to an ad if we can tell which visitor it came from, and that part is worth getting right, so it has its own section next. ### Make sure the conversion lands on the right visitor When a conversion arrives by webhook, we have to work out which visitor it came from. If we cannot, the sale still counts and the money is still yours, but it lands on a person with no history, so no ad gets the credit. **Most of the time this takes care of itself.** Nearly every tool sends us an email, and nearly every buyer types their email somewhere on your site, so the two line up and the conversion joins the right journey. Nothing for you to do. Capturing the email as early as you have it makes this even more reliable - see [`window.tmIdentify`](https://docs.truemetriks.com/platform-installs/custom/#windowtmidentifyemail-traits) on the Custom install guide. #### When email is not enough Two things break the email match, and both are worth knowing about: - **They never typed their email on your site.** They browsed, then paid somewhere you do not control, so no visit of theirs carries that address. Nothing to match against. - **They typed it two different ways.** One spelling at a booking, another at checkout, and to us that is two different people. We do repair the obvious misspellings, but only so far. We fix a short, fixed list of provider typos, one way only: an email arriving as `gmial.com` is also tried as `gmail.com`. An email that arrives spelled **correctly** is never checked against misspellings, because that could merge two different people. And a typo before the `@` (`davd@` for `david@`) is not fixed at all. So if your conversions keep landing with no visit attached, email alone is not reaching those buyers, and the next section is how you fix it. #### The fix - send us the visitor id This is optional, and most sites never need it. But when email is not landing, it is the one thing that always works, because there is nothing to match and nothing to guess. Everything else is us working out who someone probably is. This is us being told. Every visitor we track carries a cookie on your own domain called `_evid`. Read it in the browser, drop it into a hidden field on your form or checkout, and send it in the payload alongside the email you already send. You can name the field any of these: `evid`, `_evid`, `tm_evid`, `visitor_id`, `tm_visitor_id`, `tm_id`. Add the hidden field to your form: ```html ``` Then fill it from the cookie at the moment the form is submitted: ```html ``` Your payload then carries one extra line: ```json { "email": "jane@example.com", "value": 49.99, "currency": "USD", "tm_evid": "ev_k3f9q2_a1b2c3d4" } ``` **Read the cookie in the browser. Never bake it into the page.** If a CDN caches the page holding your hidden field, one visitor's `_evid` gets saved into the HTML and handed to everybody who loads it after them, and all of their conversions pile onto that one person. We trust the visitor id above everything else, so nothing later catches the mistake. The snippet above is safe because it reads the cookie as the form is sent, in that visitor's own browser. #### Send the click id if you have it `fbclid` and `gclid` sit in the landing-page URL, so you can put them in a hidden field the same way, with no cookie to read. Another option when the visitor id is awkward to get at. You can name the field any of these: `fbclid`, `gclid`, `click_id`, `tm_click_id`. #### What we try, in order - **Visitor id** - exact, no guessing. - **Click id** - `fbclid` or `gclid`, matched against the click ids we stored for that visitor. - **Email** - matched against the email attached to their visits. We stop at the first one that finds a real visit. For most sites the email on its own gets there, which is why nothing above is required. Sending more than one is safe either way - they do not clash, the strongest one wins. #### Why a conversion shows no visit A conversion with no visit attached means nothing in that payload matched a visitor we had seen. It still counts and the money is still yours, but with no journey behind it there is no ad to credit. Adding the visitor id fixes it from then on. It cannot go back and fix conversions that already arrived, so the sooner it is in, the sooner your attribution fills in. ### Also fire to connected ad platforms Each receiving webhook has an **Also fire to connected ad platforms** toggle, off by default. Turn it on and the events also go to Facebook, TikTok, GA4 and Google Ads, just like a native integration. Your analytics get them either way. Custom events work too: `Call Booked` reaches your ad platforms under that same name. #### Send a custom event to Facebook as a Custom Conversion Once a custom-named receiving webhook exists, its event name shows up in Facebook's **Create custom event** dialog, under a **Custom webhook events** group. Pick it there and we create a Facebook Custom Conversion with that name, so Facebook can optimize and report on it. We store it as an `OTHER`-type conversion, so it is never mistaken for a Lead or a Purchase, and it fires once per event with no duplicates. Facebook only gets the event while that webhook's **Also fire to connected ad platforms** toggle is on. See the [Facebook integration guide](https://docs.truemetriks.com/ad-integrations/facebook/) for the dialog. ### Duplicate protection We count each conversion once, even when two tools report it: - **Leads, Schedules and custom events:** the same email and event type counts once per day, across every source. A webhook and a native integration (say [Typeform](https://docs.truemetriks.com/form-integrations/typeform/)) reporting the same lead will not double-count. - **Purchases** are checked on email, order and amount instead, so two genuinely different orders on the same day both count. If a native integration already reports the same event type for this site, the webhook shows an amber warning as a reminder. ### Recent deliveries Every receiving webhook keeps a **Recent deliveries** log: the last 25 receipts, 5 per page. Each one shows what happened (`accepted`, `deduped`, `parse error`, `oversized` or `ignored`) plus a preview of the payload, so you can see exactly what arrived. ### Rotating or removing a webhook There is no regenerate button, on purpose. To change a URL, delete the webhook and create a new one, which gets a new URL. Deleting one stops its URL working straight away. Payloads over 256 KB are rejected. ## Send webhooks Push conversions out of TrueMetriks to any URL - a CRM, GoHighLevel, or your own backend. Every Lead, Schedule and Purchase goes to your URL with the person's first and last touch, sessions and paid channel attached. Leads reach GoHighLevel with the whole journey on them. ### Step 1 - Create a sending webhook Switch to the **Send webhooks** tab and click **Add sending webhook**. Fill in the dialog: - **Name** - a label for you (for example "GoHighLevel contacts"). - **Webhook URL** - where we POST the payload. Must be `https`. - **Send this event** - pick ONE event from the dropdown: **Lead**, **Schedule**, **Purchase**, or one of **your custom events** (your Facebook Custom Conversions and custom-named receiving webhooks). One sending webhook sends one event. To send another event to the same place, create a second one. Click **Create webhook**. ### Step 2 - Copy the signing secret We show a **signing secret** once, right after you create the webhook. Copy it now, you will not see it again. Every delivery is signed so your receiver can check it came from us. The signature rides in an `X-TrueMetriks-Signature: t=,v1=` header, built from the request body and your signing secret. Checking it is optional - receivers that do not check signatures (GoHighLevel inbound webhook triggers, for example) can ignore the header. ### Step 3 - Know the timing A delivery fires about **75 seconds** after the event arrives. The wait is on purpose: identity and attribution settle first, so the payload carries the full journey. To test the wiring without waiting, click **Send test** and a sample payload arrives in about 15 to 30 seconds. The test uses this webhook's real event name (`Call Booked`, not a generic `Test`), so your receiver sees exactly what a live delivery looks like. It is still marked with `"test": true` at the top level (and `event.properties.test: true`) so nothing downstream counts it as a real conversion, and in the **Recent deliveries** log the row reads `Test: Call Booked`. On a test send `contact` is null and `attribution` is sample data. ### The payload Every delivery is a JSON POST. `event.type` is `Lead`, `Schedule` or `Purchase` for standard events, and `Custom` for your own, so your receiver can branch on it: ```json { "api_version": "2026-07-09", "webhook": { "destination_id": "wdst_...", "attempt": 1, "sent_at": "2026-07-11T10:17:27.718Z" }, "site": { "id": 1, "domain": "example.com" }, "event": { "type": "Purchase", "name": "Purchase", "id": "evt_...", "time": "...", "value": 49.99, "currency": "USD", "source": "webhook", "properties": {} }, "contact": { "email": "jane@example.com", "phone": null, "first_name": "Jane", "last_name": null }, "attribution": { "first_touch": { "source": "google", "medium": "cpc", "campaign": "brand-search", "channel": "Paid Search", "referrer": "https://www.google.com/", "landing_url": "example.com/landing" }, "last_touch": { "source": "facebook", "medium": "paid", "campaign": "retargeting", "channel": "Paid Social", "referrer": "https://facebook.com/", "landing_url": "example.com/offer" }, "touches": 7, "sessions": 3, "days_to_convert": 7, "paid": true, "paid_channel": "Paid Social" } } ``` On real events `contact` carries the person's actual email, phone, and name, and `attribution` their real journey. On test sends `contact` is null and `attribution` is sample data. A custom event delivers the same shape, with `event.type` set to `Custom` and `event.name` set to your event name: ```json { "api_version": "2026-07-09", "webhook": { "destination_id": "wdst_...", "attempt": 1, "sent_at": "2026-07-17T10:17:27.718Z" }, "site": { "id": 1, "domain": "example.com" }, "event": { "type": "Custom", "name": "Call Booked", "id": "evt_...", "time": "...", "source": "webhook", "properties": {} }, "contact": { "email": "jane@example.com", "phone": null, "first_name": "Jane", "last_name": null }, "attribution": { "first_touch": { "source": "google", "medium": "cpc", "campaign": "brand-search", "channel": "Paid Search" }, "last_touch": { "source": "facebook", "medium": "paid", "campaign": "retargeting", "channel": "Paid Social" }, "touches": 4, "sessions": 2, "days_to_convert": 1, "paid": true, "paid_channel": "Paid Social" } } ``` A **test** delivery of that same webhook looks identical but adds a top-level `"test": true` and `event.properties.test: true`, so your receiver can drop it. ### Reliability - **Stable IDs, so you can drop repeats.** Each delivery carries an `X-TrueMetriks-Delivery: dlv_` header and an `event.id` field, so your receiver can spot a retry. The `X-TrueMetriks-Event` header carries the event name. - **Automatic retries**, spaced further apart each time, when a delivery fails. - **Dead URLs pause themselves.** A URL that keeps failing is paused for you. The card shows why, with an **Unpause** button once your receiver is fixed. - **Recent deliveries** shows every attempt (`delivered`, `queued`, `sending` or `failed`) with the HTTP code. ## Related - Send conversions into GoHighLevel: [GoHighLevel install guide](https://docs.truemetriks.com/platform-installs/gohighlevel/) - Fire conversions from your own site: [Custom install guide](https://docs.truemetriks.com/platform-installs/custom/) - Capture the email on your site so webhook conversions match: [window.tmIdentify](https://docs.truemetriks.com/platform-installs/custom/#windowtmidentifyemail-traits) - Forward conversions to your ad platforms: [Facebook CAPI](https://docs.truemetriks.com/ad-integrations/facebook/), [Google Ads](https://docs.truemetriks.com/ad-integrations/google-ads/), [GA4](https://docs.truemetriks.com/ad-integrations/ga4/), [TikTok](https://docs.truemetriks.com/ad-integrations/tiktok/) =============================================================================== BACKGROUND: Test your integration https://docs.truemetriks.com/platform-installs/test-your-integration/ =============================================================================== ## Video walkthrough VIDEO: How to test your TrueMetriks integration -> https://docs.truemetriks.com/platform-installs/test-your-integration/#video-walkthrough ## Quick checklist 1. **Open your live site in an incognito window.** This skips any admin-tracking exclusions and looks like a real visitor. 2. **Browse a few pages.** Click around two or three product or landing pages. 3. **Submit a test form** if you have one (Contact Form 7, WPForms, Gravity Forms, [Typeform](https://docs.truemetriks.com/form-integrations/typeform/), [Calendly](https://docs.truemetriks.com/form-integrations/calendly/), etc). 4. **Place a test order** if you run a store. Most platforms support a sandbox / test mode for this. Use a discount code if you want the order total to be small. ## Where to look in your dashboard Open your TrueMetriks dashboard and click the **green live counter** in the top right of the page header. It opens a tray of every visitor active in the past five minutes. If your incognito browse appears there in real time, the tracker is firing correctly. ## Still not working? Most issues are listed on the [Troubleshooting](https://docs.truemetriks.com/troubleshooting/common-issues/) page - check there first for common causes (CNAME not propagated, tracker blocked by an ad blocker, webhook URL stale, etc.). If Troubleshooting does not solve it, [contact us](https://truemetriks.com/contact) and we will help you debug it. =============================================================================== LINK MAP Use these exact URLs. Anything ending in a # anchor opens on that section or that video. Nothing else is a valid link. Never invent a URL and never guess an anchor. Webhooks The guide ................................... https://docs.truemetriks.com/integrations/webhooks/ Receive webhooks ............................ https://docs.truemetriks.com/integrations/webhooks/#receive-webhooks Step 1 - Create a receiving webhook ......... https://docs.truemetriks.com/integrations/webhooks/#step-1-create-a-receiving-webhook Step 2 - Copy the URL into your tool ........ https://docs.truemetriks.com/integrations/webhooks/#step-2-copy-the-url-into-your-tool Step 3 - Send a payload ..................... https://docs.truemetriks.com/integrations/webhooks/#step-3-send-a-payload Make sure the conversion lands on the right visitor https://docs.truemetriks.com/integrations/webhooks/#make-sure-the-conversion-lands-on-the-right-visitor Also fire to connected ad platforms ......... https://docs.truemetriks.com/integrations/webhooks/#also-fire-to-connected-ad-platforms Duplicate protection ........................ https://docs.truemetriks.com/integrations/webhooks/#duplicate-protection Recent deliveries ........................... https://docs.truemetriks.com/integrations/webhooks/#recent-deliveries Rotating or removing a webhook .............. https://docs.truemetriks.com/integrations/webhooks/#rotating-or-removing-a-webhook Send webhooks ............................... https://docs.truemetriks.com/integrations/webhooks/#send-webhooks Step 1 - Create a sending webhook ........... https://docs.truemetriks.com/integrations/webhooks/#step-1-create-a-sending-webhook Step 2 - Copy the signing secret ............ https://docs.truemetriks.com/integrations/webhooks/#step-2-copy-the-signing-secret Step 3 - Know the timing .................... https://docs.truemetriks.com/integrations/webhooks/#step-3-know-the-timing The payload ................................. https://docs.truemetriks.com/integrations/webhooks/#the-payload Reliability ................................. https://docs.truemetriks.com/integrations/webhooks/#reliability Related ..................................... https://docs.truemetriks.com/integrations/webhooks/#related Test your integration The guide ................................... https://docs.truemetriks.com/platform-installs/test-your-integration/ Video walkthrough ........................... https://docs.truemetriks.com/platform-installs/test-your-integration/#video-walkthrough Quick checklist ............................. https://docs.truemetriks.com/platform-installs/test-your-integration/#quick-checklist Where to look in your dashboard ............. https://docs.truemetriks.com/platform-installs/test-your-integration/#where-to-look-in-your-dashboard Still not working? .......................... https://docs.truemetriks.com/platform-installs/test-your-integration/#still-not-working VIDEO, How to test your TrueMetriks integration https://docs.truemetriks.com/platform-installs/test-your-integration/#video-walkthrough