Skip to main content

Run a Public Community Q&A Forum

Devotel Orbit hosts a peer-to-peer community board for your workspace: your end users post questions, answer each other, and vote on the best answers — crowdsourced self-service that resolves issues publicly instead of burning a ticket. Because every route is unauthenticated, signed-out visitors can read and participate without an account, and each resolved thread stays searchable for the next visitor who hits the same problem. The endpoint paths below are relative. Send them against https://api.orbit.devotel.io/api/v1.

Community vs ideas board — pick the right surface

Orbit ships two anonymous public-feedback surfaces. They serve different jobs: Point “how do I…” traffic at the community board and “I wish the product could…” traffic at the ideas board. Both solve the same underlying volume problem: fewer tickets in your inbox. The two public bases are described in the Public API reference.

1. Enable the board

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

2. Scope every request to your tenant

Every request carries your workspace slug in the ?org=<slug> query parameter — the same tenant-scoping contract the hosted help center uses. The value is your organization url slug (lowercase letters, digits, hyphens). If you serve a custom help domain, ?org= keeps the tenant scope uniform across orbit.devotel.io and your own domain, exactly as with the help center.

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 community 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 org resolved and the flag is set.

4. Browse and post

All paths below sit under /api/v1/public/community.

List questions (GET /community/questions)

The unanswered sort narrows to questions with zero answers — the queue your support team should work first. The top sort ranks by vote count. Add &q=<term> for substring search over titles and bodies, and &limit= / &offset= (cap 50 per page) to paginate. Each item returns id, title, an excerpt of the body, author_name, and the vote_count / answer_count / view_count counters.

Read a thread (GET /community/questions/:id)

The response returns the full question body plus its published answers, ordered so an accepted answer surfaces first, then by votes. Each read bumps the question’s view_count.

Ask a question (POST /community/questions)

A new question is visible to everyone immediately (201 with the cq_… id). Validation is fielded at the boundary: a title under 8 characters or a body under 15 returns 400 with per-field issues in the error envelope.

Post an answer (POST /community/questions/:id/answers)

Answering a deleted or never-published question returns the same 404 as an unknown org — visitors cannot probe which threads exist.

Vote (POST /community/questions/:id/vote, POST /community/answers/:id/vote)

One vote per visitor per target: the voter’s IP is hashed per target and de-duplicated through that hash, so a repeat call is a no-op that returns { voted: false, vote_count } with the current count. Question votes and answer votes use the same mechanism.

5. Moderation

The public surface reads only published content; a hidden thread or answer never appears in browse, search, or thread responses. Until the tenant-side moderator console ships (reserved for the next iteration — the hidden marker is already wired invisibly), keep these operator practices:
  • Answer publicly, do not ticket. When a commons question of the form “which plan includes X” lands, post the answer as an answer on the thread — every future visitor resolves it without opening your queue.
  • Seed the knowledge base. A question that recurs belongs in a published help-center article, and the article URL belongs in the thread answer.
  • Mark accepted answers once the console ships; the detail endpoint already ranks an accepted answer first when the flag is set.

6. 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 posts (questions + answers) 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 at 10,000. An oversized write returns 400 before it is stored.
  • Opt-in discovery — the 404-collapse described above denies tenant enumeration as well.
The community board is one of three self-service surfaces you can wire into your CX stack; pick per intent: For feature requests, set up the ideas board (enable settings.ideas.enabled); that guide covers the browse, vote, comment, and roadmap endpoints.