Developers

Noteloop API reference

A small, predictable REST API. Send and read feedback, manage projects, and power a public roadmap. Everything speaks JSON over HTTPS.

Base URL

All endpoints are served from the /api path of your Noteloop installation. On the hosted instance that is:

https://noteloop.dev/api

Requests and responses are application/json (except binary uploads, which are sent as base64 data URLs inside the JSON body). All timestamps are ISO 8601 UTC strings. Self-hosted? Swap the host for your own domain.

Authentication

Noteloop has two authentication schemes:

1 · API key (ingest)

For sending feedback and reading your widget config from untrusted clients (browser widget, mobile, server-to-server). Send it in the x-api-key header.

x-api-key: ntl_xxxxxxxx…

Keys are public-by-design and scoped to a single project. Create them in Dashboard → Project settings → API keys.

2 · Bearer token (management)

For dashboard/management calls tied to a user account. Obtain a JWT from /api/auth/login and send it as a bearer token.

Authorization: Bearer <jwt>

Project-scoped endpoints additionally require an x-project-id header identifying which project you act on. You must be a member of that project.

Rate limits & errors

Ingest requests are rate-limited per API key. When you exceed the limit you receive a 429 with a Retry-After header (seconds). Errors always return a JSON body of the shape { "error": "message" }.

StatusMeaning
200 / 201Success
204Success, no content (deletes)
400Validation failed / missing project context
401Missing or invalid credentials
403Authenticated but not allowed (wrong role, disabled feature)
404Resource not found
409Conflict (e.g. email already registered)
429Rate limited — see Retry-After

Ingest API — submit feedback

The single most important endpoint. This is what the widget calls, and what you call if you build your own reporter. Authenticated with an API key.

POST/api/feedbacksauth: API key

Only description and metadata are required — everything else is optional. Anonymous submissions (no email) are allowed.

Body fields

FieldTypeNotes
descriptionstringRequired. 1–10 000 chars — the feedback message.
metadataobjectRequired. { userAgent, url, timestamp, viewport?, customData? }
emailstring?Reporter email. Omit or send "" for anonymous.
titlestring?≤200 chars. Auto-derived / AI-generated when omitted.
screenshotstring?Base64 data URL (image/png).
audiostring?Base64 data URL of a voice note.
consoleLogsarray?≤200 { level, message, timestamp, stack? }
networkLogsarray?≤100 { method, url, status, durationMs, timestamp, error? }
breadcrumbsarray?≤50 { type: click|input|navigate, label, timestamp }
targetElementobject?{ selector, label, rect? } — the marked broken element.
identifiedUserobject?{ id?, email?, name?, attributes? } — who the reporter is.

Example request

curl -X POST https://noteloop.dev/api/feedbacks \
  -H "x-api-key: ntl_xxxxxxxx…" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "The export button does nothing on Safari.",
    "email": "user@example.com",
    "metadata": {
      "userAgent": "Mozilla/5.0 …",
      "url": "https://app.example.com/reports",
      "timestamp": 1782900000000,
      "viewport": { "width": 1440, "height": 900 }
    }
  }'

Example response — 201

{ "id": "f1e2d3c4-…" }

Widget configuration

The widget fetches its per-project styling/behaviour at init. Authenticated with an API key; you rarely call this yourself.

GET/api/widget-configauth: API key

Returns the merged config (primary color, launcher position, tooltip, locale and the capture toggles for voice / breadcrumbs / console / network). The dashboard is the source of truth — edit it under Project settings → Widget.

Auth API

Account endpoints. Registration may be disabled on an instance (ALLOW_REGISTRATION=false) once the first admin exists.

POST/api/auth/registerauth: none

Body { email, password (≥8), name? }{ token, user, defaultProjectId }.

POST/api/auth/loginauth: none

Body { email, password }{ token, user }. Use the token as your bearer credential.

PATCH/api/auth/meauth: Bearer

Update your profile. Changing email/password requires currentPassword. Returns a fresh { token, user }.

Management API — read & triage

Project-scoped endpoints. All require a Bearer token plus the x-project-id header.

GET/api/feedbacksauth: Bearer + project

List & filter feedback. Query params: status (open·in_progress·resolved·archived), priority, category, assigneeId (none = unassigned), search, tagId, page, pageSize (≤100). Returns { items, total, page, pageSize }.

GET/api/feedbacks/:idauth: Bearer + project
PATCH/api/feedbacks/:idauth: Bearer + project

Update status, priority, assigneeId, category or tags.

GET/api/feedbacks/:id/similarauth: Bearer + project

Possible duplicates (word-overlap heuristic).

Comments

GET/api/comments/:feedbackIdauth: Bearer + project
POST/api/comments/:feedbackIdauth: Bearer + project

Body { body, internal? }body is 1–5 000 chars; internal marks it as a team-only note.

DELETE/api/comments/:feedbackId/:idauth: Bearer + project

API keys

GET/api/keysauth: Bearer + project
POST/api/keysauth: Bearer (owner/admin)

Creates a key — the full ntl_… value is returned once on creation; afterwards only a masked form is shown.

DELETE/api/keys/:idauth: Bearer (owner/admin)

Public roadmap API

Public, unauthenticated endpoints for a project that has enabled its roadmap. Drives the /roadmap/:slug page.

GET/api/roadmap/:slugauth: none

Returns items bucketed into planned / inProgress / done, each with an upvotes count.

POST/api/roadmap/:slug/:feedbackId/voteauth: none

Body { voterToken } (8–100 chars, generated & stored client-side). Votes are de-duplicated per token.

Prefer the drop-in widget?

You don't need to touch the API to collect feedback. Drop the widget on any page and it handles screenshots, annotations, console/network capture and submission for you:

<script>
  window.noteloopConfig = { apiKey: "ntl_xxxxxxxx…" };
</script>
<script src="https://noteloop.dev/widget/noteloop-widget.js" defer></script>

Questions? Contact us — we're happy to help you integrate.