Skip to main content
Documentation

Minolith Feedback API

The Feedback service lets you collect structured feedback from users, customers, and team members. Create feedback items, triage them with status and priority, add internal notes, and embed a public widget for anonymous submissions. Pairs with Changelog (turn feedback into shipped features) and Context (feed patterns back into agent memory).

Base URL: https://api.minolith.io/v1/feedback

Authentication: All endpoints (except the public widget endpoint) require an API key via the Authorization header:

Authorization: Bearer mlth_your_api_key_here

Errors: All errors follow the standard Minolith error format. See Platform API — Error Response Format for the full specification.

Content Negotiation: All endpoints support two response formats:

  • Accept: application/json — JSON (default)
  • Accept: text/markdown — Raw markdown response

Resource Shapes

Item

{
  "id": "fbk_7f3a9b2c4d1e",
  "title": "Search results are slow on large datasets",
  "body": "When I search for records with more than 10,000 results, the page takes over 15 seconds to load. This started happening after the last update.",
  "type": "bug",
  "status": "open",
  "priority": "high",
  "source": "api",
  "tags": ["performance", "search"],
  "page_url": "https://app.example.com/search",
  "user_email": "alice@example.com",
  "user_name": "Alice Chen",
  "user_id_external": "usr_12345",
  "created_at": "2026-03-17 12:00:00",
  "updated_at": "2026-03-17 14:30:00"
}

Note

{
  "id": "fbn_9d4b1e7c3a2f",
  "item_id": "fbk_7f3a9b2c4d1e",
  "body": "Confirmed — the slow query is the full-text search on the records table. Adding an index should fix it.",
  "created_at": "2026-03-17 15:00:00"
}

The notes array is included when fetching a single item via GET /items/:id.


Items

Create Item

POST /v1/feedback/items

Creates a new feedback item. Costs 1 credit.

Request body:

{
  "body": "When I search for records with more than 10,000 results, the page takes over 15 seconds to load.",
  "title": "Search results are slow on large datasets",
  "type": "bug",
  "tags": ["performance", "search"],
  "page_url": "https://app.example.com/search",
  "user_email": "alice@example.com",
  "user_name": "Alice Chen",
  "user_id_external": "usr_12345"
}
Field Type Required Description
body string yes The feedback content. Max 50,000 characters.
title string no Short summary. Max 500 characters. If omitted, the system does not generate one.
type string no One of: feedback, bug, idea, question, praise. Defaults to feedback.
tags array no Array of tag strings. Max 10 tags, each max 100 characters.
page_url string no URL of the page where the feedback was submitted. Max 2,000 characters.
user_email string no Email address of the person who submitted the feedback. Max 255 characters.
user_name string no Display name of the person who submitted the feedback. Max 255 characters.
user_id_external string no Your application's user ID for the submitter. Max 255 characters.

Response (201 Created):

{
  "data": {
    "id": "fbk_7f3a9b2c4d1e",
    "title": "Search results are slow on large datasets",
    "body": "When I search for records with more than 10,000 results, the page takes over 15 seconds to load.",
    "type": "bug",
    "status": "open",
    "priority": null,
    "source": "api",
    "tags": ["performance", "search"],
    "page_url": "https://app.example.com/search",
    "user_email": "alice@example.com",
    "user_name": "Alice Chen",
    "user_id_external": "usr_12345",
    "created_at": "2026-03-17 12:00:00",
    "updated_at": "2026-03-17 12:00:00"
  }
}

Error responses:

  • 422 — Validation error (missing body, invalid type, etc.)
  • 402 — Spending cap exceeded.

List Items

GET /v1/feedback/items

Returns a paginated list of feedback items for the authenticated project.

Query parameters:

Parameter Type Description
status string Filter by status: open, under_review, planned, in_progress, completed, declined
type string Filter by type: feedback, bug, idea, question, praise. Supports comma-separated values: type=bug,idea
priority string Filter by priority: low, medium, high, urgent. Supports comma-separated values: priority=high,urgent
tags string Filter by tags. Comma-separated. Items matching any of the listed tags are returned: tags=performance,search
user_email string Filter by submitter email (exact match)
created_after string ISO 8601 datetime. Only items created after this time.
created_before string ISO 8601 datetime. Only items created before this time.
limit integer Number of results (1-100, default 20)
cursor string Cursor from a previous response's pagination.next_cursor

