Submissions & Moderation
The submission inbox (dashboard) and submission detail page are where you review incoming feedback (roasts and praise), decide what becomes public, reply to submitters, run AI analysis, and remove submissions. This page explains exactly what each moderation action does, who is allowed to do it, and the side effects.
The submission lifecycle
Every submission has a status: pending, approved, rejected or flagged. New feedback arrives as pending and stays there until someone moderates it.
Status is just a label on the submission record. Approving or rejecting changes only that field — it does not move, copy or delete anything, and no webhook or external notification is fired on a status change. The status matters because only approved items are eligible to be shown publicly (for example on a Wall of Love); pending, rejected and flagged items remain private to the workspace.
There is no enforced one-way flow. You can move a submission between any of the four statuses via the API. In the dashboard inbox, the Approve / Reject / Flag buttons are only shown while a submission is pending; once it leaves pending you change status from elsewhere (e.g. the detail page still offers Flag). On the detail page, Approve and Reject buttons appear only for pending submissions, and Flag is always available in the Actions panel (disabled once already flagged).
Status values: pending, approved, rejected, flagged. Any other value is rejected by the API with a 400 'Invalid status'.
Approving does NOT automatically publish a submission anywhere — it only makes it eligible. Adding praise to the Wall of Love is a separate action.
No webhook, email or integration is triggered when you change a submission's status.
Approve and Reject — exactly what they do
Both Approve and Reject call PATCH /api/submissions/[submissionId] with the new status. The handler validates the status, confirms the submission belongs to your workspace, checks your role, then writes the new status value to the submission. That is the entire effect: a single field update.
Approve sets status to 'approved' (the only status that lets an item be shown publicly). Reject sets status to 'rejected', which keeps it private. Neither deletes the submission, removes the video, or contacts the submitter.
In the inbox, these buttons live in the expanded quick-actions row (open the … menu on a card). On the detail page they sit in the top-right header for pending items. After a successful change the badge updates immediately.
Permission required: submissions:write. That means owner, admin and editor can approve/reject. Viewers cannot — the API returns 403 Forbidden.
Errors are swallowed silently in the UI. The dashboard and detail page only update the badge when the request returns OK; if the request fails (e.g. 403 for a viewer, or a server error) nothing visible happens and no error message is shown. If a status change doesn't 'stick', a permission or network problem is the likely cause.
Approving alone does not put praise on the Wall of Love. Use the separate 'Add to Wall of Love' action (praise submissions where the submitter consented to marketing only).
Flagging a submission
Flag sets the status to 'flagged' (typically used for inappropriate or abusive content). It uses the same PATCH endpoint and the same submissions:write permission as Approve/Reject.
On the detail page, Flag is in the Actions card and reads 'Flag as inappropriate'; once flagged it shows 'Flagged' and is disabled. In the inbox it appears alongside Approve/Reject for pending submissions. Like other status changes, flagging has no side effects beyond the status field and fires no notifications.
Flagged items are not public (only approved items are eligible for public display).
Flagging is reversible by changing the status again via the API; the detail-page Flag button itself only sets 'flagged'.
Replying to a submitter
The Replies tab on the detail page lets you send a written response. It posts to /api/submissions/[submissionId]/replies, which stores the reply against the submission and records you (the actual team member, not the workspace owner) as the author.
If the submitter left an email address AND consented to being contacted (either display consent or marketing consent), and email sending is configured on the server, the reply is also emailed to them with the subject 'A reply to your feedback'. If any of those conditions is not met, the reply is still saved but no email goes out — the UI shows an 'Emailed' badge only when delivery succeeded. The composer also tells you up front whether the reply will be emailed or will be dashboard-only.
Email delivery failures are non-fatal: the reply is persisted regardless. Reply content is required and capped at 10,000 characters.
The composer has a Video reply option in the UI, but recording is not wired up — only text replies are actually sent.
Permission required: replies:write (owner, admin, editor). Viewers cannot reply (403).
An email is only sent when: server email is configured, the submitter provided an email, and they consented to contact. Otherwise the reply is saved silently with emailSent=false.
Reply errors here ARE surfaced (the composer shows the error message), unlike status changes.
The 'Video' reply tab shows a placeholder 'Start Recording' button that is not functional; use text replies.
AI re-analysis
The Insights tab runs (or re-runs) AI analysis via POST /api/submissions/[submissionId]/analyze. Analysis produces a sentiment score, AI-detected topic tags and an AI summary, which are saved back to the submission and shown in the Insights tab and on the inbox card.
If a submission already has analysis, the endpoint returns the cached result instead of calling the AI again, unless re-analysis is forced. The detail page's 'Analyse with AI' / 'Re-analyse with AI' buttons trigger this; the inbox offers 'Analyze with AI' on cards that have content but no summary yet.
Analysis only works on submissions that have text content; there is no video transcription yet (the Transcript tab is a placeholder).
Permission required: analyze (owner, admin, editor). Viewers cannot analyse (403).
Plan-gated: AI analysis is a paid feature tied to the workspace owner's plan. On the free/Spark plan it returns 403 prompting an upgrade to Flame or Inferno.
Rate-limited to 10 analysis requests per user per hour (429 if exceeded).
Requires server-side AI configuration; if not configured it returns 503. Submissions with no text content return 400.
On the detail page, analysis failures are swallowed silently; on the inbox card the error message is shown via an alert.
Convert to praise (Roast-to-Toast)
For roast submissions with mildly negative or better sentiment, the detail-page sidebar offers 'Convert to Testimonial' (POST /api/submissions/[submissionId]/convert-to-praise). This turns a roast into a praise/testimonial: it changes the type to praise, sets marketing consent, derives a star rating from the old heat level, clears the heat level, tags it 'Converted from Roast' / 'Roast-to-Toast', prefixes the AI summary, sets status to approved, and inserts it onto the Wall of Love.
Only roast submissions can be converted (praise is rejected with a 400). The endpoint requires marketing consent in the request body — without it, it returns 400 'Marketing consent is required for conversion'.
Note: the detail-page button currently sends the request without a consent flag, so the conversion will fail server-side with the 400 above. Because the detail page swallows conversion errors silently, the button will appear to do nothing. Treat this as a known limitation rather than expected behaviour.
Permission required: submissions:write (owner, admin, editor). Viewers cannot convert (403).
Only shown for roasts whose sentiment is not strongly negative (above roughly -0.3).
Conversion auto-approves the item and adds it to the Wall of Love.
The Wall insert is non-fatal — if it fails, the type change still succeeds.
Detail-page conversion failures are not surfaced in the UI.
Creating an issue from feedback
For roast cards in the inbox, 'Create Issue' (POST /api/submissions/[submissionId]/create-issue) pushes the feedback into your connected issue tracker(s) — Jira, Linear and/or GitHub. It creates one issue per connected, enabled tracker and includes the message, author, page URL, video URL, heat level and AI tags.
Unlike automatic issue creation on new submissions, this manual action ignores each tracker's auto-create setting — if you click the button, an issue is created. On success the inbox opens the first created issue in a new tab.
If no issue tracker is connected, the API returns a 400 with a NO_TRACKER code and the inbox offers to take you to Settings → Integrations.
Permission required: submissions:write (owner, admin, editor). Viewers cannot create issues (403).
Requires at least one enabled Jira/Linear/GitHub integration on the workspace owner's account; otherwise NO_TRACKER (400).
If all trackers fail, the API returns 502 with the failure reasons; partial failures are reported alongside the created issues.
This action is exposed on roast cards in the inbox quick-actions.
Deleting a submission (GDPR)
DELETE /api/submissions/[submissionId] permanently removes a submission — this is the 'right to be forgotten' path. It first attempts to delete the associated video from storage (best-effort; a storage failure does not block the record deletion), then deletes the submission row itself.
Deletion is irreversible. There is no separate confirmation enforced by the API beyond authentication, ownership and role checks.
Permission required: submissions:write (owner, admin, editor). Viewers cannot delete (403).
The submission must belong to your workspace, or the request is rejected (403/404).
Video cleanup is non-fatal: if the stored video can't be removed, the submission record is still deleted.
There is no undo. Use this for genuine erasure requests.
Who can do what (roles)
Access is scoped to a workspace, which is the data owned by one account (the owner). Team members act inside the owner's workspace under a role. Roles and their moderation permissions are: owner and admin can do everything in this area (approve/reject/flag, reply, analyse, convert, create issues, delete); editor can do all of those too (submissions:write, replies:write, analyze); viewer is read-only and can view submissions and replies but cannot moderate, reply, analyse, convert, create issues or delete.
All write actions are enforced server-side: the API verifies the submission belongs to your workspace and that your role permits the action before performing the write. Members do not have direct database write access — writes go through a privileged server path only after these checks pass.
submissions:write covers approve, reject, flag, convert and delete — granted to owner, admin, editor.
replies:write covers sending replies — granted to owner, admin, editor.
analyze covers AI analysis — granted to owner, admin, editor (and is additionally plan-gated).
Viewers get read-only access and will receive 403 on any moderation attempt.
Frequently asked questions
- Why isn't my approved praise showing on the Wall of Love?
- Approving only changes the submission's status to 'approved' so it becomes eligible for public display — it does not publish it. Add praise to the Wall of Love using the separate 'Add to Wall of Love' action (available for praise where the submitter consented to marketing).
- I clicked Approve/Reject and nothing happened. Why?
- The dashboard only updates the status badge when the request succeeds, and it does not show errors. The most common cause is permissions — viewers cannot change status and get a silent 403. A network or server error would also fail silently. Check your role (you need owner, admin or editor).
- Does approving or rejecting notify the submitter or trigger any integration?
- No. Status changes are a single field update with no side effects — no email, no webhook and no issue creation. To contact the submitter, use the Replies tab; to push feedback to a tracker, use Create Issue.
- Will my reply always email the submitter?
- Only if the submitter left an email address, consented to being contacted, and server email is configured. Otherwise the reply is saved to the dashboard but not emailed. The composer tells you which will happen, and an 'Emailed' badge appears on replies that were delivered.
- Why does 'Convert to Testimonial' on the detail page seem to do nothing?
- The conversion endpoint requires marketing consent in the request, and the detail-page button currently sends the request without it, so the server rejects it with a 400 and the page swallows the error silently. This is a known limitation. Converting requires roast type, sufficient sentiment, and submissions:write permission.
- Why can't I run AI analysis?
- AI analysis needs the analyze permission (owner/admin/editor, not viewer), a paid plan on the workspace owner's account (Flame or Inferno), server AI configuration, and text content on the submission. It is also rate-limited to 10 runs per user per hour. Existing analysis is returned from cache unless you force a re-run.
- Can I get a transcript of a video submission?
- Not yet. The Transcript tab is a placeholder — video transcription is not implemented, and text submissions don't have transcripts.
- Is deleting a submission reversible?
- No. Deletion permanently removes the submission record and attempts to delete its video from storage. It is intended for GDPR erasure requests and cannot be undone. Only owner, admin and editor can delete.
- What can a viewer do on these pages?
- Viewers have read-only access: they can open the inbox and detail page and read submissions and replies, but cannot approve, reject, flag, reply, analyse, convert, create issues or delete. Any such attempt returns a 403.