Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

PM Webhooks

Webhooks in both directions for Mission Control boards. Outbound: subscriptions POST matching board events to callback URLs with an HMAC-SHA256 signature, retried, health-tracked, auto-disabled and dead-lettered. Inbound: a public per-board URL receives external POSTs, with an optional HMAC signature to prove the sender, and folds each one into a board event.

What it is

PM Webhooks connect PM boards to external systems in both directions.

Outbound subscriptions: external systems register a callback URL, and when board events fire (from the sync/diff pipeline) matching events are POSTed there with an HMAC-SHA256 signature, retried, health-tracked, auto-disabled on repeated failure, and dead-lettered.

Inbound receiver: each inbound webhook owns a generated token URL that external systems POST to, and the payload is folded into a board event. Signing is opt-in, and recommended for anything reaching Omniscio from off this machine.

Where to find it

There is no screen for this. It is an agent and API surface: subscriptions are created, listed and removed through the app's local control server using the routes listed under For agents, and there is no settings panel to configure them from.

How it behaves

Key behaviors

  • Signing: every delivery carries X-AMC-Signature (HMAC-SHA256 of the raw payload using the webhook's secret)
  • Retry: 3 attempts with full-jitter backoff (base 2s, max 16s), 10s timeout per attempt
  • Auto-disable: after 3 consecutive failures the webhook is marked inactive and an inbox alert surfaces
  • Health reset: a single successful delivery resets the failure counter
  • Event filtering: an empty event_filter array means all event types
  • Soft delete: DELETE marks is_deleted = 1, never destroys data

Dead-letter queue

Failed deliveries (all 3 retries exhausted) are queued in pm_webhook_dlq. A background service ticks every 15 minutes:

  1. Purges entries past 10 retries or older than 14 days (anti-abandonment backstop), raising an operator alert when events are discarded
  2. Re-delivers retryable entries preserving the original deliveryId for receiver idempotency, refreshing only deliveredAt and the signature
  3. DLQ success does NOT reset the webhook's failure counter -- only live delivery success does

Settings

No dedicated settings. Requires Mission Control to be enabled.

Inbound webhooks (receiving events from other systems)

The other direction: instead of Omniscio pushing events out, an external system POSTs to a URL and Omniscio folds the payload into a board event that board automations can trigger on.

The URL is the credential. Each inbound webhook gets a generated token, and the endpoint is POST /pm/webhooks/inbound/<token>. It carries no bearer auth and is reachable from the network, so treat the full URL as a secret: anyone holding it can deliver events.

Signing (opt-in, recommended for anything off this machine)

Create the webhook with enableHmac: true and it gets an HMAC secret alongside its token. Every delivery must then carry:

X-Webhook-Signature: sha256=<lowercase hex digest>

where the digest is HMAC-SHA256(secret, rawBody) -- the raw body bytes exactly as you sent them, computed before any JSON parsing. Do not re-serialize a parsed object to sign it: pretty printing, a space after a colon, or a different key order all change the bytes, and the signature will not match. This is the same convention as GitHub and Stripe, and the same rule outbound-webhooks.md gives for verifying Omniscio's own deliveries. The comparison is constant-time.

Response codes

Status Meaning
200 Accepted -- the body was folded into a board event
400 Missing token, or the body is not a bounded JSON object
401 Signature missing, malformed, or wrong
404 Token unknown or inactive (or Mission Control is disabled)
413 Body over 64 KiB
429 Per-board rate limit (60 deliveries per minute)
503 The webhook needs a signature but its secret could not be read

401 and 503 are different failures and you must treat them differently. A 401 means your signature is wrong and retrying unchanged will fail again. A 503 means the receiver temporarily cannot verify anyone's signature -- your signature may be perfectly correct -- so retry rather than alerting on a bad secret.

Duplicate deliveries

Webhooks get redelivered, so the receiver collapses a repeat rather than running the same automation twice. What counts as a repeat depends on what you send:

  • Send a delivery id and the collapse is exact. Stamp one of X-Idempotency-Key, X-Event-Id, X-Webhook-Id or X-Request-Id with a value that is stable across retries of the same event and different for distinct events. A redelivery then collapses, and two different events never do -- even when their payloads are byte-identical.
  • Send nothing and the receiver falls back to a hash of the body. Two deliveries carrying the same body are then treated as the same event and collapse.

Either way the later delivery is answered 200 { "ok": true, "deduplicated": true } and is not dispatched again.

This matters if you can legitimately post the same payload twice -- a monitor re-firing the same alert, a poller re-posting an unchanged record. Without a delivery id the second one is indistinguishable from a retry of the first, so it is dropped and folded into the earlier event. Send a delivery id whenever a repeat is meaningful. A suppressed delivery is written to the server log; nothing beyond the deduplicated flag reaches the sender.

For agents

Outbound subscription routes:

  • POST /pm/webhooks -- create a subscription ({ boardId, callbackUrl, events[], secret })
  • GET /pm/webhooks -- list subscriptions
  • DELETE /pm/webhooks/:id -- soft-delete a subscription

Inbound receiver routes:

  • POST /pm/webhooks/inbound -- create an inbound webhook ({ boardId, name?, enableHmac? }); the response carries the token, and the HMAC secret when enableHmac is set
  • GET /pm/webhooks/inbound?boardId=<id> -- list inbound webhooks for a board
  • DELETE /pm/webhooks/inbound/:id -- soft-delete one
  • POST /pm/webhooks/inbound/:id/regenerate -- issue a new token (the old URL stops working)

The delivery endpoint itself, POST /pm/webhooks/inbound/:token, is public and takes no bearer token.

Requires the missionControlEnabled setting.

Related

These are board-scoped subscriptions, which makes mission-control.md -- the parent page -- the natural next read. Do not confuse them with outbound-webhooks.md, Omniscio's own outbound webhook system, which is a separate mechanism with its own page. The full behavioural contract is recorded in pm-webhooks-contract.md, and every other page in this library is listed in INDEX.md.

Last verified 2026-10-01