Example requests:

GET /v1/feedback/items?status=open&type=bug&priority=high,urgent
GET /v1/feedback/items?tags=performance&created_after=2026-03-01T00:00:00Z
GET /v1/feedback/items?user_email=alice@example.com&limit=50
GET /v1/feedback/items?type=idea,feedback&status=open

Response (200 OK):

{
  "data": [
    {
      "id": "fbk_7f3a9b2c4d1e",
      "title": "Search results are slow on large datasets",
      "body": "When I search for records with more than 10,000 results, the page takes over 15 seconds to load.",
      "type": "bug",
      "status": "open",
      "priority": "high",
      "source": "api",
      "tags": ["performance", "search"],
      "page_url": "https://app.example.com/search",
      "user_email": "alice@example.com",
      "user_name": "Alice Chen",
      "user_id_external": "usr_12345",
      "created_at": "2026-03-17 12:00:00",
      "updated_at": "2026-03-17 14:30:00"
    },
    {
      "id": "fbk_4c5d6e7f8a9b",
      "title": null,
      "body": "Would be great if the dashboard had a dark mode option.",
      "type": "idea",
      "status": "open",
      "priority": null,
      "source": "mcp",
      "tags": ["ui"],
      "page_url": null,
      "user_email": "bob@example.com",
      "user_name": "Bob",
      "user_id_external": null,
      "created_at": "2026-03-16 09:30:00",
      "updated_at": "2026-03-16 09:30:00"
    }
  ],
  "pagination": {
    "has_more": false,
    "next_cursor": null,
    "limit": 20
  }
}

Get Item

GET /v1/feedback/items/:id

Returns a single feedback item by its ID, including its internal notes.

Response (200 OK):

{
  "data": {
    "id": "fbk_7f3a9b2c4d1e",
    "title": "Search results are slow on large datasets",
    "body": "When I search for records with more than 10,000 results, the page takes over 15 seconds to load.",
    "type": "bug",
    "status": "under_review",
    "priority": "high",
    "source": "api",
    "tags": ["performance", "search"],
    "page_url": "https://app.example.com/search",
    "user_email": "alice@example.com",
    "user_name": "Alice Chen",
    "user_id_external": "usr_12345",
    "created_at": "2026-03-17 12:00:00",
    "updated_at": "2026-03-17 15:00:00",
    "notes": [
      {
        "id": "fbn_9d4b1e7c3a2f",
        "item_id": "fbk_7f3a9b2c4d1e",
        "body": "Confirmed — the slow query is the full-text search on the records table. Adding an index should fix it.",
        "created_at": "2026-03-17 15:00:00"
      }
    ]
  }
}

Error responses:

  • 404 — Item not found.
{
  "error": {
    "code": "item_not_found",
    "message": "Feedback item 'fbk_nonexistent' not found.",
    "docs": "https://docs.minolith.io/api/feedback#get-item"
  }
}

Update Item

PUT /v1/feedback/items/:id

Updates an existing feedback item. Only status, priority, and tags can be changed — the body, title, type, and user fields are immutable after creation. Only include the fields you want to change. Free — no credit cost.

Request body (all fields optional):

{
  "status": "under_review",
  "priority": "high",
  "tags": ["performance", "search", "database"]
}
Field Type Description
status string One of: open, under_review, planned, in_progress, completed, declined
priority string One of: low, medium, high, urgent. Set to null to clear.
tags array Replaces all existing tags. Max 10 tags, each max 100 characters.

Response (200 OK):

Returns the full updated item in the same format as the create response (without notes).

Error responses:

  • 404 — Item not found.
  • 422 — Validation error (invalid status, invalid priority, etc.)

Delete Item

DELETE /v1/feedback/items/:id

Permanently deletes a feedback item and all of its notes. This is a hard delete — the item cannot be recovered. Free — no credit cost.

