Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lumiqtrace.com/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks let LumiqTrace push alert notifications to your own infrastructure in real time. When an alert rule fires, LumiqTrace immediately sends a signed HTTP POST to your configured endpoint. Use webhooks to integrate with Slack, PagerDuty, OpsGenie, custom dashboards, or any HTTP endpoint.
Webhooks are available on the Scale plan. On Pro and Team, email notifications are available but webhook delivery is not.

Configuring a webhook URL

Webhook URLs are set per alert rule. When creating or editing an alert rule in Dashboard → Alerts, enter your endpoint URL in the Webhook URL field. The URL must:
  • Use HTTPS
  • Accept POST requests
  • Respond with a 2xx status code within 10 seconds

Payload schema

When an alert fires, LumiqTrace sends a POST request with Content-Type: application/json and the following body:
{
  "event": "alert.fired",
  "alert_id": "alert_abc123",
  "rule_name": "Error rate above 5%",
  "metric": "error_rate",
  "condition": ">",
  "threshold": 0.05,
  "current_value": 0.12,
  "window_min": 15,
  "project_id": "proj_xyz789",
  "project_name": "acme-production",
  "organization_id": "org_def456",
  "organization_name": "AcmeCorp",
  "fired_at": "2026-04-20T14:32:00Z",
  "dashboard_url": "https://app.lumiqtrace.com/acme/acme-production/traces",
  "signature": "sha256=a4b3c2d1..."
}
event
string
Always "alert.fired" for alert webhooks.
alert_id
string
The ID of the alert rule that triggered.
rule_name
string
The human-readable name of the alert rule, as set in the dashboard.
metric
string
The metric that crossed the threshold: error_rate, cost_usd, latency_ms, request_count, or token_count.
condition
string
The comparison that triggered: ">" or "<".
threshold
number
The configured threshold value.
current_value
number
The actual metric value at the time of firing.
window_min
number
The aggregation window in minutes.
fired_at
string
ISO 8601 UTC timestamp when the alert fired.
dashboard_url
string
Direct link to the traces page for this project — include this in your Slack message for one-click investigation.
signature
string
HMAC-SHA256 signature for verifying the payload. See below.

Verifying the signature

Every webhook payload includes a signature field in the format sha256=<hex_digest>. You should verify this before processing the payload to protect against spoofed requests. The signature is computed as:
HMAC-SHA256(webhook_secret, raw_request_body)
Where webhook_secret is the signing secret shown once when you configure the webhook URL in the dashboard. Store it as an environment variable.
import crypto from "crypto";
import { Request, Response } from "express";

const WEBHOOK_SECRET = process.env.LUMIQTRACE_WEBHOOK_SECRET!;

export function handleWebhook(req: Request, res: Response) {
  const rawBody = req.body; // must be the raw buffer, not parsed JSON
  const signature = req.headers["x-lumiqtrace-signature"] as string;

  const expected = "sha256=" + crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(rawBody)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const payload = JSON.parse(rawBody.toString());
  // Process payload...

  return res.status(200).json({ received: true });
}
Use the raw request body (Buffer) for signature verification, not the parsed JSON object. Parsing changes whitespace and field ordering, which invalidates the signature.

Delivery guarantees

PropertyValue
Timeout10 seconds per attempt
Retries3 attempts with exponential backoff (5s, 25s, 125s)
OrderingNot guaranteed — events may arrive out of order
DeduplicationUse alert_id + fired_at to deduplicate
If all 3 delivery attempts fail, the webhook is marked as failed and no further retries are made. You can see failed deliveries in Dashboard → Alerts → Webhook history.

Integration examples

Slack

Post a formatted message to a Slack channel using an incoming webhook:
export async function POST(req: Request) {
  const rawBody = await req.arrayBuffer();
  // ... verify signature ...

  const alert = JSON.parse(Buffer.from(rawBody).toString());

  await fetch(process.env.SLACK_WEBHOOK_URL!, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      text: `🚨 *LumiqTrace Alert: ${alert.rule_name}*`,
      blocks: [
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: `*${alert.rule_name}*\n${alert.metric} is ${alert.current_value} (threshold: ${alert.threshold})`,
          },
        },
        {
          type: "actions",
          elements: [
            {
              type: "button",
              text: { type: "plain_text", text: "View traces" },
              url: alert.dashboard_url,
            },
          ],
        },
      ],
    }),
  });

  return Response.json({ ok: true });
}

PagerDuty

Create a PagerDuty incident from an alert:
await fetch("https://events.pagerduty.com/v2/enqueue", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Token token=${process.env.PAGERDUTY_API_KEY}`,
  },
  body: JSON.stringify({
    routing_key: process.env.PAGERDUTY_ROUTING_KEY,
    event_action: "trigger",
    payload: {
      summary: `LumiqTrace: ${alert.rule_name}`,
      source: alert.project_name,
      severity: alert.current_value > alert.threshold * 2 ? "critical" : "warning",
      custom_details: {
        metric: alert.metric,
        current_value: alert.current_value,
        threshold: alert.threshold,
        window_min: alert.window_min,
        dashboard: alert.dashboard_url,
      },
    },
  }),
});

Testing your webhook endpoint

Use the Test webhook button in the alert rule editor to send a sample payload to your endpoint. The test payload uses current_value equal to threshold + 1 so your handler can distinguish it from real alerts if needed (the fired_at timestamp will also be clearly recent). Alternatively, use a tool like webhook.site to inspect raw payloads during development before wiring up your real handler.