Skip to content

REST API: send feedback, read themes

Last updated October 25, 2026

Send feedback to Camelus from any server, and read the themes it builds, with plain HTTP requests. Responses never contain original feedback text or personal data: only AI summaries and counts.

The machine-readable version of this page is the OpenAPI document at api.camelus.si/v1/openapi.json. It includes the webhook payloads too.

Authentication

Create an API key in Settings → API & MCP. Keys look like ck_live_abc123_…, are shown once, and belong to a workspace, not to a person. Send the key as a bearer token:

Authorization: Bearer ck_live_abc123_…

Each key has scopes:

Scope Allows Plans
feedback:write POST /v1/feedback All
read Reading items and themes, and the MCP server Pro, Studio
themes:write Changing a theme's status Pro, Studio

Keep keys on your server. Revoke a key in Settings when you no longer need it.

Send feedback

curl https://api.camelus.si/v1/feedback \
  -H "Authorization: Bearer $CAMELUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "product": "habits",
    "text": "Export uses US dates, I am in France.",
    "external_id": "zendesk-4412",
    "person": { "id": "u_123", "email": "ana@example.com", "name": "Ana" },
    "metadata": { "plan": "pro", "app_version": "2.3.1" }
  }'
Field Type Notes
product string, required The product's slug, shown on the product page.
text string, required The feedback itself. Text beyond 10,000 characters is cut, and the item is marked truncated.
title string Up to 200 characters.
external_id string Your id for this message (a ticket number, a row id). Sending the same id twice creates one item.
person object id (your user id), email, name. All optional. Without them the feedback is anonymous.
metadata object Anything useful for triage: plan, app version, browser. Up to 4 KB of JSON.
page_url string The page the feedback is about.
created_at ISO 8601 date-time When the feedback was given, for imports. Defaults to now.

A new item returns 202 Accepted with { "id": "k57c…", "status": "received" }.

Retries are safe. A request with the same external_id as an earlier one, or with no external_id and the same text from the same person within 10 minutes, returns 200 OK with the first item's id and "duplicate": true.

Read themes

curl "https://api.camelus.si/v1/themes?product=habits&status=open&sort=score&limit=20" \
  -H "Authorization: Bearer $CAMELUS_API_KEY"

sort is score (the default), requesters, mrr, trend or recent. limit goes up to 100. Themes that have only one item so far (candidates) aren't listed.

Change a theme's status, with an optional note for its timeline:

curl -X PATCH https://api.camelus.si/v1/themes/k97d… \
  -H "Authorization: Bearer $CAMELUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "planned", "note": "On the roadmap for November" }'

Statuses are open, planned, in_progress, shipped, declined and closed. A change fires theme.status_changed to your destinations, and shipped drafts an email to the people who asked.

Reference

POST /v1/feedback

Stores one feedback item. Returns 202 for a new item, 200 with the same id for a repeat (same external_id, or same text from the same person within 10 minutes). Scope: feedback:write.

GET /v1/feedback/{id}

Processing results of one item: summary, type, sentiment, urgency and theme. No original text or personal data. Scope: read.

GET /v1/themes

Themes ranked by score (or another sort), optionally for one product and status. Scope: read.

GET /v1/themes/{id}

Summary, stats, up to 10 representative item summaries and linked external work. Scope: read.

PATCH /v1/themes/{id}

Sets the status and adds an optional note to the timeline. Fires theme.status_changed to subscribed destinations. Scope: themes:write.

Theme

Returned by GET /v1/themes (in data) and inside webhook payloads.

Field Type Notes
id string
product object
title string
summary string or null
type bug · feature_request · question · complaint · praise · other
status open · planned · in_progress · shipped · declined · closed
score number
trend new · rising · falling · stable
requesters integer
paying_requesters integer
mrr_affected_cents integer or null null when no billing connector is set up; never estimated
item_count integer
sentiment object
last_item_at string or null
url string The theme in the Camelus app

Theme detail

Returned by GET /v1/themes/{id} and PATCH /v1/themes/{id}: every Theme field, plus:

Field Type Notes
representative_items object[], optional Up to 10, chosen by code: most recent, highest weight, diverse sources
external_links object[], optional

Feedback item

Field Type Notes
id string
product object
source string
status received · processing · processed · needs_review · archived · spam
received_at string ISO 8601 date-time, UTC
external_id string or null
language string or null
summary_en string or null
type bug · feature_request · question · complaint · praise · other or null
sentiment negative · neutral · positive or null
urgency low · medium · high or null
theme_id string or null

Limits

  • 60 requests a minute per API key. Past that, the API answers 429 with a Retry-After header.
  • Request bodies up to 128 KB.
  • Past your plan's monthly item limit, feedback is still accepted and stored. It's never dropped.

Errors

Errors use standard HTTP status codes and a JSON body:

{ "error": { "code": "invalid_body", "message": "person.email: Invalid email address" } }
Status Code Meaning
400 invalid_json, invalid_body, invalid_query The body isn't JSON, or a field or parameter is missing or invalid. The message names it.
401 unauthorized The key is missing, malformed or revoked.
403 forbidden, plan_required, source_disabled The key lacks the scope, the plan doesn't include the read API, or the product's API source is turned off.
404 product_not_found, not_found No such product slug, item or theme in the key's workspace.
409 merged The theme was merged into another one.
413 too_large The body is too big.
429 rate_limited Too many requests for this key. Wait for the number of seconds in Retry-After.