Webhooks
Webhooks let PLUR push events at your systems instead of you polling. Useful for piping engram activity into Slack, audit warehouses, or any other internal system.
Register
Section titled “Register”In the user portal at /me/webhooks:
- Click
New webhook. - Enter the target URL — must be a public HTTPS URL (private/loopback addresses are refused).
- Pick events to subscribe to (or all).
- PLUR generates a webhook secret — copy it; it’s used for HMAC verification.
Events
Section titled “Events”| Event | Fires when |
|---|---|
engram_created | An engram is saved. |
engram_retired | An engram moves to retired status. |
oauth_login | A user logs in via OAuth. |
Further events (SSO logins, admin actions, SCIM operations) are planned.
Payload shape
Section titled “Payload shape”Every webhook POST has this envelope:
{ "event": "engram_created", "occurred_at": "2026-05-25T14:32:18.123Z", "org_id": "acme", "user_id": "alice", "target_type": "engram", "target_id": "ENG-...", "details": { /* event-specific payload */ }}Headers:
Content-Type: application/jsonX-Plur-Event: engram_createdX-Plur-Delivery: <uuid, fresh per delivery>X-Plur-Signature: sha256=<hex hmac>Verifying signatures
Section titled “Verifying signatures”The signature is HMAC-SHA256 over the raw request body with the webhook’s secret as the key. Verify before processing, using a constant-time comparison:
import crypto from 'node:crypto';
function verify(rawBody: string, signature: string, secret: string): boolean { const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected), );}Retries
Section titled “Retries”Delivery is best-effort, at-least-once:
- On 5xx or network error, PLUR retries once, 30 seconds later.
- Every attempt is logged to the delivery history (visible at
/me/webhooks). - After 10 consecutive failures, the subscription auto-disables.
Make your handler idempotent — the same event can arrive twice around a retry. Redirects are never followed.
Auto-disable and re-enable
Section titled “Auto-disable and re-enable”When auto-disabled, the webhook stays registered but is paused. Re-enable from /me/webhooks after fixing your endpoint.
When not to use webhooks
Section titled “When not to use webhooks”- For triggering an LLM call — use the MCP/REST API instead.
- For audit-grade compliance pipelines — delivery is best-effort with a single retry; use the audit log export and reconcile periodically instead.