Webhooks
Webhooks let Mitr tell your other tools the moment something happens — a purchase, a signup, any custom event you already track. Instead of checking your dashboard or polling an API, the event shows up wherever you need it, seconds after it happens.
What you can build with it
A few real setups people use this for:
- Get a Slack ping on every sale. Point a webhook at a
Slack incoming-webhook URL, filter to your
purchaseevent, and your team sees revenue land in real time — no dashboard-refreshing. - Sync signups into a CRM. Fire on
signup, forward the payload to a small serverless function, and create the lead in HubSpot/Pipedrive/Airtable automatically instead of exporting CSVs. - Feed a data warehouse. If you already run BigQuery, Snowflake, or a Postgres warehouse, a webhook is the simplest way to stream Mitr events in alongside your other data, instead of waiting on a scheduled export.
- Trigger no-code automation. Point a webhook at Zapier, Make, or n8n and build flows — a welcome email on signup, a Notion row per conversion — without writing a backend yourself.
- Client reporting for agencies. Managing analytics for multiple client sites? Route each client's key conversions to their own Slack channel or dashboard, instead of them asking you to check.
How it works
In your dashboard, add a webhook with a destination URL and (optionally) the specific event names you care about — leave it blank to receive everything. From then on, every matching event sends an HTTP POST with a JSON body to that URL.
Delivery is decoupled from tracking: a webhook attempt never happens in the same request as the event being tracked, so a slow or temporarily unreachable endpoint on your end never slows down your site or app. If a delivery fails, Mitr retries automatically with increasing delays (1 minute, 5 minutes, 30 minutes, 2 hours, then 12 hours) before giving up — you can see the full delivery history, including any errors, right in the dashboard.
Setting one up
From the dashboard: Settings → Webhooks → Manage → Add webhook. Paste your destination URL, optionally list the event names to filter to, and save. Use the Send test button to fire an immediate test payload and confirm your endpoint is set up correctly before relying on it.
Ready-to-use templates
Add webhook now opens a template picker first — pick a common set of event names instead of typing them from scratch, or choose "Choose events myself" for the blank form. You still paste your own destination URL either way; a template only pre-fills which events to filter to, and every pre-filled event name stays a removable chip you can edit before saving.
| Template | Event names |
|---|---|
| New signups | signup_completed |
| Revenue events | purchase_completed, subscription_started, refund_issued |
| Churn & cancellations | subscription_cancelled, refund_issued |
| Email opens | email_open |
Every event name above is a naming convention, not a
reserved keyword — a webhook only ever fires on an event your own app
actually tracks, so pick the template closest to what you already send
(or already plan to) and adjust the names to match. email_open
is the one exception: it's a real event Mitr's backend emits itself,
from the tracking pixel, once you've
registered an Email app in the Integration Hub.
Payload shape
{
"eventId": "3fae1c9e-...",
"eventType": "purchase",
"time": "2026-08-02T14:03:11.000Z",
"path": "/checkout/success",
"userHash": "a1b2c3d4...",
"metadata": { "value": 49.99, "currency": "USD" },
"siteId": "...",
"workspaceId": "..."
} userHash is already the same anonymised/hashed identifier
Mitr stores internally — never a raw user ID, email, or device
identifier. metadata is whatever custom properties you sent
with the original event, already scanned and hashed for accidental PII
at ingest.
Verifying requests came from Mitr
Every request includes an X-Mitr-Signature header — a
hex-encoded HMAC-SHA256 of the exact request body, keyed with the
signing secret shown in your webhook's settings. Recompute it on your
end and compare before trusting the payload:
import hmac, hashlib
def verify(request_body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), request_body, hashlib.sha256).hexdigest()
received = signature_header.removeprefix("sha256=")
return hmac.compare_digest(expected, received) const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
} Limits
Free tier: 1 webhook endpoint, with delivery history kept for 7 days. Paid tiers: up to 5 endpoints, with delivery history kept as long as your plan's own data retention window. See pricing for details.