Introducing the SupDesk SDKs
Every serious product ends up writing an integration layer — a script that reads from an inbox, a cron job that syncs a board, an endpoint that files feedback from your own UI. The SupDesk console is great when you're at the keyboard. The moment you want to automate it, you need an API, and an API is only as good as the clients you have to talk to it.
Today we're shipping four of them.
Meet the SDKs
- JavaScript / TypeScript —
supdeskon npm. Runs unmodified in Node 18+, Deno, Bun, and Cloudflare Workers, with zero runtime dependencies. - Python —
supdeskon PyPI. One syncSupDeskclient and one asyncAsyncSupDeskclient sharing a single httpx core. - Go —
github.com/rabinapps/supdesk-go. Standard library only, so it builds anywhere Go 1.23+ runs — including Cloudflare Workers viaGOOS=wasip1. - Dart —
supdeskon pub.dev. Built on dio, so interceptors,CancelToken, and proxy adapters all work the way you already expect.
Install
npm install supdeskpip install supdeskgo get github.com/rabinapps/supdesk-godependencies:
supdesk: ^0.1.0One API, four languages
The SDKs aren't four separate wrappers; they're the same API with the same semantics in every language. If you can read submissions in one, you can read them in all four.
Auto-pagination. list() returns a page that is also an async iterable — walk every page with a for await, or pull just the first page when that's all you need.
Typed resources. Submissions, feedback, changelog entries, messages, waitlist signups, beta programs and testers, and help center articles and categories — each with the methods you'd expect and typed parameters, so typos fail at compile time instead of in production.
Typed errors. Every failure descends from a single base — SupDeskError in JS and Python, APIError in Go, SupDeskException in Dart — so one catch handles the lot while instanceof or errors.As still narrows to the specific case.
Webhooks. constructEventFromRequest, construct_event_from_headers, ConstructEvent, and constructEventFromHeaders verify SupDesk's signature in constant time, so you can trust what your receiver acts on.
Resilience built in. Every client retries with exponential backoff and jitter, honours Retry-After, and never retries a metered POST it might already have accepted — a flaky network can't double-file a user's ticket.
Server-side by design
SupDesk API keys authenticate as your entire project, so the SDKs refuse to run in a browser — the JS and Dart constructors throw if they detect a DOM or a client build, and the READMEs are blunt about why. Keep the key in a server-side environment variable, behind an endpoint you control.
Two more things worth knowing: reads work on every plan, while writes (POST/PATCH/DELETE) require a paid plan; and keys are project-scoped, so give each environment its own and you can revoke one without touching the rest.
Where SupDesk fits
The SDKs are the backend half of the SupDesk SaaS integration guide — multi-tenant support, API access, and webhooks for products that want support embedded in their own systems. The full reference lives in the API documentation.
Get started
Grab an API key from Workspace Settings → API Keys, install the client for your stack, and run the quick start on this page. Then clone the repo and read the README.
Server-side SDKs for backend integration
Live code examples pulled from each SDK's GitHub repository.
import { SupDesk } from "supdesk";
const supdesk = new SupDesk({ apiKey: process.env.SUPDESK_API_KEY! });
// Auto-pages: iterating walks every page for you.
for await (const submission of await supdesk.submissions.list({
status: "open",
})) {
console.log(submission.title);
}
await supdesk.submissions.create({
type: "bug",
title: "Export button does nothing",
email: "user@example.com",
body: "Clicking Export on the reports page has no effect.",
});from supdesk import SupDesk
supdesk = SupDesk() # api_key=... or $SUPDESK_API_KEY
# Auto-pages: iterating walks every page for you.
for submission in supdesk.submissions.list(status="open"):
print(submission.title)
supdesk.submissions.create(
type="bug",
title="Export button does nothing",
email="user@example.com",
body="Clicking Export on the reports page has no effect.",
)import "github.com/rabinapps/supdesk-go/supdesk"
client, err := supdesk.New(os.Getenv("SUPDESK_API_KEY"))
if err != nil {
log.Fatal(err)
}
page, err := client.Submissions.List(ctx, supdesk.SubmissionsListParams{
Status: ptr("open"),
})
if err != nil {
return err
}
// Auto-pages: All walks every page for you.
for sub, err := range page.All(ctx) {
if err != nil {
return err
}
fmt.Println(sub.Title)
}
_, err = client.Submissions.Create(ctx, supdesk.SubmissionsCreateParams{
Type: supdesk.SubmissionTypeBug,
Title: "Export button does nothing",
Email: "user@example.com",
Body: "Clicking Export on the reports page has no effect.",
})import 'dart:io';
import 'package:supdesk/supdesk.dart';
final supdesk = SupDesk(apiKey: Platform.environment['SUPDESK_API_KEY']!);
// Auto-pages: the stream walks every page for you.
final page = await supdesk.submissions.list(status: PostStatus.open);
await for (final submission in page.autoPaging()) {
print(submission.title);
}
await supdesk.submissions.create(
type: SubmissionType.bug,
title: 'Export button does nothing',
email: 'user@example.com',
body: 'Clicking Export on the reports page has no effect.',
);