Представляем SDK SupDesk
Каждый серьёзный продукт рано или поздно пишет слой интеграции — скрипт, читающий из почтового ящика, задачу cron, синхронизирующую доску, или эндпоинт, принимающий обратную связь из вашего собственного интерфейса. Консоль SupDesk отлична, пока вы сидите за клавиатурой. Но как только требуется автоматизация, вам нужен API, а API хорош ровно настолько, насколько хороши клиенты для работы с ним.
Сегодня мы выпускаем четыре таких клиента.
Знакомьтесь с SDK
- JavaScript / TypeScript —
supdeskв npm. Работает без изменений в Node 18+, Deno, Bun и Cloudflare Workers, не имея сторонних рантайм-зависимостей. - Python —
supdeskв PyPI. Один синхронный клиентSupDeskи один асинхронный клиентAsyncSupDesk, использующие единое ядро на базе httpx. - Go —
github.com/rabinapps/supdesk-go. Использует только стандартную библиотеку, поэтому собирается везде, где работает Go 1.23+, включая Cloudflare Workers черезGOOS=wasip1. - Dart —
supdeskв pub.dev. Построен на базе dio, поэтому перехватчики,CancelTokenи адаптеры прокси работают привычным образом.
Установка
npm install supdeskpip install supdeskgo get github.com/rabinapps/supdesk-godependencies:
supdesk: ^0.1.0Один API, четыре языка
Наши SDK — это не четыре изолированные обёртки, а один и тот же API с одинаковой семантикой на всех языках. Если вы научились читать обращения на одном из них, вы сможете делать это на всех четырёх.
Автопагинация. Метод list() возвращает страницу, которая одновременно является асинхронным итерируемым объектом — перебирайте все страницы через for await или запрашивайте только первую, если этого достаточно.
Типизированные ресурсы. Обращения, обратная связь, записи журнала изменений, сообщения, заявки в список ожидания, бета-программы и тестировщики, а также статьи и категории центра помощи — каждый ресурс оснащён ожидаемыми методами и типизированными параметрами, благодаря чему опечатки отлавливаются на этапе компиляции, а не в продакшене.
Типизированные ошибки. Все сбои наследуются от единого базового класса — SupDeskError в JS и Python, APIError в Go, SupDeskException в Dart — поэтому один блок catch обрабатывает всё, пока instanceof или errors.As сужают тип до конкретного случая.
Вебхуки. constructEventFromRequest, construct_event_from_headers, ConstructEvent и constructEventFromHeaders проверяют подпись SupDesk за константное время, чтобы вы могли доверять входящим данным.
Встроенная отказоустойчивость. Каждый клиент выполняет повторные попытки с экспоненциальной задержкой и джиттером, учитывает заголовок Retry-After и никогда не повторяет платный POST-запрос, который мог быть уже принят — нестабильная сеть не приведёт к дублированию тикета пользователя.
Серверное применение по проекту
Ключи API SupDesk авторизуют доступ от имени всего вашего проекта, поэтому SDK отказываются работать в браузере — конструкторы JS и Dart выбрасывают исключение при обнаружении DOM или клиентской сборки, а в файлах README четко объяснена причина. Храните ключ в серверных переменных окружения за контролируемым вами эндпоинтом.
Ещё две важные детали: чтение доступно на всех тарифах, тогда как запись (POST/PATCH/DELETE) требует платного тарифа; кроме того, ключи ограничены рамками проекта, поэтому выдавайте каждому окружению свой ключ, чтобы иметь возможность отозвать один без вреда для остальных.
Где применяется SupDesk
Эти SDK составляют серверную часть руководства по интеграции SupDesk в SaaS — мультитенантная поддержка, доступ к API и вебхуки для продуктов, желающих встроить поддержку в собственные системы. Полный справочник доступен в документации API.
Как начать
Получите API-ключ в разделе Настройки рабочего пространства → Ключи API, установите клиент для вашего стека и выполните быстрый старт с этой страницы. Затем клонируйте репозиторий и прочитайте README.
Серверные SDK для интеграции с бэкендом
Живые примеры кода, загружаемые из репозитория GitHub каждого SDK.
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.',
);