Response (204 No Content):

Empty response body.

Error responses:

  • 404 — Item not found.

Notes

Add Note

POST /v1/feedback/items/:id/notes

Adds an internal note to a feedback item. Notes are for your team — they are never exposed via the public widget. Free — no credit cost.

Request body:

{
  "body": "Confirmed — the slow query is the full-text search on the records table. Adding an index should fix it."
}
Field Type Required Description
body string yes Note content. Max 50,000 characters.

Response (201 Created):

{
  "data": {
    "id": "fbn_9d4b1e7c3a2f",
    "item_id": "fbk_7f3a9b2c4d1e",
    "body": "Confirmed — the slow query is the full-text search on the records table. Adding an index should fix it.",
    "created_at": "2026-03-17 15:00:00"
  }
}

Error responses:

  • 404 — Item not found.
  • 422 — Validation error (missing body).

Public Endpoint

Widget Submission

POST /v1/feedback/public/:slug

Accepts feedback from the embeddable widget. No authentication required. Rate limited by IP address: 10 submissions per IP per hour per project.

The :slug is the project's public slug, configured in the Minolith dashboard.

The widget automatically captures page_url from the browser. You can also pass user context via the widget's data- attributes (see JS Widget below).

Request body:

{
  "body": "The export button doesn't work on Firefox.",
  "title": "Export broken on Firefox",
  "type": "bug",
  "page_url": "https://app.example.com/exports",
  "user_email": "alice@example.com",
  "user_name": "Alice Chen",
  "user_id_external": "usr_12345"
}
Field Type Required Description
body string yes The feedback content. Max 50,000 characters.
title string no Short summary. Max 500 characters.
type string no One of: feedback, bug, idea, question, praise. Defaults to feedback.
page_url string no Auto-captured by the widget. Max 2,000 characters.
user_email string no Passed via widget data-user-email attribute. Max 255 characters.
user_name string no Max 255 characters.
user_id_external string no Passed via widget data-user-id attribute. Max 255 characters.

Response (201 Created):

{
  "data": {
    "id": "fbk_3e2d1c4b5a6f",
    "title": "Export broken on Firefox",
    "body": "The export button doesn't work on Firefox.",
    "type": "bug",
    "status": "open",
    "priority": null,
    "source": "widget",
    "tags": [],
    "page_url": "https://app.example.com/exports",
    "user_email": "alice@example.com",
    "user_name": "Alice Chen",
    "user_id_external": "usr_12345",
    "created_at": "2026-03-17 16:00:00",
    "updated_at": "2026-03-17 16:00:00"
  }
}

Error responses:

  • 404 — Project slug not found.
  • 422 — Validation error (missing body, invalid type).
  • 429 — Public rate limit exceeded.
{
  "error": {
    "code": "public_rate_limited",
    "message": "Rate limit exceeded. Maximum 10 submissions per hour.",
    "docs": "https://docs.minolith.io/api/feedback#rate-limiting"
  }
}

JS Widget

Embed a feedback widget on your website or application:

<script src="https://api.minolith.io/widget/feedback.js"
        data-project="your-slug"
        data-position="bottom-right"
        data-color="#6366f1"
        data-user-email="alice@example.com"
        data-user-id="usr_12345"></script>
Attribute Required Description
data-project yes Your project's public slug
data-position no Widget position: bottom-right (default), bottom-left, top-right, top-left
data-color no Primary accent color as hex. Defaults to #6366f1.
data-user-email no Pre-fills the submitter's email. Passed through to the user_email field on the created item.
data-user-id no Your application's user ID. Passed through to the user_id_external field on the created item.

The widget renders inside a Shadow DOM, so it will not conflict with your site's styles or scripts. It automatically captures the current page_url when the user submits feedback. Submissions go to POST /v1/feedback/public/:slug.


Validation Rules

