Integrations

Connect Roast to Slack, Discord, Jira, Linear, GitHub and custom webhooks so new feedback flows automatically into the tools your team already uses. Integrations live under Settings -> Integrations and fire whenever a new submission is created, plus a manual "create issue" action on individual submissions.

Overview and where integrations live

All integrations are managed from the dashboard at Settings -> Integrations. The page shows a catalogue of six integrations grouped into three categories: Issue Trackers (Jira, Linear, GitHub Issues), Communication (Slack, Discord) and Automation (Webhooks). Use the category filter buttons at the top to narrow the list.

Each integration is configured once per workspace and stored against the workspace owner's account (the roast_integrations table). An integration set up by an admin therefore applies to the whole workspace, not just the person who created it. When feedback arrives on any of the workspace's forms, Roast loads the owner's enabled integrations and dispatches to all of them.

A card shows "Connect" if the integration has never been set up. Once connected it shows a status badge - green "Connected" when enabled, or grey "Paused" when disabled - along with Pause/Enable, Configure and Disconnect controls.

Integrations are workspace-wide: they belong to the workspace owner and apply to every form in the workspace.

Secrets (webhook URLs, API tokens, signing secrets) are never shown back to you in full. The API masks them to the last 4 characters. When you re-open Configure, leave a masked field untouched to keep the existing secret, or type a new value to replace it.

Who can manage integrations (permissions)

Reading the integrations list is allowed for every role (owner, admin, editor, viewer). However, creating, editing, pausing/enabling and disconnecting integrations all require the integrations:write permission, which is held only by owners and admins.

Editors and viewers can see which integrations are connected but will receive a "Forbidden" (403) error if they attempt to connect, change, toggle or disconnect one. This is enforced server-side in every write route (POST, PATCH, DELETE), so the restriction cannot be bypassed from the browser.

The separate "create issue from this submission" action is gated differently: it is a moderation action requiring submissions:write, which owners, admins and editors hold but viewers do not.

Connect / Configure / Pause / Enable / Disconnect: owners and admins only.

Manual "create issue" on a submission: owners, admins and editors (not viewers).

All integration writes go through a service-role client only after an explicit ownership + role check, and verify the record belongs to your workspace owner before changing it.

Slack

Slack posts a richly formatted message to a channel whenever qualifying feedback arrives. It includes the form name, a quoted excerpt of the feedback, the type (praise/roast), heat level or star rating, who it was from, the page URL, any AI summary and AI tags, plus action buttons (View Feedback, Approve, Reject) and a video thumbnail when available.

