> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a Public Idea Board and Roadmap

> Enable the hosted feature-request portal, wire its unauthenticated endpoints into your CX stack, let visitors submit and vote on product ideas, and publish a roadmap that moves each idea from planned to shipped.

# Run a Public Idea Board and Roadmap

Devotel Orbit hosts a feature-request portal for your workspace: your end
users submit product ideas, upvote the ones they want, comment for context,
and watch a public roadmap move each idea from planned to shipped. This is
the Canny / Productboard class of surface — it captures and prioritizes
product feedback, distinct from the peer-to-peer
[community board](/guides/community-qa-forum) where visitors answer each
other's questions. Because every route is unauthenticated, signed-out
visitors participate without an account.

The endpoint paths below are relative. Send them against
`https://api.orbit.devotel.io/api/v1`.

## Ideas board vs community — pick the right surface

Orbit ships two anonymous public-feedback surfaces. They serve different
jobs:

|              | Ideas board (this guide)                                         | Community Q\&A                                        |
| ------------ | ---------------------------------------------------------------- | ----------------------------------------------------- |
| Purpose      | Feature requests — submit and prioritize product ideas           | Peer support — visitors answer each other's questions |
| Thread shape | Idea → comments, lifecycle runs under review → planned → shipped | Question → answers, one answer can be marked accepted |
| Vote meaning | "I want this feature"                                            | "This answer helped me"                               |
| Enable flag  | `settings.ideas.enabled`                                         | `settings.community.enabled`                          |
| API base     | `/public/ideas`                                                  | `/public/community`                                   |

Point "I wish the product could…" traffic at the ideas board and "how do I…"
traffic at the community board. Both are described in the
[Public API reference](/api-reference/endpoints/public).

## 1. Enable the board

The idea board is opt-in per workspace. Until you flip it on, the public
endpoints answer nothing. Enable it by setting
`settings.ideas.enabled = true` on your organization settings — the same
workspace-level block that holds the parallel `settings.community.enabled`
flag (dashboard **Settings → Organization**, or the organizations API). The
board's tables are created on first use per workspace, so there is nothing
to migrate and nothing to clean up if you turn the feature off again.

## 2. Scope every request to your workspace

Every request carries your workspace slug in the `?org=<slug>` query
parameter — the same tenant-scoping contract the
[hosted help center](/guides/help-center-portal) and community board use.
The value is your organization url slug (lowercase letters, digits,
hyphens). On write calls (`POST`, vote, comment) the slug travels in the
JSON body as `"org": "<slug>"`; on reads it travels as a query parameter.

## 3. Anonymous-visitor posture

The board answers only anonymous traffic; no API key or session is
accepted. To keep that posture safe, the gate collapses two failure modes
into one: an unknown organization slug and an organization that has not
enabled the idea board both return the identical **404**. A probe cannot
enumerate which tenants exist or which of them turned the feature on.
Anything other than 404 means the workspace resolved and the flag is set.

Anonymous visitors can never move an idea through its lifecycle — the
public write paths only create ideas (always landing in `under_review`),
comments, and votes. Status changes are an operator action.

## 4. Browse, submit, vote, comment

All paths below sit under `/api/v1/public/ideas`.

### List ideas (GET /public/ideas)

```bash theme={null}
# sort: top (default) | recent
curl "https://api.orbit.devotel.io/api/v1/public/ideas?org=acme&sort=top"
```

The `top` sort ranks by vote count — the queue your visitors most want.
Add `&q=<term>` for substring search over titles and bodies,
`&status=<under_review|planned|in_progress|shipped|declined>` to filter by
lifecycle stage, and `&limit=` / `&offset=` (cap 50 per page) to paginate.
Each item returns `id`, `title`, an `excerpt` of the body, `author_name`,
`category`, `status`, an optional `admin_response` note, and the
`vote_count` / `comment_count` / `view_count` counters.

### Submit an idea (POST /public/ideas)

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/public/ideas" \
  -H "Content-Type: application/json" \
  -d '{
    "org": "acme",
    "title": "Webhook retries dashboard",
    "body": "Show per-endpoint retry attempts and final delivery status in the webhook test view.",
    "author_name": "Rita M.",
    "email": "rita@example.com",
    "category": "developers"
  }'
