Documentation REST API

REST API v1.0.0

OpenAPI 3.0 specification for the FeedbackKit platform. Build custom integrations, generate client libraries, or explore endpoints directly.

OpenAPI 3.0 REST JSON Download YAML
Base URL https://api.feedbackkit.app/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.feedbackkit.app.

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
GET /metrics/summary Aggregate metrics for the key’s project
GET /metrics/timeseries Bucketed metrics for the key’s project
GET /metrics/breakdown Metrics grouped by one dimension
GET /metrics/events Raw event feed (Pro)
GET /projects/:id/metrics/summary Aggregate metrics, incl. revenue measures (admin token)
GET /projects/:id/metrics/timeseries Bucketed metrics (admin token)
GET /projects/:id/metrics/breakdown Grouped metrics (admin token)
GET /projects/:id/metrics/events Raw event feed (admin token, Pro)

Feedback

GET /feedbacks

Retrieves all feedback for the project, sorted by vote count (descending). Merged feedback items are excluded by default.

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
curl
curl -X GET "https://api.feedbackkit.app/api/v1/feedbacks?status=approved" \
  -H "X-API-Key: your-api-key" \
  -H "X-User-Id: user_12345"

Response

200 OK
[
  {
    "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"
  }
]
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.feedbackkit.app/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.feedbackkit.app/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.feedbackkit.app/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.feedbackkit.app/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 all comments for a feedback item, sorted by creation time (ascending).

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

Response

200 OK
[
  {
    "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"
  }
]
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.feedbackkit.app/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.feedbackkit.app/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.feedbackkit.app/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"
    }
  }'

Metrics

Eight read-only operations return aggregated project metrics and the raw event feed. Four answer for the project behind an X-API-Key; four are nested under /projects/:id/metrics, take an admin bearer token, and additionally answer the SDK-user and revenue measures.

The machine-readable document is the authority for field names

This page deliberately does not restate the metrics response schemas. Every property name, type and example lives in the OpenAPI document at /openapi/openapi.yaml, which is generated from a single source and checked against the server’s own encoder by an automated drift test. A second, hand-maintained copy of those names on this page is exactly how the published contract came to declare field names the server had never sent.

A narrowed answer is a 200, not an error

Two subscription axes can narrow a metrics answer, and neither makes the feature unavailable. Every metrics response echoes what the server actually ran, so a low figure always arrives with a machine-readable reason attached — read the value, never infer it from an absence.

Axis Free Pro Team
Custom event names — events your app names itself not readable readable readable
Metrics window — how far back a query may reach 30 days 30 days 365 days

FeedbackKit’s own three predefined events — feedback_list, feedback_detail and submit_feedback — are readable on every tier. Below Pro your own event names are still ingested and retained; they simply are not counted, and they become readable on upgrade with no re-tracking.

  • event_scopeall, or predefined_only when custom event names were excluded. It narrows only the two event measures, event_count and unique_event_users; no other measure is ever affected by it.
  • retention_clamped — true when your plan narrowed the window you asked for. The request still succeeds.
  • retention_window_days — your plan’s allowance. Together with the applied date_from and date_to this makes “showing 30 of the 180 days you asked for” computable from the response alone.

The one 402

METRICS_CUSTOM_EVENTS_REQUIRE_PRO is this family’s only payment-required refusal. It is raised on exactly three requests, each of which is exclusively about custom event names and so has no narrower honest answer: a breakdown by event name, a filter naming an event outside the three predefined ones, and any request to the raw event feed. Everything else a plan affects comes back as a narrower 200.

Two different error bodies

The metrics family is not uniformly enveloped, and a client that assumes an error code is always present will fail on a 401. Failures raised by the metrics API itself — its 400s, the 402, and the API-key surface’s measure 403 — carry error as an object with a stable code. Failures raised by the shared authentication, authorization and rate-limiting layers — 401, the suspended-project and no-access 403s, 404, 429 and 500 — use the server-wide shape below, where error is a boolean and there is no code. Same property name, incompatible types; the OpenAPI document declares both for every status that can carry either.

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