Skip to content

REST API

The FeedbackKit REST API is the HTTP interface behind every SDK: submit feedback, read votes and manage projects with plain JSON requests. Use it from any language or platform that has no FeedbackKit SDK, or generate a client from the OpenAPI file.

OpenAPI 3.0 REST JSON Download YAML
Base URL https://api.prod.getfeedbackkit.com/api/v1

Authentication

All API requests require authentication via the X-API-Key header. You can find your project API key in the FeedbackKit dashboard under Project Settings.

request headers
X-API-Key: your-project-api-key
X-User-Id: optional-user-id    # For personalized has_voted state
Content-Type: application/json

Optional: X-User-Id Header

Include the X-User-Id header to get personalized has_voted state in feedback responses. Without it, has_voted will always be false.

Field naming

Response bodies are snake_case — every field below is spelled exactly as it arrives on the wire.

Request bodies accept either casing. Both {"userId": …} and {"user_id": …} decode to the same field, so the camelCase request examples below are correct and so is the snake_case every official SDK sends.

Query parameters are read verbatim — neither convention applies, so includeMerged is spelled exactly as documented.

Endpoints Overview

All endpoints are prefixed with /api/v1. The base URL for production is https://api.prod.getfeedbackkit.com.

Method Path Description
GET /feedbacks List all feedback
POST /feedbacks Submit new feedback
GET /feedbacks/:id Get feedback by ID
POST /feedbacks/:id/votes Vote for feedback
DELETE /feedbacks/:id/votes Remove vote
GET /feedbacks/:id/comments List comments
POST /feedbacks/:id/comments Add comment
POST /users/register Register SDK user
POST /events/track Track analytics event

Feedback

GET /feedbacks

Retrieves feedback for the project, sorted by vote count (descending) unless sort says otherwise. Comment counts are totals; comment text is not included. Merged feedback items are excluded by default. The default body is a JSON array of every visible row. page and per_page do not change that array. Send paged=1 for { items, meta }. Then page defaults to 1 and per_page defaults to 20 (clamped to 1–100). A page past the end returns an empty items array and the real total. The array path has no row cap, because a cap would drop rows existing clients already receive.

Query Parameters

Parameter Type Description
status string Filter by status: pending, approved, in_progress, testflight, completed, rejected
category string Filter by category: feature_request, bug_report, improvement, other
includeMerged boolean Include merged feedback items. Default: false
sort string Sort order: votes, newest, oldest, comments. Default: votes
paged string 1 or true selects the page envelope. Omitted, the body stays a JSON array.
page integer 1-indexed page. Ignored unless paged=1. Default: 1
per_page integer Page size, clamped to 1–100. Ignored unless paged=1. Default: 20
curl
curl -X GET "https://api.prod.getfeedbackkit.com/api/v1/feedbacks?status=approved" \
  -H "X-API-Key: your-api-key" \
  -H "X-User-Id: user_12345"

Response when paged=1

Without paged=1 the same objects are returned as a JSON array, with no items or meta wrapper.

200 OK
{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "title": "Add dark mode support",
      "description": "It would be great to have a dark mode option.",
      "status": "approved",
      "category": "feature_request",
      "user_id": "user_12345",
      "vote_count": 42,
      "has_voted": false,
      "comment_count": 5,
      "created_at": "2026-02-01T10:30:00Z",
      "updated_at": "2026-02-05T14:20:00Z"
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "per_page": 20,
    "total_pages": 1
  }
}
POST /feedbacks

Creates a new feedback item. The creator automatically receives a vote (vote_count starts at 1). Triggers notifications to project members and configured integrations.

Request Body

Field Type Required Description
title string Yes Feedback title (1-200 chars)
description string Yes Detailed description (1-5000 chars)
category string Yes feature_request, bug_report, improvement, other
userId string Yes Unique identifier of the submitting user
userEmail string No Email for status update notifications
curl
curl -X POST "https://api.prod.getfeedbackkit.com/api/v1/feedbacks" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Add dark mode support",
    "description": "It would be great to have a dark mode option.",
    "category": "feature_request",
    "userId": "user_12345",
    "userEmail": "user@example.com"
  }'
GET /feedbacks/:id

Retrieves a single feedback item by its UUID.

curl
curl -X GET "https://api.prod.getfeedbackkit.com/api/v1/feedbacks/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: your-api-key" \
  -H "X-User-Id: user_12345"

Votes

POST /feedbacks/:id/votes

Adds a vote to a feedback item. Each user can only vote once per feedback.

Restrictions

  • Cannot vote on archived projects (403)
  • Cannot vote on completed or rejected feedback (403)
  • Cannot vote twice on the same feedback (409)

Request Body

Field Type Required Description
userId string Yes Unique identifier of the voting user
email string No Email for status change notifications
notifyStatusChange boolean No Opt-in to email notifications on status changes. Default: false
curl
curl -X POST "https://api.prod.getfeedbackkit.com/api/v1/feedbacks/550e8400-.../votes" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_12345",
    "email": "user@example.com",
    "notifyStatusChange": true
  }'

Response

200 OK
{
  "feedback_id": "550e8400-e29b-41d4-a716-446655440000",
  "vote_count": 43,
  "has_voted": true
}
DELETE /feedbacks/:id/votes