```

A new idea is visible to everyone immediately and lands in `under_review`
(`201` with the `fi_…` id). Validation runs at the boundary: a title under
8 characters or a body under 15 returns `400` with per-field issues in the
error envelope. `category` and `locale` are optional.

### Vote on an idea (POST /public/ideas/:id/vote)

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/public/ideas/fi_8fb2d1b7c00c4ec9a1d3f5e7b9c1d36e/vote?org=acme"
```

One vote per visitor per idea: the voter's IP is hashed per idea and
de-duplicated through that hash, so a repeat call is a no-op that returns
`{ voted: false, vote_count }` with the current count.

### Comment on an idea (POST /public/ideas/:id/comments)

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/public/ideas/fi_8fb2d1b7c00c4ec9a1d3f5e7b9c1d36e/comments" \
  -H "Content-Type: application/json" \
  -d '{
    "org": "acme",
    "body": "This would save us a support ticket per week — the retry view is the missing piece.",
    "author_name": "Devotel Orbit Support",
    "email": "support@devotel.io"
  }'
```

Commenting on a hidden or never-created idea returns the same 404 as an
unknown org — visitors cannot probe which ideas exist.

### Read an idea (GET /public/ideas/:id)

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/public/ideas/fi_8fb2d1b7c00c4ec9a1d3f5e7b9c1d36e?org=acme"
```

The response returns the full idea body plus its published comments. Each
read bumps the idea's `view_count`.

## 5. The public roadmap (GET /public/ideas/roadmap)

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/public/ideas/roadmap?org=acme"
```

The roadmap returns three columns — `planned`, `in_progress`, and
`shipped` — each holding up to 50 ideas. The planned and in-progress
columns rank by vote count; the shipped column reads newest-first, so it
doubles as a "what we shipped" feed for your own change-log page. Each
idea carries the operator's `admin_response` note (for example "Shipping
in v2.4") when one is set.

## 6. Operator workflow

Visitors never touch an idea's status — moving a submission along the
lifecycle is an operator action on your side:

1. **Triage.** Work the `under_review` queue first. New submissions land
   there; `sort=top` tells you which closed queue to work next by raw
   demand.
2. **Commit.** Promote an agreed idea to `planned`, move it to
   `in_progress` when build starts, and close it as `shipped` — or answer
   `declined` with a reason. Set an `admin_response` when you do; the
   note shows publicly against the idea.
3. **Publish.** The shipped column is your published changelog feed. Read
   `GET /public/ideas/roadmap?org=<slug>` from your own site and render
   the `shipped` column next to (or as) your change-log so voters see the
   follow-through; the shipped ordering is already newest-first.
4. **Hide abuse.** Hidden ideas and comments never surface in browse,
   search, detail, or roadmap responses — the public surface reads only
   published rows.

## 7. Abuse posture

The public routes are unauthenticated, so the surface relies on
server-side limits and pseudonymised tracking rather than writer
identity:

* **Rate limits per IP** — reads at 120/min, votes at 30/min, and writes
  (submit + comment) at 5/min. A `429` means your embed is degrading or
  one visitor is scripting the board.
* **HMAC-hashed identifiers** — the author email and the visitor IP are
  stored only as irreversible hashes, computed with a server-held key. The
  hashes exist for abuse tracing and vote de-duplication; raw IPs and raw
  emails never persist.
* **Content length caps** — titles cap at 200 characters, bodies and
  comments at 10,000, author names at 80. An oversized write returns `400`
  before it is stored.
* **Opt-in discovery** — the 404-collapse described above denies tenant
  enumeration as well.

## Related surfaces

The idea board is one of three self-service surfaces you can wire into
your CX stack; pick per intent:

* [Brand and Launch Your Hosted Help Center](/guides/help-center-portal) —
  operator-curated articles with a visitor ticket form.
* [Run a Public Community Q\&A Forum](/guides/community-qa-forum) —
  peer-to-peer questions and answers.
* [Public API reference](/api-reference/endpoints/public) — field-level
  endpoint coverage of `/public/ideas` and its siblings.
