EVENTS
Webhook delivery
React to committed changes without receiving unnecessary customer data.
Register a public HTTPS receiver with POST /webhooks. The new subscription is disabled and returns its Bearer secret once. Store that secret in your receiver’s secret manager, then update the subscription with its id and enabled: true.
Verify the Bearer credential
This integration uses Authorization: Bearer <whsec_…>. There is no HMAC signature header. Compare the received header against your configured secret with a constant-time comparison, before parsing or acting on the event. Require HTTPS, apply a body-size limit, and never log the header.
import { timingSafeEqual } from 'node:crypto';
const expected = Buffer.from('Bearer ' + process.env.WEBHOOK_SECRET);
const received = Buffer.from(req.headers.authorization || '');
if (received.length !== expected.length ||
!timingSafeEqual(received, expected)) {
res.status(401).end(); return;
}
// Validate schemaVersion, orgId and the expected event type.
// Deduplicate id in a durable store before processing.
// Enqueue your work durably, then acknowledge with 2xx.Identifier-only events (schema version 2)
Every event contains schemaVersion, id, event, occurredAt, orgId and data.ideaId. It contains no contact email, message content, comments or actor details. Use a separately scoped API key if your integration needs resource fields.
Events: idea.submitted, idea.published, idea.status_changed, idea.official_update_added, idea.comment_added, idea.voted and idea.followed. API creation, status changes and publication workflows emit the matching committed events. Deleting an idea does not emit an event.
Retries and subscription changes
Events enter a transactional outbox and become available only after commit. Network failures and HTTP 408, 429 and 5xx retry after 60 seconds, 5 minutes and 30 minutes, for four attempts total. Other non-2xx responses fail without retry. Redirects are never followed. Delivery order is not guaranteed; duplicate events are possible.
Updating the subscription cancels older queued events. URL changes and secret rotation also disable the destination; re-enable explicitly once it is ready. Disabled/deleted hooks and suspended workspaces do not receive queued events. Completed outbox records are retained for up to 30 days, cleaned when that workspace next processes a delivery.
Test before enabling
POST /webhooks/{id}/test sends a synthetic payload with type: webhook.test, id, createdAt and data.message. It reports delivery status in the HTTP 200 body. It does not send customer data and is separate from the event contract.
Migration from earlier payloads
Version 2 replaces the previous full idea object and event-specific personal data. Update consumers before enabling this release. OAuth consent flows already in progress must also restart after the security migration.