Setup: in Slack, create an Incoming Webhook for the channel you want notifications in, then in Roast click Connect on the Slack card and paste the Webhook URL. You can optionally set a Default Channel (for example #feedback). The webhook URL must be a valid HTTPS hooks.slack.com URL - Roast rejects anything else.

  1. 1In Slack, create an Incoming Webhook for your target channel and copy the webhook URL.
  2. 2In Roast, go to Settings -> Integrations and click Connect on the Slack card.
  3. 3Paste the Webhook URL (required) and optionally enter a Default Channel.
  4. 4Under "Notify on", choose which events should trigger a message (see Notification rules below).
  5. 5Click Connect to save.

The webhook URL is validated and host-restricted to hooks.slack.com; non-HTTPS, localhost or private-IP URLs are rejected.

The Approve/Reject buttons are rendered in the Slack message, but there is no documented interactive endpoint that handles those clicks - use "View Feedback" to act in the dashboard.

Discord

Discord posts an embed to a channel via an incoming webhook when qualifying feedback arrives. It carries the same information as Slack (type, heat/rating, author and so on) formatted as a Discord embed.

Setup: in Discord, go to Server Settings -> Integrations and create a webhook for your channel, then click Connect on the Discord card in Roast and paste the Webhook URL. The URL must be a valid HTTPS discord.com or discordapp.com URL and must point at an /api/webhooks/... path.

  1. 1In Discord, open Server Settings -> Integrations and create a webhook; copy its URL.
  2. 2In Roast, go to Settings -> Integrations and click Connect on the Discord card.
  3. 3Paste the Webhook URL (required).
  4. 4Choose your "Notify on" events.
  5. 5Click Connect to save.

The URL is validated against discord.com / discordapp.com and must include /api/webhooks; other hosts or paths are rejected.

Discord uses the same notification rules as Slack.

Notification rules for Slack and Discord (Notify on)

When configuring Slack or Discord you set "Notify on" with three checkboxes: Praise, Roasts, and "Nuclear roasts only". By default Praise and Roasts are on and Nuclear is off.

The delivery logic is: if the feedback is praise and Praise is off, it is skipped; if it is a roast and Roasts is off, it is skipped; and if "Nuclear roasts only" is enabled, anything that is not a nuclear-heat roast is skipped. In other words, ticking "Nuclear roasts only" narrows delivery to nuclear roasts regardless of the other boxes.

"Nuclear roasts only" is a hard filter: with it on, only nuclear-heat roasts notify.

These notifications fire automatically on submission creation - there is no manual "send to Slack/Discord" button.

Webhooks (custom / Zapier / automation)

The generic Webhook integration POSTs a JSON payload to any HTTPS URL you control when a submission is created. The payload has the shape { event, timestamp, data } where event is submission.created and data contains the submission id, type, content, heat level, rating, author name/email, page URL and form id.

Setup: click Connect on the Webhooks card, enter your endpoint URL and, optionally, a Signing Secret. If you provide a secret, Roast signs each request with HMAC-SHA256 and sends the signature so you can verify authenticity. Each delivery includes the headers X-Roast-Signature (the HMAC hex digest), X-Roast-Event (the event name) and X-Roast-Timestamp.

  1. 1Click Connect on the Webhooks card.
  2. 2Enter your endpoint URL (must be HTTPS).
  3. 3Optionally enter a Signing Secret for HMAC request verification.
  4. 4Click Connect to save. New submissions will now POST to your endpoint.

The URL must be HTTPS. To mitigate SSRF, Roast rejects localhost and literal private/loopback/link-local IP ranges (10.x, 127.x, 169.254.x, 172.16-31.x, 192.168.x, IPv6 loopback, and similar).

To verify a request, recompute HMAC-SHA256 of the raw request body using your signing secret and compare it to X-Roast-Signature.

The codebase defines additional event types (submission.approved, submission.rejected, submission.replied, submission.converted, wall_item.added/removed, expert_roast.requested/completed), but the automatic dispatcher currently only fires submission.created for the Webhook integration.

Deliveries are fire-and-forget: a failed webhook is logged server-side but never blocks the submission or other integrations, and there is no automatic retry.

Issue trackers: Jira, Linear and GitHub

Issue trackers let Roast create an issue from feedback. Connecting a tracker requires its credentials: Jira needs Domain, Email, API Token and Default Project (project key); Linear needs an API Key and Team ID; GitHub Issues needs a Personal Access Token, Repository Owner and Repository Name. Help text on each field points to where to generate the token (id.atlassian.com for Jira, linear.app/settings/api for Linear, github.com/settings/tokens for GitHub).

Issues can be created two ways. Automatically: on submission creation, the dispatcher passes the submission to each connected tracker, which only creates an issue if that tracker's auto-create rules are met. Manually: a user can trigger creation from an individual submission via the dashboard's create-issue action, which forces creation in every connected tracker, bypassing the auto-create gating entirely.

Auto-create rules (stored per tracker in the autoCreate config) gate automatic creation by: enabled on/off; feedbackTypes (praise/roast); minHeatLevel (using the order lukewarm, warm, hot, fire, nuclear - feedback below the threshold is skipped); and requireTags (the feedback must carry at least one of the required AI tags). Note that the Configure modal does not currently expose fields for these auto-create rules, so automatic issue creation depends on autoCreate being present in the stored config; the reliable, user-facing path is the manual create-issue action.

Manual create-issue requires submissions:write (owner/admin/editor). If no Jira/Linear/GitHub integration is connected it returns an error (code NO_TRACKER) telling you to connect one in Settings -> Integrations.

Manual creation makes one issue per connected tracker and returns each issue's URL; if all attempts fail it returns a 502 with the failure reasons.

Issue creation failures are non-fatal during automatic dispatch - they are swallowed so one bad tracker never blocks others or the submission.

Pausing, editing and disconnecting

On a connected card, Pause toggles the integration off without deleting its configuration (the card then shows "Paused" and it stops firing); Enable turns it back on. Configure re-opens the settings modal so you can change non-secret fields or rotate secrets. Disconnect deletes the integration entirely.

When editing, only the fields you change are sent. Masked secret placeholders are treated as "unchanged" and never overwrite the stored secret, so you can safely save a change to, say, a Slack channel without re-entering the webhook URL.

  1. 1Open Settings -> Integrations and find the connected card.
  2. 2Click Pause to disable (or Enable to re-activate) without losing settings.
  3. 3Click Configure to change settings; edit only the fields you need and leave masked secrets untouched to keep them.
  4. 4Click Disconnect to remove the integration completely.

Only the workspace owner's enabled integrations are dispatched - a paused integration is skipped entirely.

Pause/Enable, Configure and Disconnect all require integrations:write (owner/admin).

Frequently asked questions

When exactly do notifications fire?
Automatically when a new submission is created on any of your workspace's forms. The submissions endpoint dispatches to every enabled integration the workspace owner has set up. Slack/Discord respect your "Notify on" rules, the generic Webhook fires a submission.created payload, and issue trackers create issues only if their auto-create rules match. There is also a manual create-issue action on individual submissions.
Can editors or viewers connect integrations?
No. Connecting, configuring, pausing, enabling and disconnecting all require the integrations:write permission, held only by owners and admins. Editors and viewers can see the list but get a Forbidden error if they try to change anything. Editors (and admins/owners) can, however, use the manual create-issue action on a submission.
Why can't I see my webhook URL or API token after saving?
Secrets are deliberately masked to their last 4 characters and never returned in full by the API. When you re-open Configure, leave the masked field as-is to keep the current secret, or type a new value to replace it.
My Slack or Discord webhook URL was rejected. Why?
Roast enforces host allowlists and an SSRF guard. Slack URLs must be HTTPS and on hooks.slack.com; Discord URLs must be HTTPS on discord.com/discordapp.com and include an /api/webhooks/ path. All webhook URLs must be HTTPS and cannot point at localhost or private/reserved IP ranges.
Does a failed integration block my form from receiving feedback?
No. Integration dispatch is fire-and-forget and fully isolated: each integration runs in its own try/catch, failures are logged server-side, and nothing delays or fails the visitor's submission. There is no automatic retry, so persistent failures (such as a wrong webhook URL) mean those notifications are silently missed until you fix the configuration.
Why didn't an issue get created automatically?
Automatic issue creation only happens when the tracker's auto-create rules pass (enabled, matching feedback type, minimum heat level, and required tags). Because the Configure modal doesn't expose those auto-create fields, automatic creation may not be enabled. Use the manual create-issue action on a submission, which forces creation in every connected tracker.