SDKs
Typed clients for JavaScript and Python, with webhook verification built in.
Both SDKs are built from the OpenAPI spec, have no dependencies, and cover every endpoint in the API reference. Use them on your server; never ship an API key to a browser.
JavaScript and TypeScript
Runs in Node.js 18+, Next.js, Remix, Express, Bun, Deno, Cloudflare Workers and Vercel Edge.
npm install @feedbackdots/sdk
import { FeedbackDots } from '@feedbackdots/sdk';
const feedbackdots = new FeedbackDots({ apiKey: process.env.FEEDBACKDOTS_API_KEY! });
// Reports
const { data } = await feedbackdots.reports.list({ status: 'Triage', severity: 'High' });
const report = await feedbackdots.reports.get(data[0].id);
console.log(report.context.console_logs);
await feedbackdots.reports.update(report.id, { status: 'Done' });
await feedbackdots.reports.comments.create(report.id, { body: 'Fixed in v2.3.1' });
// Feature requests, every page
for await (const idea of feedbackdots.featureRequests.listAll({ status: 'open' })) {
console.log(idea.votes, idea.title);
}
Every method returns typed objects. Failed requests throw a FeedbackDotsError with status, type and message.
| Method | Endpoint |
|---|---|
workspace.get() | GET /me |
projects.list(), projects.listAll(), projects.get(id) | /projects |
reports.list(), reports.listAll(), reports.get(id), reports.create(), reports.update(id) | /reports |
reports.comments.list(reportId), reports.comments.create(reportId) | /reports/{id}/comments |
featureRequests.list(), featureRequests.listAll(), featureRequests.get(id), featureRequests.create(), featureRequests.update(id) | /feature-requests |
In a Next.js route handler
// app/api/support-ticket/route.ts
import { FeedbackDots } from '@feedbackdots/sdk';
const feedbackdots = new FeedbackDots({ apiKey: process.env.FEEDBACKDOTS_API_KEY! });
export async function POST(request: Request) {
const ticket = await request.json();
const report = await feedbackdots.reports.create({
project_id: process.env.FEEDBACKDOTS_PROJECT_ID!,
title: ticket.subject,
description: ticket.body,
reporter_email: ticket.from,
});
return Response.json({ url: report.dashboard_url });
}
Python
Works with Python 3.9+, Django, Flask, FastAPI and scripts. Responses are plain dicts shaped like the API reference.
pip install feedbackdots
import os
from feedbackdots import FeedbackDots, FeedbackDotsError
client = FeedbackDots(api_key=os.environ["FEEDBACKDOTS_API_KEY"])
reports = client.reports.list(status="Triage", severity="High")["data"]
report = client.reports.get(reports[0]["id"])
client.reports.update(report["id"], status="Done")
client.reports.comments.create(report["id"], body="Fixed in v2.3.1")
for idea in client.feature_requests.list_all(status="open"):
print(idea["votes"], idea["title"])
Method names match the JavaScript SDK in snake_case: feature_requests.list_all() and so on.
Verifying webhooks
Both SDKs check the X-FeedbackDots-Signature header and the timestamp, and return the parsed event. Pass the raw body, before any JSON parsing.
// Next.js: app/api/feedbackdots/route.ts
import { verifyWebhook } from '@feedbackdots/sdk';
export async function POST(request: Request) {
const event = await verifyWebhook({
secret: process.env.FEEDBACKDOTS_WEBHOOK_SECRET!,
body: await request.text(),
headers: request.headers,
});
if (event.event === 'report.created') console.log('New report:', event.report.title);
return new Response(null, { status: 204 });
}
# Django
from django.http import HttpResponse, HttpResponseBadRequest
from feedbackdots import verify_webhook, WebhookVerificationError
def feedbackdots_webhook(request):
try:
event = verify_webhook(
secret=settings.FEEDBACKDOTS_WEBHOOK_SECRET,
body=request.body,
headers=request.headers,
)
except WebhookVerificationError:
return HttpResponseBadRequest()
if event["event"] == "feature_request.status_changed":
print(event["feature_request"]["title"], event["feature_request"]["status"])
return HttpResponse(status=204)
In Express, read the body with express.raw({ type: 'application/json' }) so it isn't parsed before you verify it.
Other languages
Generate a client from /api/v1/openapi.json with any OpenAPI generator, or call the API directly; it's plain JSON over HTTPS.