Field Type Required Constraints
body (item) string yes Max 50,000 characters
title (item) string no Max 500 characters
type enum no feedback, bug, idea, question, praise. Default: feedback
status enum no open, under_review, planned, in_progress, completed, declined. Default: open
priority enum no low, medium, high, urgent. Default: null
source string no Read-only. Set automatically: api (REST API), mcp (MCP tool), widget (public widget).
tags array no Max 10 tags, each max 100 characters
page_url string no Max 2,000 characters
user_email string no Max 255 characters, must be valid email format
user_name string no Max 255 characters
user_id_external string no Max 255 characters
body (note) string yes Max 50,000 characters

Credit Costs

Action Credits Cost
Item created (API, widget, or MCP) 1 $0.01
All other operations (reads, updates, deletes, notes) 0 Free

Error Codes

Code HTTP Message
body_required 422 The body field is required.
invalid_feedback_type 422 Type '{value}' is not valid. Accepted values are: feedback, bug, idea, question, praise.
invalid_status 422 Status '{value}' is not valid. Accepted values are: open, under_review, planned, in_progress, completed, declined.
invalid_priority 422 Priority '{value}' is not valid. Accepted values are: low, medium, high, urgent.
item_not_found 404 Feedback item '{id}' not found.
public_rate_limited 429 Rate limit exceeded. Maximum 10 submissions per hour.
spending_cap_exceeded 402 Spending cap exceeded.
validation_error 422 Field-specific validation message.
not_found 404 Resource not found.
unauthorized 401 Authentication required.
rate_limit_exceeded 429 Rate limit exceeded.

All error responses include a docs URL pointing to https://docs.minolith.io/api/feedback#errors.


ID Format

Item IDs use the prefix fbk_ and note IDs use the prefix fbn_, each followed by 12 random hex characters:

fbk_7f3a9b2c4d1e
fbn_9d4b1e7c3a2f

Always use the full ID (including prefix) when referencing resources in API calls.


Rate Limiting

  • Authenticated endpoints: 100 requests per minute per API key (standard). See Platform API — Rate Limiting for full details.
  • Public widget endpoint: 10 submissions per IP address per hour per project. This limit is separate from the authenticated rate limit.

MCP Tools

The Feedback service is available via MCP for direct integration with AI coding tools.

Connection

claude mcp add --transport http minolith https://mcp.minolith.io \
  --header "Authorization: Bearer mlth_your_api_key_here" \
  --header "X-Minolith-Agent: your-agent-name"

submit_feedback

Submit a new feedback item. Costs 1 credit.

Input Schema:

{
  "type": "object",
  "properties": {
    "body": {
      "type": "string",
      "description": "The feedback content. Max 50,000 characters."
    },
    "title": {
      "type": "string",
      "description": "Short summary. Max 500 characters."
    },
    "type": {
      "type": "string",
      "enum": ["feedback", "bug", "idea", "question", "praise"],
      "description": "Type of feedback. Defaults to feedback."
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Array of tags. Max 10 tags."
    },
    "page_url": {
      "type": "string",
      "description": "URL of the page where the feedback originated."
    },
    "user_email": {
      "type": "string",
      "description": "Email of the person submitting feedback."
    },
    "user_name": {
      "type": "string",
      "description": "Name of the person submitting feedback."
    },
    "user_id_external": {
      "type": "string",
      "description": "Your application's user ID for the submitter."
    }
  },
  "required": ["body"]
}

Example:

{
  "name": "submit_feedback",
  "arguments": {
    "body": "The CSV export is missing the created_at column.",
    "title": "CSV export missing timestamp",
    "type": "bug",
    "tags": ["export", "csv"]
  }
}

list_feedback

List feedback items with optional filters.

Input Schema:

{
  "type": "object",
  "properties": {
    "status": {
      "type": "string",
      "enum": ["open", "under_review", "planned", "in_progress", "completed", "declined"],
      "description": "Filter by status."
    },
    "type": {
      "type": "string",
      "description": "Filter by type. Comma-separated for multiple: 'bug,idea'."
    },
    "priority": {
      "type": "string",
      "description": "Filter by priority. Comma-separated for multiple: 'high,urgent'."
    },
    "tags": {
      "type": "string",
      "description": "Filter by tags. Comma-separated: 'performance,search'."
    },
    "user_email": {
      "type": "string",
      "description": "Filter by submitter email (exact match)."
    },
    "limit": {
      "type": "integer",
      "description": "Max items to return (1-100, default 20)."
    }
  },
  "required": []
}

