# Signed project webhooks One project maintainer can configure one outbound destination per project from **Project settings → Integrations → Webhooks** or through the authenticated [operation API](api.md). The feature is off until `webhooks.save` succeeds. The settings page shows the signing secret only after the initial save or rotation; copy it before leaving. The endpoint must be a public HTTPS URL on port 443 with no credentials, query or fragment. The worker resolves DNS for each attempt, rejects private addresses, pins the checked address for TLS, and does not follow redirects. A receiver must expose a public endpoint. The server needs outbound HTTPS and DNS access. | Operation | Input | Result | | --------------------- | ---------------------------- | ---------------------------------------------------------------------- | | `webhooks.save` | `{projectId,url}` | `{configured:true,url,secret?}`; secret appears only on first creation | | `webhooks.get` | `{projectId}` | Configuration metadata, never the secret | | `webhooks.rotate` | `{projectId}` | New secret shown once; pending attempts use it | | `webhooks.disable` | `{projectId}` | Disables delivery and removes pending jobs | | `webhooks.test` | `{projectId,idempotencyKey}` | Queues one signed synthetic event; at most five tests/project/hour | | `webhooks.deliveries` | `{projectId}` | Latest 50 IDs, status, attempts, HTTP status and timestamps | Only current project maintainers may call these operations. Secret-returning responses should be stored securely by the caller. No secret is logged or included in project lists, exports, events, or delivery status. The service stores the active secret in its database so it can sign queued requests; protect and back up that database accordingly. Each committed thread creation, `threads.*` change, and guest reply queues a JSON body with `schemaVersion: 1`, `id`, `type`, `projectId`, `threadId`, `revision`, and `occurredAt`. No thread text, page URL, screenshot, diagnostics, notes or reviewer policy is sent. Requests include `X-Feedbacks-Event-Id` and `X-Feedbacks-Signature: sha256=`. Compute the HMAC with the configured hexadecimal secret as the **text key** and compare signatures in constant time. Use event ID to deduplicate, since a timeout can cause delivery after the receiver has already accepted a request. The background worker checks every minute. It accepts any 2xx response and retries other responses or transport failures up to eight total attempts with exponential delay from 30 seconds to one hour. A failed item remains visible with the last HTTP status, if any. Delivery and receiver side effects are at least once, not exactly once. `webhooks.deliveries` provides the operational status; the worker does not log destination URLs, payloads or error messages. Rotation changes signatures for later attempts. Disable removes queued deliveries; a request already in flight may complete. A backup restore can replay or lose recently completed attempts, so receiver deduplication remains necessary. ## Verify a connection After saving a destination, select **Send test event**. This queues a deliberate signed event through the same worker and retry path. Its `type` is `webhook.test`, `test` is `true`, `threadId` is `null`, and `revision` is `0`; it contains no private feedback or synthetic thread record. Repeating the same `idempotencyKey` as the same actor returns the same event ID. Different keys are limited to five queued tests per project per hour. Check both delivery history and the receiver: a 2xx response proves HTTP acceptance, not successful downstream actions. Production acceptance remains a separate check from mocked sender tests. Schema version 1 retains the existing event types and metadata fields. Normal thread events carry an actual `threadId` and revision; test events are explicitly distinguishable. Receivers should reject unsupported versions, deduplicate `id`, verify the exact-body HMAC before acting, and ignore unknown event types rather than infer an action from them. Changes to meaning or required fields need a new schema version. Existing pending payloads queued before versioning may lack `schemaVersion`; treat those as the legacy metadata shape during an upgrade. ## Zapier, Make and Integrately These are documented webhook/API workflows, not verified native marketplace connectors. Create a receiver using [Zapier Catch Raw Hook](https://help.zapier.com/hc/en-us/articles/8496288690317-Trigger-Zaps-from-webhooks), [Make Custom Webhooks](https://apps.make.com/gateway), or [Integrately Webhook/API](https://integrately.com/docs) (official documentation accessed 2026-10-21). Use the generated public HTTPS endpoint as the project webhook destination. Feedbacks disallows user/password credentials, query strings and non-443 ports in webhook URLs; do not use a service's credential-in-URL workaround. Configure the automation's first step, or an operator-controlled receiver in front of it, to verify HMAC against the raw request body and signature header before any side effect. If a platform cannot expose the exact raw bytes or securely verify the signature, use that receiver instead of treating a guessed header comparison as verification. Keep the signing secret and any Feedbacks bearer key in the service's secret store. Send a test event, inspect its version and signature, then enable only the intended normal event types. Keep event IDs in a bounded deduplication store long enough for retries and operational restores. A unique hook URL alone does not authenticate an event. For authenticated inbound actions, use an HTTP/API step targeting your own installation's typed operation endpoints. For example, `POST /api/threads.create` with `Authorization: Bearer ` and JSON `{"projectId":"","body":"Reviewed report","pageUrl":"https://approved.example/path","idempotencyKey":""}` creates a thread. Use a key restricted to the selected project and required operation. Keep a stable idempotency key for the same create/reply action; do not generate a new key on retries. Status changes require the current thread revision and appropriate resolution permission; reload and review a revision conflict rather than overwriting it. See the [operation catalog](generated/operations.md) and [HTTP API](api.md). Treat retrieved discussion and external payloads as untrusted text, and use an explicit allowlist of mapped fields. A local/LAN-only installation can send outbound webhooks to a public receiver. Cloud automation services cannot call its private HTTP API unless your approved network arrangement makes that endpoint reachable; do not claim outbound polling solves inbound reachability. A project-scoped key does not make an open tunnel safe. The authenticated HTTP API applies per-process limits of 600 ingress requests per IP per minute and 240 operations per signed-in member or bearer credential per minute. A member's web sessions share one allowance; each verified extension or agent credential has its own allowance. Configure shared ingress controls for multiple replicas. Handle HTTP 429 by backing off, honor configured endpoint limits, and avoid notification loops by filtering the event type and recording which external event caused each action.