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, verify that signature against the raw request body and your webhook secret. The parse_webhook_event function handles verification and deserialization in one call.

Import

from agentrail import parse_webhook_event

Verify and parse a delivery

from agentrail import parse_webhook_event

raw_body = request.body
signature = request.headers["X-AgentRail-Signature"]

event = parse_webhook_event(
    raw_body,
    os.environ["AGENTRAIL_WEBHOOK_SECRET"],
    signature,
)

print(event.type, event.data)
parse_webhook_event raises an exception if the signature does not match or if the body cannot be deserialized.

Parameters

ParameterTypeDescription
raw_bodybytes | strThe raw request body, unmodified
Second argumentstrYour webhook secret from AGENTRAIL_WEBHOOK_SECRET
signaturestrThe value of the X-AgentRail-Signature header

Use the raw request body

Pass the raw request body bytes or string to parse_webhook_event. Do not parse the body as JSON first. JSON re-serialization changes byte ordering and whitespace, which breaks the HMAC signature check.
In FastAPI, read the raw body with Request.body():
import os

from fastapi import FastAPI, Request
from agentrail import parse_webhook_event

app = FastAPI()

@app.post("/webhooks/agentrail")
async def handle_webhook(request: Request):
    raw_body = await request.body()
    signature = request.headers["X-AgentRail-Signature"]

    event = parse_webhook_event(
        raw_body,
        os.environ["AGENTRAIL_WEBHOOK_SECRET"],
        signature,
    )

    print(event.type, event.data)
    return {"ok": True}
In Django or Flask, read request.body before any JSON parsing middleware runs.

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.