Feedboon

API Reference

REST API for programmatic access to feedback data.

Base URL

https://api.feedboon.com/api/v1

Authentication

Every request needs an API key in the Authorization header:

Authorization: Bearer fbk_your_api_key

Create API keys in the Feedboon dashboard under Account → API Keys.

Endpoints

GET/me

What this key can do: its permissions and the projects it can currently reach. A useful first call — a project missing here is served by no other endpoint.

GET/projects

List the projects this key can reach.

GET/feedback

List bugs in one project. Requires project_id; optional status, priority, page and per_page.

GET/feedback/:id

Get one bug with its description, page context, metadata and console errors.

PATCH/feedback/:id

Update title, description, status, priority or assignee. Accepts the bug id, the reference the dashboard shows, or the external_id it was imported with.

GET/feedback/:id/comments

List the comments on a bug.

POST/feedback/:id/comments

Add a comment to a bug.

POST/feedback/bulk

Import up to 50 bugs at once. Two steps: preview shows where they would land, confirm writes them.

POST/imports/:batch_id/undo

Take back one import. The bugs are archived and can be restored from the dashboard.

Example request

Terminal
curl -X GET "https://api.feedboon.com/api/v1/feedback?project_id=YOUR_PROJECT_ID&status=new" \
  -H "Authorization: Bearer fbk_your_api_key"

Project ids come from GET /projects.

Response

response.json
{
  "data": {
    "items": [
      {
        "id": "8f14e45f-ceea-467a-9f0c-2b1a3d5e7c91",
        "feedback_number": 7,
        "feedback_prefix": "FB",
        "title": "Checkout button does nothing",
        "status": "new",
        "priority": "high",
        "page_url": "https://acme.com/checkout",
        "browser": "Chrome 120",
        "has_screenshot": true,
        "has_console_errors": true,
        "created_at": "2026-01-25T10:30:00Z"
      }
    ],
    "meta": {
      "page": 1,
      "per_page": 20,
      "total": 1,
      "total_pages": 1
    }
  },
  "error": null
}

feedback_prefix and feedback_number are the reference a human reads on the card — "FB-7" above. id is the one to pass back to the API.

Importing bugs in bulk

Bulk import is two calls on purpose, so a batch can never land in the wrong project unnoticed. The first writes nothing and tells you where the items would go; the second writes them.

Step 1 — preview

Terminal
curl -X POST https://api.feedboon.com/api/v1/feedback/bulk \
  -H "Authorization: Bearer fbk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "acme",
    "items": [{
      "external_id": "BUG-042",
      "title": "Checkout button does nothing",
      "page_url": "https://acme.com/checkout",
      "found_in": "pre_release"
    }]
  }'

The response names the project, counts what is new versus what would be updated, and returns confirm_token together with next_step — the exact call to make next.

Step 2 — confirm

Terminal
curl -X POST https://api.feedboon.com/api/v1/feedback/bulk \
  -H "Authorization: Bearer fbk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "acme",
    "mode": "confirm",
    "confirm_token": "<from the preview response>",
    "items": [ ... the same items, unchanged ... ]
  }'

Two things the token enforces: it belongs to one project, and it is bound to the exact items it previewed. Editing an item between the calls invalidates it, as does letting it expire — the window is returned as confirm_token_expires_in.

Two fields are worth getting right. external_id is your own id for the bug, and re-sending it updates that bug instead of creating a duplicate. found_in is required and says where the bug was found — pre_release, staging or production.

Keys, rotation and revocation

A key reaches only the projects it was created for, and only while its owner still has access to them — remove someone from a project and their keys stop reaching it on the next request.

Revoking takes effect immediately, because every request re-checks the key. Replacing one is different: a long-running process reads its environment once at start, so a new key takes effect after that process restarts. Rotation issues the replacement while the previous key keeps working for 24 hours, which is what makes changing keys a non-event.

Responses and limits

Every response — success or error — is JSON shaped { data, error }, and the HTTP status carries the outcome: 401 for a missing or invalid key, 400 for input the API rejected, with error.message naming the field.

Requests are rate limited per key, reads more generously than writes. Over the limit the API answers 429 with code RATE_LIMITED; wait and retry. Batch your work where you can — one bulk import of 50 bugs costs a single call.

Troubleshooting

A response that is not JSON. If you receive HTML or plain text, the request was answered before it reached Feedboon — it is not about your API key or your project permissions. Send a User-Agent that identifies your application and retry.

An import that keeps previewing. The write happens only with mode: "confirm" and the token from the preview. Other spellings are rejected rather than silently previewed, and the preview response carries the call to make in next_step.

OpenAPI specification

The full machine-readable description, for generating a client or importing into Postman and Insomnia:

Terminal
curl https://api.feedboon.com/api/v1/openapi.json