---
title: "Webhook Events"
description: "The full set of webhook event types PgBeam delivers, when each one fires, and the payload shape you receive."
canonical: "https://pgbeam.com/docs/webhook-events"
last-updated: "2026-10-08T11:52:38.000Z"
---

# Webhook Events

> The full set of webhook event types PgBeam delivers, when each one fires, and the payload shape you receive.

URL: https://pgbeam.com/docs/webhook-events

Audit export delivers events to a webhook endpoint as they happen. This page enumerates every event type you can subscribe to, when each one fires, and the fields in its payload. Subscribe to a subset with `event_types` (the CLI `--event` flag), or omit it to receive all of them.

## Event types

`event_type`

Fires when

`query_blocked`

A statement is rejected by policy (allowlist, read-only, and so on).

`budget_exhausted`

A credential hits its query or row budget.

`kill_switch`

A credential or project kill-switch is tripped.

`masked`

A result is returned with one or more masked columns.

`migration_flagged`

A DDL statement is flagged by the safe-migration linter.

`approval_requested`

A write or DDL is held for approval.

`canary_tripped`

A statement references a honeytoken decoy relation.

`content_flagged`

The result-content scan finds instruction-shaped text in the values a statement returned.

`anomaly_alert`

Anomaly detection raises an alert.

`audit_checkpoint`

A signed checkpoint is issued over the project's audit chain.

A separate `webhook.test` event is sent only when you use **Send test event** on an endpoint. You do not subscribe to it, and it never fires from live traffic.

## Envelope

Every delivery in the native `json` format shares the same envelope. The event-specific fields live under `data`.

Field

Description

`id`

Stable event id. Use it to de-duplicate retried deliveries.

`type`

The event type, one of the values above.

`project_id`

The project the event belongs to.

`occurred_at`

When the underlying event happened (RFC 3339).

`data`

Event-specific fields, documented per event type below.

The SIEM formats (`splunk_hec`, `datadog`, `elastic`) wrap these same fields in the shape that product expects.

## Audit-derived events

`query_blocked`, `budget_exhausted`, `masked`, `migration_flagged`, `approval_requested`, `canary_tripped`, and `content_flagged` all come from the audit log. They share the same `data` shape; the `event` field inside `data` tells you which underlying audit event it was.

Field

Description

`audit_id`

Id of the audit-log entry this event came from.

`credential_id`

The credential that ran the statement.

`region`

Region that served the statement.

`event`

The underlying audit event (for example `blocked`, `masked`).

`sql`

The statement, as parsed.

`normalized_sql`

The statement with literals stripped.

`query_hash`

Hash of the normalized statement.

`statement_kind`

The statement kind (for example `select`, `delete`).

`decision_rule`

The rule that produced the decision.

`reason`

Why it was blocked, masked, or held.

`rows_returned`

Rows returned to the agent, after masking and row caps.

`bytes_out`

Bytes returned.

`latency_ms`

Time to serve the statement.

`client_ip`

The agent's source IP.

`session_id`

The wire session the statement ran in.

`source`

Where the statement came from: a connection string or MCP.

The `kill_switch` type also fires from the audit stream when a statement is killed mid-flight, with the same `data` shape as above.

## `content_flagged`

This one is not an outcome. The statement ran, every row was forwarded to the agent unchanged, and it records its own `query`, `masked`, or `truncated` outcome as well. What the event says is that the values coming back carried instruction-shaped text: invisible character runs, Unicode Tag smuggling, unterminated bidi embeddings, mixed-script words. Text like that is written by whoever filled the row, which for a support ticket or a product review is someone outside your trust boundary, and it lands in the agent's context.

`decision_rule` is the field to filter on, and it carries one of two values:

`decision_rule`

Meaning

`content_scan_high_confidence`

At least one high-confidence structural finding. This is the one that also raises an anomaly alert.

`content_scan`

Findings were medium confidence only. A BOM from a CSV export and an unterminated bidi embedding in a right-to-left address both produce these honestly.

Both are delivered, because a receiver can threshold for itself and a delivery that never arrives is indistinguishable from a statement that was never flagged.

`reason` names the columns, the techniques, and how many values matched. It carries no bytes from the row, which is true of every field on this event and of the audit trail behind it. Under `content_scan_mode=block` the reason says the statement was refused, and the statement's own row in the audit log records `result_withheld`: the statement ran on your database, and the agent received an error instead of the result. Turn the scan on with `content_scan_mode` on the policy profile; the Prompt Scan API runs the same detector over text you hold yourself.

## `kill_switch` (project)

When a project kill-switch is engaged from the control plane, the event carries a compact payload rather than a per-statement one:

Field

Description

`project_id`

The project whose kill-switch was engaged.

`agents_disabled`

`true` while agent connections are blocked.

`reason`

Why the kill-switch fired.

## `anomaly_alert`

Raised by anomaly detection when a credential drifts from its baseline.

Field

Description

`id`

The anomaly alert id.

`project_id`

The project the alert belongs to.

`credential_id`

The credential the alert is about.

`kind`

The signal that tripped: `volume_spike`, `egress_spike`, `new_query_shape`, `off_hours`, or `error_spike`.

`severity`

The alert severity.

`title`

A short human-readable summary.

`details`

Signal-specific detail (varies by `kind`).

`window_start`

Start of the window the alert was computed over (RFC 3339).

`window_end`

End of that window (RFC 3339).

## `audit_checkpoint`

A periodic signed statement of how long the project's audit chain is and what it contains. Unlike every other event here, it is not about one query: it is about the whole chain.

Keep these. A hash chain cannot detect deletion at its own tip, because nothing inside it records how long it was supposed to be. A checkpoint you have retained is an outside record, so it lets you detect a truncation from a copy PgBeam no longer holds, and lets you verify the claim without trusting us to verify it for you.

Field

Description

`checkpoint_id`

Id of the checkpoint.

`origin`

Log identity, `pgbeam/audit/<project_id>`. Bound into the signature.

`size`

Number of audit entries the checkpoint commits to.

`root`

Merkle root over those entries, hex.

`key_name`

Name of the Ed25519 key that signed the note.

`note`

The signed artifact, in the transparency-log note format. This is what to retain.

The `size` and `root` fields are there so you can read the event without parsing anything. `note` is the one that carries the claim: it is signed, so `size` and `root` cannot be altered inside it, and it is what a verifier checks. If you keep only one field, keep that one.

The tree is an RFC 6962 Merkle tree, so any library implementing that specification can verify a note against a set of entries.

## `webhook.test`

Sent by **Send test event** so you can verify a receiver before relying on it.

## Related

Audit export: configure endpoints, signing, and SIEM formats.

Audit log: the queryable history audit-derived events come from.

Anomaly detection: source of `anomaly_alert` events.

Kill-switch: source of `kill_switch` events.

Audit log: the chain `audit_checkpoint` commits to, and the verification endpoint that compares the two.