The Notify service · notifications

Notify

A record captures the full lifecycle of a piece of work: the intent at the start, the delegation in the middle, the result at the end, each stage signed the moment it is real. Notify carries the events of that signed span out to the systems and people you already run in production. When an agent finishes a task, when a verdict lands, when a delegation changes hands, the delivery shows up at your endpoint as an HTTPS POST you already know how to receive. No broker to adopt, nothing to poll: the loop closes by delivery, not by you asking.

At-least-once · Idempotency key · Retry with backoff · Circuit breaker · Dead-letter replay · HMAC-SHA256 / Ed25519 RFC 9421

The shape

Human-in-the-loop by delivery, not by polling

An agent that has to wait on a person should not sit in a loop hitting an inbox endpoint. Notify pushes the moment a record reaches a state someone cares about (an approval queue, a Slack channel, a ticketing system, a payment platform), so the human or the downstream system reacts to a delivery instead of the agent burning cycles polling for one. The agent registers what it wants to hear about, then goes idle until the event arrives.

Everything Notify carries is an event of an already-signed record. This page is about the delivery: how the event reaches you intact, safe to handle exactly once, and provable to the receiver. What is inside a settlement event, the SETTLE, HOLD, or RELEASE on a terminal verdict, lives on the Settlement Signal webhooks page; those are one payload class on this channel, not the whole of it.

Signing

Two signing schemes for two trust problems

Every delivery is signed. The scheme is fixed per subscription and reported on the webhook's read surface as signingAlg, so a consumer checks it once and writes the matching verifier. Which scheme you want depends on who needs to trust the delivery.

hmac (default)

HMAC-SHA256 over a per-subscription shared secret, in the same header shape Stripe, GitHub, and Shopify use: X-AGLedger-Signature: t=<unix>,v1=<hex>. It confirms to one specific receiver that the POST came from the Server it subscribed against, untampered. It verifies in two lines and needs no third party. This is the right choice for ordinary notarization fan-out, where only your own system consumes the event.

ed25519: verifiable by a third party

RFC 9421 HTTP Message Signatures, signed with the Server's vault key, the same key that signs the chain. The receiver verifies against the Server's published public keys and holds no secret of its own. A subscription that lists a settlement event defaults to ed25519 when the Server has a signing key. This is the scheme that lets a settlement instruction cross a company boundary.

Verifiable by a third party

Signed the same way the chain is signed

A shared secret is symmetric: the receiver holds the same key that signs, so it can confirm a delivery for itself but cannot prove to anyone else who produced it. For a Settlement Signal™ webhook routed into a payment platform, ERP, or ticketing system, that is the difference that matters.

The Ed25519 path is asymmetric. The delivery is signed by the same vault key that signs the chain, naming the accountable principal inside the payload. The payment system on the other side verifies a SETTLE against the Server's published key, checked once against the key pin the Server's operator hands over. There is no shared secret to exchange, and anyone holding the published key can check the signature, not only the receiver. That is what lets a settlement instruction cross a company boundary without a trusted intermediary.

The receiver resolves the key by the keyid in the signature header against GET /v1/verification-keys (also published at /.well-known/agledger-vault-keys.json), recomputes the signature base, and checks the Ed25519 signature. The SETTLE and the chain record it settles share one trust root.

Content-Digest: sha-256=:<base64(sha256(body))>: Signature-Input: sig1=("content-digest" "x-agledger-idempotency-key"); created=<unix>;keyid="<kid>";alg="ed25519" Signature: sig1=:<base64(ed25519 over the signature base)>:

Derived components (@method, @target-uri, @authority) are deliberately excluded so a load balancer or reverse proxy that rewrites host and path cannot break verification of an authentic message. Step-by-step verification code for both schemes is in the webhook guide.

Events

Business moments, not internal state transitions

Notify emits an event at every business-meaningful moment in the record lifecycle. Register an endpoint through POST /v1/webhooks with an event-type filter or the wildcard ["*"]. Federation events mirror the lifecycle stream with a federation. prefix and a thin cross-org payload, so a single subscription can see both sides without two divergent schemas on one event type. Payloads ship in AGLedger's native envelope or CloudEvents 1.0.

CategoryExample events
Record lifecyclerecord.created, record.recorded, record.completion_submitted, record.fulfilled, record.failed, record.expired, record.cancelled
Agent-to-agentrecord.proposed, record.proposal_accepted, record.proposal_rejected, record.delegated, record.revision_requested
Delegation rollupcascading.gate.complete
Settlement and disputessignal.emitted, signal.received, dispute.opened, dispute.resolved, dispute.withdrawn
Federationfederation.record.state_changed, federation.settlement.signal, record.federation_fulfilled (and other federation-projected lifecycle events)
Entity referencesrecord.reference_added, agent.reference_added

Every payload carries a type and a status in display names (CREATED / FULFILLED / FAILED / RECORDED …), not internal state-machine names. The full event-type list is in the API reference.

Delivery and management

Built to survive a receiver that is having a bad day

Delivery is at-least-once. Every event carries a stable idempotency key, replayed verbatim on every retry, so a receiver dedups on it and treats a repeat as a no-op. Ordering is serialized per subscription and best-effort, so a receiver driving a state machine branches on the payload's status rather than on arrival order.

A failed delivery retries with exponential backoff, then lands in the subscription's dead-letter queue carrying the original event body. A circuit breaker opens after a run of consecutive failures and closes on the first success. Replay one entry or drain the queue once the receiver is back. HMAC secrets rotate with a grace window, so consumers update on their own schedule.

Subscriptions are an API, not a config file you redeploy: register, inspect, rotate, pause, resume, send a test event, read the per-attempt delivery log, and work the dead-letter queue, all from the same key. An org-wide health view gives SRE dashboards one row per subscription with breaker state and last-success timestamp. Config-as-code installs declare the same subscriptions in provisioning YAML.

The retry count, breaker threshold, DLQ retention window, and every command live in the webhook guide.

Related capabilities

Settlement Signal webhooks →

What the Ed25519-signed delivery carries on terminal verdicts: SETTLE, HOLD, RELEASE.

Federation →

How a peer Server's event projects into your local stream as signal.received.

Integrations →

Trace-ID join keys and OCSF SIEM export: the other ways AGLedger fits under your stack.

Security →

SSRF protection on delivery URLs, secret storage, and the verification-key surface.

Webhook guide →

Register an endpoint and verify both signature schemes, with real code.

API →

The full webhook route surface and per-event payload schemas.

Yours to run, free to start