Skip to main content

Documentation Index

Fetch the complete documentation index at: https://agentrail.app/docs/llms.txt

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

AgentRail signs each webhook delivery with an HMAC signature. Before you process any payload, you must verify that signature against the raw request body and your webhook secret. The parseWebhookEvent function handles verification and deserialization in one call.

Import

import { parseWebhookEvent } from "@agentrail-core/sdk";

Verify and parse a delivery

import { parseWebhookEvent } from "@agentrail-core/sdk";

const event = parseWebhookEvent(rawBody, process.env.AGENTRAIL_WEBHOOK_SECRET!, {
  "x-agentrail-subscription-id": req.headers["x-agentrail-subscription-id"],
  "x-agentrail-event-id": req.headers["x-agentrail-event-id"],
  "x-agentrail-event-type": req.headers["x-agentrail-event-type"],
  "x-agentrail-delivery-id": req.headers["x-agentrail-delivery-id"],
  "x-agentrail-delivery-attempt": req.headers["x-agentrail-delivery-attempt"],
  "x-agentrail-signature": req.headers["x-agentrail-signature"],
});

console.log(event.type, event.data);
parseWebhookEvent throws if the signature does not match or if required headers are missing.

Required headers

AgentRail sends all of the following headers with every delivery. Pass them exactly as received — do not normalize or rename them.
HeaderDescription
x-agentrail-subscription-idID of the webhook subscription that triggered the delivery
x-agentrail-event-idUnique ID for this event
x-agentrail-event-typeEvent type, e.g. task.updated
x-agentrail-delivery-idUnique ID for this delivery attempt
x-agentrail-delivery-attemptAttempt number (starts at 1)
x-agentrail-signatureHMAC signature to verify

Use the raw request body

Pass the raw request body bytes or string to parseWebhookEvent. Do not parse the body as JSON first. JSON re-serialization changes byte ordering and whitespace, which breaks the HMAC signature check.
In Express, read the raw body by configuring express.raw:
import express from "express";
import { parseWebhookEvent } from "@agentrail-core/sdk";

const app = express();

app.post(
  "/webhooks/agentrail",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const event = parseWebhookEvent(
      req.body,
      process.env.AGENTRAIL_WEBHOOK_SECRET!,
      {
        "x-agentrail-subscription-id": req.headers["x-agentrail-subscription-id"] as string,
        "x-agentrail-event-id": req.headers["x-agentrail-event-id"] as string,
        "x-agentrail-event-type": req.headers["x-agentrail-event-type"] as string,
        "x-agentrail-delivery-id": req.headers["x-agentrail-delivery-id"] as string,
        "x-agentrail-delivery-attempt": req.headers["x-agentrail-delivery-attempt"] as string,
        "x-agentrail-signature": req.headers["x-agentrail-signature"] as string,
      },
    );

    console.log(event.type, event.data);
    res.status(200).send("OK");
  },
);

Set the webhook secret

Your webhook secret (AGENTRAIL_WEBHOOK_SECRET) is separate from your API key. You set it when you create a webhook subscription — see POST /event-subscriptions for the secret parameter.