---
title: "Report an in-app issue."
method: POST
path: "/v1/support-issues"
tags: ["support-issues"]
---

# Report an in-app issue.

`POST /v1/support-issues`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/support-issues`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

Files an in-app "Report an issue" submission against a dashboard (support-reporting epic). Open to any authenticated member wherever the surface exists — anyone hitting a dashboard problem must be able to report it, so this adds no per-user capability check beyond authentication. It IS edition-gated (POLISH-61): the deployment must have `editionCapabilities.reportIssue` true, which is false in snowflake mode, where a filed report would land in the app's own in-account Postgres and reach nobody at dvt — see the `403` below and the `reportIssue` cell on `Me.editionCapabilities`. The full dashboard spec is captured server-side from `dashboardId` (the client never sends the spec) and a best-effort render snapshot is attached. `scope` is `element` (with `elementIds`), `page`, or `dashboard`.

## Request body

- CreateSupportIssueRequest
  - `dashboardId` string, uuid, required: The dashboard the issue is about. The server reads its spec authoritatively — the client never sends the spec.
  - `pageId` string: The active page id, for context. Optional.
  - `scope` 'element' | 'page' | 'dashboard', required: `element` flags specific panels (requires a non-empty `elementIds`); `page` flags the active page; `dashboard` flags the whole dashboard.
  - `elementIds` string[]: The flagged element ids. Required (non-empty) when `scope` is `element`; ignored otherwise.
  - `body` string, required: The user's description of the problem.

## Response `201`

Support issue filed.

- SupportIssueEnvelope
  - `data` SupportIssue, required: An in-app "Report an issue" submission (support-reporting epic): a user's description of a dashboard problem, scoped to the whole dashboard, the active page, or specific elements, with the full dashboard spec captured at submit time and a best-effort render snapshot. Org-scoped and tenant-isolated (ADR-0025). `specSnapshot` is present on the single-issue GET and omitted from the list.
    - `id` string, uuid, required
    - `orgId` string, uuid: The org the issue was filed in. Present on the triage (admin) reads; omitted from the submitter's create response.
    - `submittedBy` string, uuid, required: The user who filed the issue.
    - `dashboardId` string, uuid, nullable: The reported dashboard. Null if the dashboard was later deleted (the spec snapshot is the durable record).
    - `pageId` string, nullable: The active page id at submit time. Null/omitted for a whole-dashboard report.
    - `scope` 'element' | 'page' | 'dashboard', required: What the report targets. `element` carries `elementIds`; `page`/`dashboard` carry none.
    - `elementIds` string[], required: The flagged panel/element ids (empty for page/dashboard scope).
    - `body` string, required: The user's free-text description.
    - `specSnapshot` object: The full dashboard spec at submit time. Present on GET by id; omitted from the list.
    - `renderId` string, uuid, nullable: Reserved for a render snapshot of the dashboard at submit time. Always null for now — snapshot capture with a dedicated render budget is a follow-up; the triage agent re-renders from `specSnapshot` on demand in the meantime.
    - `status` 'open' | 'triaging' | 'ticketed' | 'resolved' | 'dismissed', required: Triage lifecycle state. Submissions start `open`.
    - `triageTicket` string, nullable: The PM ticket friendly-id filed for this issue during triage (e.g. "DVT-1234").
    - `triageNotes` string, nullable: The triage agent's classification / suggested-fix note.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
  - `meta` Meta, required: Response metadata.
    - `requestId` string, required: Correlates with the X-Request-Id header.
    - `total` integer: Item count, present on collection responses.
    - `nextCursor` string, nullable: Opaque keyset-pagination cursor, present on paginated responses (e.g. GET /v1/dashboards) when more rows exist beyond this page. Pass it back as the `cursor` query param to fetch the next page; absent or null on the last page.
    - `roleResolveDegraded` boolean: Snowflake mode only (DVT-2260), on GET /v1/dashboards: present and true when the caller's live Snowflake role resolution failed or was unavailable — role-shared dashboards may be missing from this page. Omitted (not merely false) whenever resolution succeeded or the role-share arm does not apply (off snowflake mode, an org admin/owner, or off the ingress listener).

## Other responses

- `400`: Malformed request.
- `401`: Missing, invalid, or expired session.
- `403`: `https://docs.dvt.dev/errors/not-in-edition` — snowflake mode only (POLISH-61): `editionCapabilities.reportIssue` is false there, so the end-user "Report an issue" CREATE path is unavailable. A report filed from a Snowflake native-app install would land in the app's own Postgres inside the consumer's account and reach nobody at dvt, so the surface is withheld rather than accepting a submission no one will read; DVT-4354 routes those submissions back to dvt and flips the cell. The SPA hides both entry points on the same cell, so only a direct API caller — or a client on a stale bundle — sees this. The admin triage routes on this resource (`GET`/`PATCH /v1/support-issues[/{id}]`) are NOT gated and stay available in every edition. Reach dvt by email in the meantime.
- `404`: Resource does not exist.

---

[API](https://skmtc.dev/dvt/apis/dvt-rest-api.md) · [All operations](https://skmtc.dev/dvt/apis/dvt-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dvt/apis/dvt-rest-api/revisions/00016f504165?raw)
