Skip to content
Pixel Relay

Webhooks

Have Pixel Relay post new leads, failed deliveries and a daily summary to your own URL, signed and retried.

3 min read Updated 21 Oct 2026

A webhook is a URL on your side that Pixel Relay posts to when something happens on a website. Use it to alert a sales team about a new lead, open a ticket when Meta refuses events, or feed a daily report.

Add a webhook

  1. Open the website from Websites and scroll to Webhooks.
  2. Enter the Endpoint URL. It must be https:// and reachable from the internet.
  3. Choose what to send and click Add webhook.
  4. Copy the signing secret. It is shown once. Roll secret creates a new one.
  5. Click Send test to check your endpoint answers.

Clients need the Manage webhooks permission. Ask your account team if you do not see Webhooks. A website can have up to five.

Events

Event When
lead.received A Lead event reaches the relay, one post per lead.
delivery.failed Meta refuses a batch of events. At most one post every 5 minutes per webhook, so a broken access token does not flood you.
daily.summary Shortly after midnight UTC, with the previous day's totals.

Posts are sent after the visitor's request has been answered, so they never slow the site down.

What is sent

Every post is JSON with the same envelope:

{
  "id": "6f0e2c1a-3b7d-4f7e-9a51-0c3f2d8e4b10",
  "type": "lead.received",
  "created_at": "2026-10-21T09:14:03Z",
  "website": { "uuid": "9b1d...", "name": "Clinic" },
  "data": {
    "event_id": "gf_81_1042",
    "source_event": "lead",
    "meta_event": "Lead",
    "event_time": "2026-10-21T09:14:01Z",
    "page_url": "https://clinic.example/page/book",
    "source_domain": "clinic.example",
    "referrer_domain": "www.google.com",
    "form_ref": "gf:81",
    "custom_data": { "value": 150, "currency": "USD" },
    "delivered_to_meta": true
  }
}

delivery.failed carries the number of events, Meta's error message and up to 20 event IDs and names. daily.summary carries date, received, delivered, failed, delivery_rate, visitors, page_views and leads.

Webhooks only contain what the relay keeps after sanitising: the cleaned page address, hosts, event names and cleaned event details. They never contain names, email addresses, phone numbers or their hashes, IP addresses or their hashes, or the visitor's user agent.

Check the signature

Each post has these headers:

  • X-Pixel-Relay-Signature: t=1792574043,v1=5257a869...
  • X-Pixel-Relay-Event: lead.received
  • X-Pixel-Relay-Delivery: the id of the post, the same on every retry, so you can ignore repeats

v1 is the HMAC-SHA256 of the timestamp, a full stop and the raw body, keyed with the signing secret. Recompute it, compare in constant time and refuse old timestamps:

[$t, $v1] = sscanf($_SERVER['HTTP_X_PIXEL_RELAY_SIGNATURE'], 't=%d,v1=%s');
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $t.'.'.$body, getenv('PIXEL_RELAY_WEBHOOK_SECRET'));

if (! hash_equals($expected, (string) $v1) || abs(time() - $t) > 300) {
    http_response_code(400);
    exit;
}

Retries and switching off

Answer with any 2xx status within 10 seconds. Anything else counts as a failure and the post is retried 4 more times, after about 30 seconds, 2 minutes, 10 minutes and 30 minutes. Redirects are not followed.

After 10 posts in a row fail every retry, the webhook is Turned off and nothing more is sent. Fix your endpoint, then click Resume. Recent deliveries under each webhook lists the latest attempts with their status, and the delivery log is kept for 30 days.