Webhooks
HMAC-signed webhook integrations with Agent Community services.
Agent Community services exchange event notifications through HMAC-SHA256-signed webhook requests. This page documents the signing scheme so integration partners can verify payloads.
Who this is for
Webhook integrations are currently partner-scoped — internal agent services (e.g. the enrichment pipeline) and document-signing callbacks. There is no self-serve webhook subscription product yet. If you're building an integration that needs event callbacks, contact hello@agentcommunity.org.
Signature scheme
Every request signed with this scheme carries an HMAC-SHA256 signature computed over the raw request body with a shared secret, sent in the x-webhook-signature header as sha256=<hex digest>.
Verification steps:
- Read the raw request body (before any JSON parsing) — the signature is computed over the exact bytes sent, so parsing first and re-serializing will break verification.
- Compute
HMAC-SHA256(secret, body)and hex-encode it. - Constant-time-compare the result, prefixed with
sha256=, against thex-webhook-signatureheader value. Reject the request if they don't match.
import { createHmac, timingSafeEqual } from 'crypto'
function verifyWebhookSignature(
body: string,
signatureHeader: string | null,
secret: string,
): boolean {
if (!signatureHeader?.startsWith('sha256=')) return false
const expected = `sha256=${createHmac('sha256', secret).update(body).digest('hex')}`
if (expected.length !== signatureHeader.length) return false
return timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
}This mirrors the reference implementation in this repo (lib/webhooks/hmac.ts) — used both to verify inbound callbacks (e.g. the enrichment pipeline notifying us that a member profile is ready) and to sign outbound requests to partner services.
Replay handling
There is no timestamp header in this signing scheme — it authenticates the payload, not the delivery time. Replay protection, where needed, is the receiver's responsibility. Today's live consumer of this scheme (the enrichment-complete callback) applies idempotency at the data layer: before queuing a follow-up action it checks for an existing record keyed to the same source event, so a duplicate delivery is a safe no-op rather than a duplicate side effect.
A separate webhook receiver (DocuSeal document-signing callbacks) uses its own verification method — not this x-webhook-signature scheme — and deduplicates deliveries by submission ID and event type in Cloudflare Workers KV with a Postgres backstop. It's mentioned here only to avoid confusion: not every webhook endpoint on this site uses the scheme documented above.
Events
Live usage today includes internal agent-service callbacks (enrichment pipeline → site) and document-signing status updates. Outbound event feeds for members are on the roadmap and will be announced in /lists.