Webhooks
Get an HTTP POST when something happens on your account: an anomaly fires, or a settlement lands. Send it to your own endpoint (we sign every request) or straight into a Slack, Discord, or Teams channel. Webhooks are free on every plan.
Manage them under Settings → API & webhooks.
Events
anomaly.detected: a traffic or earnings anomaly tripped one of your alerts.settlement.completed: a payout settled to an author on one of your sites.
The envelope every delivery carries
A signed (raw) delivery posts one envelope, and the event's own fields are nested inside
it under data:
{
"id": "dlv_01J8...",
"type": "settlement.completed",
"eventId": "settlement:pub_123:29650",
"createdAt": 1719000000000,
"data": {}
}Read your fields off data, not off the top level: body.data.tenant, not
body.tenant. Every payload example below is the data object, not the whole body.
eventId is stable per underlying occurrence, so a retry or two racing sweeps carry the same
value. De-duplicate on eventId; id is unique per delivery attempt and is also sent as the
Naulon-Id header. createdAt is Unix epoch milliseconds.
The signature covers the exact bytes of that whole envelope, so verify the HMAC over the raw body before you parse it.
Payload profile: summary or detailed
For a signed (raw) endpoint you choose, per hook, how much the settlement.completed
body carries. Pick it when you create the endpoint, or change it any time from the
endpoint's detail panel. (Chat channels like Slack, Discord, and Teams always get a
one-line summary; the profile doesn't apply to them.)
summary
The count only, meaning how many settlements this delivery covers. Pick it when all you need is a nudge to go look at your earnings.
{ "tenant": "acme", "announced": 3 }detailed
The full settlement: the gross that moved, a leg per payee with its on-chain reference, and the window it covers. New endpoints default to this.
{
"tenant": "acme",
"host": "acme.example.com",
"window": { "toMs": 1719000000000, "spanMs": 60000 },
"citations": { "settled": 3 },
"gross": { "microUsdc": 8800, "usdc": "0.008800" },
"legs": [
{ "role": "author", "payTo": "0x…", "microUsdc": 8000, "settled": true, "settlementRef": "0x…" },
{ "role": "operator", "payTo": "0x…", "microUsdc": 800, "settled": true, "settlementRef": "0x…" }
],
"settlementRefs": ["0x…"]
}Money is integer micro-USDC (microUsdc). That's the source of truth. The usdc
string is a formatted convenience; don't parse it back. gross.microUsdc is the sum
of the legs. settlementRef is the on-chain reference for that leg; use it to build
an explorer link for your chain. A field we can't attribute is left out, never faked.
So if a leg's settlementRef is null, it genuinely couldn't be pinned to one
settlement.
Switching a hook from summary to detailed (or back) takes effect on the next
delivery. Because the signature covers the exact bytes you receive, adding fields is
safe: verify the HMAC over the raw body you got, and it checks out either way.
Inspecting deliveries
Each endpoint's detail panel has a delivery log: event, status, response code, attempt count, and when. Expand a row to see the exact body that was delivered (with a copy button); a settlement row also shows the gross as a chip so the log reads like an earnings feed, not just a status list.
Signing (raw endpoints)
Every raw delivery carries a Naulon-Signature header: t=<unix>,v1=<hex>, an
HMAC-SHA256 over `${t}.${rawBody}` with your endpoint's secret. Recompute it over
the raw request bytes and compare in constant time; reject anything outside a ~5 minute
clock skew. Your secret is shown once when you create the endpoint (and on an explicit
reveal or rotate). Store it then.
What we don't send
A settlement webhook tells you the money that landed on your site: the gross, the payees, the on-chain references. It does not carry the query or prompt that led an agent to cite you: that lives with the reading agent, not with your site, so we never claim to have it. What you get is the settlement, in as much depth as we can honestly attribute.