Introducing the SupDesk SDKs

SupDesk Team

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 / TypeScriptsupdesk on npm. Runs unmodified in Node 18+, Deno, Bun, and Cloudflare Workers, with zero runtime dependencies.
  • Pythonsupdesk on PyPI. One sync SupDesk client and one async AsyncSupDesk client sharing a single httpx core.
  • Gogithub.com/rabinapps/supdesk-go. Standard library only, so it builds anywhere Go 1.23+ runs — including Cloudflare Workers via GOOS=wasip1.
  • Dartsupdesk on pub.dev. Built on dio, so interceptors, CancelToken, and proxy adapters all work the way you already expect.

Install

npm install supdesk
pip install supdesk
go get github.com/rabinapps/supdesk-go
dependencies:
  supdesk: ^0.1.0

One 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.

Get started at supdesk.app

Server-side SDKs for backend integration

Live code examples pulled from each SDK's GitHub repository.

RabinApps/supdesk-nodeJavaScript / TypeScript
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.",
});
RabinApps/supdesk-pythonPython
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.",
)
RabinApps/supdesk-goGo
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.",
})
RabinApps/supdesk-dartDart
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.',
);

Tags

#sdk#api#developers