Example:

{
  "name": "list_feedback",
  "arguments": {
    "status": "open",
    "type": "bug",
    "priority": "high,urgent",
    "limit": 50
  }
}

get_feedback_item

Get a single feedback item with its notes.

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Feedback item ID (fbk_xxxxxxxx)."
    }
  },
  "required": ["id"]
}

Example:

{
  "name": "get_feedback_item",
  "arguments": {
    "id": "fbk_7f3a9b2c4d1e"
  }
}

update_feedback_status

Update the status and/or priority of a feedback item.

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Feedback item ID (fbk_xxxxxxxx)."
    },
    "status": {
      "type": "string",
      "enum": ["open", "under_review", "planned", "in_progress", "completed", "declined"],
      "description": "New status for the item."
    },
    "priority": {
      "type": "string",
      "enum": ["low", "medium", "high", "urgent"],
      "description": "New priority for the item."
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Replace all tags on the item."
    }
  },
  "required": ["id"]
}

Example:

{
  "name": "update_feedback_status",
  "arguments": {
    "id": "fbk_7f3a9b2c4d1e",
    "status": "in_progress",
    "priority": "high"
  }
}

add_feedback_note

Add an internal note to a feedback item.

Input Schema:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Feedback item ID (fbk_xxxxxxxx)."
    },
    "body": {
      "type": "string",
      "description": "Note content. Max 50,000 characters."
    }
  },
  "required": ["id", "body"]
}

Example:

{
  "name": "add_feedback_note",
  "arguments": {
    "id": "fbk_7f3a9b2c4d1e",
    "body": "Root cause identified — missing index on the records table. Fix deployed in v2.5.1."
  }
}

Example Workflows

Simple: Collect and triage feedback

Submit feedback from an agent, then triage it.

1. POST /v1/feedback/items
   {
     "body": "Users are reporting that the dashboard loads slowly after the last deploy.",
     "title": "Dashboard performance regression",
     "type": "bug",
     "tags": ["performance", "dashboard"]
   }
   -> 201, returns fbk_a3b7c1d9e5f2

2. PUT /v1/feedback/items/fbk_a3b7c1d9e5f2
   { "status": "under_review", "priority": "high" }
   -> 200

3. POST /v1/feedback/items/fbk_a3b7c1d9e5f2/notes
   { "body": "Traced to the new analytics query running on every page load. Needs to be moved to a background job." }
   -> 201

Agent workflow: Review open bugs before starting work

Use MCP tools to check for open bugs at the start of a coding session.

1. list_feedback { "status": "open", "type": "bug", "priority": "high,urgent" }
   -> Returns list of high-priority open bugs

2. get_feedback_item { "id": "fbk_7f3a9b2c4d1e" }
   -> Returns full item with notes for context

3. update_feedback_status { "id": "fbk_7f3a9b2c4d1e", "status": "in_progress" }
   -> Marks the item as being worked on

4. (after fixing the bug)
   add_feedback_note { "id": "fbk_7f3a9b2c4d1e", "body": "Fixed in commit abc123. Added index to records table." }

5. update_feedback_status { "id": "fbk_7f3a9b2c4d1e", "status": "completed" }

Widget: Embed on your app and triage submissions

1. Add the widget to your app:
   <script src="https://api.minolith.io/widget/feedback.js"
           data-project="my-app"
           data-user-email="{{user.email}}"
           data-user-id="{{user.id}}"></script>

2. Users submit feedback via the widget.
   The widget POSTs to /v1/feedback/public/my-app automatically.

3. GET /v1/feedback/items?status=open&limit=50
   -> Review new submissions

4. PUT /v1/feedback/items/fbk_xxx
   { "status": "planned", "priority": "medium", "tags": ["v3.0"] }
   -> Triage into your roadmap

Last updated: 6 Apr 2026