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
| Header | Needed | What to send |
|---|---|---|
Authorization | Always | Your API key, like Bearer fr_live_xxx. |
X-Device-Id | Almost always | A random ID for this device or user. Make it once, save it, reuse it. See who is voting. |
Content-Type | When sending a body | application/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)"
}
}| Code | HTTP | What happened |
|---|---|---|
invalid_key | 401 | The API key is wrong or turned off. |
missing_device_id | 400 | The X-Device-Id header is missing. |
validation_failed | 400 | Something in the body is missing or too long. The message says what. |
not_found | 404 | That request doesn't exist. |
limit_reached | 402 | Your plan's limit was reached. |
rate_limited | 429 | This device hit its daily limit. Try again tomorrow. |
internal | 500 | Something 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
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
| Query | Default | What it does |
|---|---|---|
sort | new | top for most votes, new for newest. |
limit | 20 | How many to return, from 1 to 100. |
cursor | — | Pass nextCursor from the last page to get the next one. |
status | all | Only 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
Returns one request, in the same shape as the list.
Create a request
| Field | Needed | Rules |
|---|---|---|
title | Yes | 3 to 100 characters. |
description | No | Up to 1000 characters. |
email | No | If given, the person is told when the status changes. |
isSubscriber | No | Send 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 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
Oldest first. Takes limit and cursor, just like the request list.
{ "comments": [ /* comments */ ], "nextCursor": null }limit, or even none, and still have a nextCursor. Keep going until nextCursor is null.Add a comment
| Field | Needed | Rules |
|---|---|---|
featureId | Yes | The request to comment on. |
text | Yes | 1 to 1000 characters. |
authorName | No | Up to 60 characters. |
Returns the new comment with status 201.
Follow
Send { "email": "you@example.com" }. The person gets an email when the status changes. DELETE on the same path stops it.
{ "following": true }