Fewchurs
Docs / REST API

REST API

Use Fewchurs from any language. Every SDK is built on these same calls.

Base URL: https://www.fewchurs.com/api/v1

Basics

Send JSON, get JSON back. Every call needs your API key and a device ID. Here is a full example:

curl https://www.fewchurs.com/api/v1/features?sort=top \
  -H "Authorization: Bearer fr_live_xxx" \
  -H "X-Device-Id: 6f1c2a9e-4b7d-4e0a-9d5f-2c8b1e3a7f10"

Browsers can call the API directly. If you can, call it from your server instead, so your key stays private.

Headers

HeaderNeededWhat to send
AuthorizationAlwaysYour API key, like Bearer fr_live_xxx.
X-Device-IdAlmost alwaysA random ID for this device or user. Make it once, save it, reuse it. See who is voting.
Content-TypeWhen sending a bodyapplication/json

Errors

When something goes wrong, you get an HTTP error code and this body:

{
  "error": {
    "code": "validation_failed",
    "message": "String must contain at least 3 character(s)"
  }
}
CodeHTTPWhat happened
invalid_key401The API key is wrong or turned off.
missing_device_id400The X-Device-Id header is missing.
validation_failed400Something in the body is missing or too long. The message says what.
not_found404That request doesn't exist.
limit_reached402Your plan's limit was reached.
rate_limited429This device hit its daily limit. Try again tomorrow.
internal500Something broke on our side. Try again.

Objects

Request. hasVoted, isFollowing and isMine are about the device in X-Device-Id.

{
  "id": "Xk3pQ9rT2mL8",
  "title": "Dark mode",
  "description": "A dark theme that follows the system.",
  "status": "planned",
  "upvoteCount": 42,
  "commentCount": 3,
  "followerCount": 12,
  "hasVoted": true,
  "isFollowing": false,
  "isMine": false,
  "createdAt": "2026-10-01T09:30:00.000Z",
  "updatedAt": "2026-10-04T14:12:00.000Z"
}

Comment. isDeveloper is true for replies you write in the dashboard.

{
  "id": "c7Hq2LmN0pRs",
  "text": "Planned for the next release.",
  "authorName": "Alex",
  "isDeveloper": true,
  "isMine": false,
  "createdAt": "2026-10-04T14:15:00.000Z"
}

status is one of open, planned, in_progress, done or declined. Show a plain label if you get a status you don't know.

Get board settings

GET/config

Tells your board how to look for this app.

{ "showBranding": true, "hideVoteCounts": false, "appName": "Habits" }

When showBranding is true, show a small "Powered by Fewchurs" line. When hideVoteCounts is true, hide the numbers.

List requests

GET/features
QueryDefaultWhat it does
sortnewtop for most votes, new for newest.
limit20How many to return, from 1 to 100.
cursor—Pass nextCursor from the last page to get the next one.
statusallOnly these statuses, comma separated. Example: planned,in_progress,done.
{ "features": [ /* requests */ ], "nextCursor": "Xk3pQ9rT2mL8" }

nextCursor is null on the last page.

Lists only include the requests your plan shows: an app's first 5 on Free, its first 200 on Starter, and all of them on Pro. See pricing.

Get one request

GET/features/{id}

Returns one request, in the same shape as the list.

Create a request

POST/features
FieldNeededRules
titleYes3 to 100 characters.
descriptionNoUp to 1000 characters.
emailNoIf given, the person is told when the status changes.
isSubscriberNoSend true if this person pays for your app. You'll see a Subscriber badge in the dashboard.
{ "title": "Dark mode", "description": "Please add a dark theme." }

Returns the new request with status 201. New requests start as open.

Vote

POST/features/{id}/vote

POST adds this device's vote. DELETE on the same path removes it. Doing it twice is safe: it won't count twice.

{ "upvoteCount": 43, "hasVoted": true }

List comments

GET/features/{id}/comments

Oldest first. Takes limit and cursor, just like the request list.

{ "comments": [ /* comments */ ], "nextCursor": null }
A page can come back with fewer comments than limit, or even none, and still have a nextCursor. Keep going until nextCursor is null.

Add a comment

POST/comments
FieldNeededRules
featureIdYesThe request to comment on.
textYes1 to 1000 characters.
authorNameNoUp to 60 characters.

Returns the new comment with status 201.

Follow

POST/features/{id}/follow

Send { "email": "you@example.com" }. The person gets an email when the status changes. DELETE on the same path stops it.

{ "following": true }