Removes the user's vote from a feedback item.

curl
curl -X DELETE "https://api.prod.getfeedbackkit.com/api/v1/feedbacks/550e8400-.../votes" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user_12345"}'

Comments

GET /feedbacks/:id/comments

Retrieves comments for a feedback item, oldest first. The default body is a JSON array of every comment. paged=1 selects { items, meta }, and only then do page and per_page apply, with the same clamps as the feedback list.

curl
curl -X GET "https://api.prod.getfeedbackkit.com/api/v1/feedbacks/550e8400-.../comments" \
  -H "X-API-Key: your-api-key"

Response when paged=1

Without paged=1 the same comments are returned as a JSON array.

200 OK
{
  "items": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "content": "Thanks for the suggestion! We're looking into this.",
      "user_id": "admin_user",
      "is_admin": true,
      "created_at": "2026-02-02T09:15:00Z"
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "per_page": 20,
    "total_pages": 1
  }
}
POST /feedbacks/:id/comments

Adds a comment to a feedback item. Cannot comment on archived projects.

Request Body

Field Type Required Description
content string Yes Comment text (1-2000 chars)
userId string Yes Unique identifier of the commenting user
isAdmin boolean No Whether this is an admin comment. Default: false
curl
curl -X POST "https://api.prod.getfeedbackkit.com/api/v1/feedbacks/550e8400-.../comments" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "This would be really helpful!",
    "userId": "user_67890",
    "isAdmin": false
  }'

Users

POST /users/register

Registers or updates an SDK user. Use this to track user activity and associate MRR (Monthly Recurring Revenue). If the user already exists, their last_seen_at timestamp and MRR will be updated.

Request Body

Field Type Required Description
userId string Yes Unique identifier of the SDK user
mrr number No Monthly Recurring Revenue for this user
curl
curl -X POST "https://api.prod.getfeedbackkit.com/api/v1/users/register" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user_12345",
    "mrr": 9.99
  }'

Response

200 OK
{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "user_id": "user_12345",
  "mrr": 9.99,
  "first_seen_at": "2026-01-15T08:00:00Z",
  "last_seen_at": "2026-02-08T12:30:00Z"
}

Events

POST /events/track

Tracks a custom event for analytics. Use this to measure user engagement with the feedback system.

Common Events

Event Name Description
feedback_list User viewed the feedback list
feedback_detail User viewed feedback details
submit_feedback User opened the submit form

Request Body

Field Type Required Description
eventName string Yes Name of the event (1-100 chars)
userId string Yes Unique identifier of the user
properties object No Key-value properties for the event
curl
curl -X POST "https://api.prod.getfeedbackkit.com/api/v1/events/track" \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "eventName": "feedback_list",
    "userId": "user_12345",
    "properties": {
      "filter": "feature_request",
      "sort": "votes"
    }
  }'

Models

FeedbackResponse

Field Type Description
id UUID Unique identifier
title string Feedback title
description string Detailed description
status FeedbackStatus Current status of the feedback
category FeedbackCategory Feedback category
user_id string ID of the submitting user
user_email string? Email of the submitter (if provided)
vote_count integer Total number of votes
has_voted boolean Whether the current user has voted
comment_count integer Total number of comments
total_mrr number? Combined MRR of all voters
created_at ISO 8601 Creation timestamp
updated_at ISO 8601 Last update timestamp
rejection_reason string? Explanation for rejection (max 500 chars)
merged_into_id UUID? ID of feedback this was merged into
merged_at ISO 8601? When this feedback was merged
merged_feedback_ids UUID[]? IDs of feedback merged into this one

FeedbackStatus

Value Description Voting
pending New, awaiting review Allowed
approved Accepted for consideration Allowed
in_progress Currently being worked on Allowed
testflight Available in beta/TestFlight Allowed
completed Shipped and available Blocked
rejected Won't be implemented Blocked

FeedbackCategory

Value Description
feature_request New functionality request
bug_report Issue or problem report
improvement Enhancement to existing feature
other General feedback

VoteResponse

Field Type Description
feedback_id UUID ID of the feedback item
vote_count integer Updated vote count
has_voted boolean Whether the user has voted after this action

CommentResponse

Field Type Description
id UUID Unique identifier
content string Comment text
user_id string ID of the commenting user
is_admin boolean Whether this is an admin comment
created_at ISO 8601 Creation timestamp

Error Handling

All errors follow a consistent format with an error boolean and a human-readable reason string.

error response
{
  "error": true,
  "reason": "Invalid API key"
}

HTTP Status Codes

Code Name Description
200 OK Request succeeded
400 Bad Request Validation error (missing or invalid fields)
401 Unauthorized Missing or invalid API key
402 Payment Required Subscription tier limit exceeded
403 Forbidden Action not allowed (archived project, completed feedback, etc.)
404 Not Found Resource does not exist
409 Conflict Duplicate action (e.g., already voted)
429 Too Many Requests Rate limit exceeded

Subscription Tiers

Some API features are limited by subscription tier. Exceeding limits returns a 402 Payment Required response.

Feature Free Pro Team
Projects 1 2 Unlimited
Feedback per project 10 Unlimited Unlimited
Team members - - Unlimited
Integrations - All All
Voter notifications - - Yes