Repository navigation
2.0.0
Изменения и улучшения
Типы пакета теперь импортируются по имени, ошибки ловятся через instanceof, добавлены методы звонков и HelpDesk, вложения в сообщениях и тела всех событий вебхуков
Релиз мажорный: 16 методов переименованы, изменился CJS-импорт и поднялась минимальная версия Node. Ниже — что менять в коде, с примерами
🚀 Как обновиться
npm i getcourse-api@2Нужен Node 22 или новее — проверьте свою версию:
node -v⚠️ Ломающие изменения
Подключение через require
// было
const GetCourse = require("getcourse-api");
// стало
const { GetCourse } = require("getcourse-api");Пакет собирается с именованными экспортами, поэтому require отдаёт объект, а не сам класс. Оттуда же достаются классы ошибок:
const { GetCourse, GetCourseApiError } = require("getcourse-api");ESM-импорт не меняется ни в JavaScript, ни в TypeScript:
import GetCourse from "getcourse-api";Node 18 и 20 больше не поддерживаются
engines.node поднят с >=18 до >=22. Обе версии вышли из поддержки Node.js, пакет на них не проверяется. На Node 22 и новее ничего делать не нужно
Переименованные методы
Имена приведены к одной схеме — глагол, сущность, объект. Тела запросов и ответы не изменились, правится только имя вызова
| Было | Стало |
|---|---|
setUri |
subscribeWebhook |
addCommentToDeal |
addDealComment |
addCommentToUser |
addUserComment |
addCommentToLessonAnswer |
addLessonAnswerComment |
addCommentToWebinar |
sendWebinarMessage |
addCommentToDialog |
sendDialogMessage |
addNote |
addDialogNote |
changeDepartment |
changeDialogDepartment |
changeStatusAnswers |
changeLessonAnswerStatus |
getAllGroups |
getGroups |
getAllPersonalManagers |
getPersonalManagers |
getAllWebinars |
getWebinars |
getDealsTags |
getDealsWithTags |
getOffersTags |
getOffersWithTags |
getUserAnswers |
getUserSurveyAnswers |
moderateWebinarComment |
moderateWebinarMessage |
Переименованные типы ничего не ломают
В 1.x пакет отдавал наружу только класс — точка входа состояла из одной строки export default class GetCourse, и ни один тип по имени импортировать было нельзя. Поэтому переименования Diploma → UserDiploma, CancelReason → DealCancelReason, UpdateCustomField → UpdatedCustomField, DialogTransport → MessageTransport, SetUriRequest → SubscribeWebhookRequest, CustomField → LegacyCustomField ничей код не задевают
Начиная с этой версии имена зафиксированы и меняются только мажором
✨ Что нового
🆕 Новые методы
Восемь методов, которых не было в 1.x. Подробности с примерами — в разделах ниже
| Метод | Что делает |
|---|---|
addCallComment(body) |
Комментарий к звонку — попадает в поле «Описание» |
addCallTranscription(body) |
Транскрибация звонка, отображается как HTML |
getTicketHistory(body) |
История переписки тикета HelpDesk |
sendTicketMessage(body) |
Сообщение в тикет от имени сотрудника |
changeTicketDepartment(body) |
Перевод тикета в другой отдел |
closeTicket(body) |
Закрытие тикета с причиной из TicketCloseReason |
getDepartments() |
Отделы поддержки проекта |
unsubscribeWebhook(event) |
Отписка от события — тот же set-uri с subscribe: 0 |
🧩 Типы импортируются по имени
Наружу выведено 149 типов — модели, тела запросов, тела вебхуков, legacy, справочники:
import GetCourse, { GetCourseApiError } from "getcourse-api";
import type { CallWebhook, Deal, GetCourseConfig, User } from "getcourse-api";Отдельных путей вроде getcourse-api/types нет — всё лежит в корне пакета. В чистом JavaScript типы доступны через JSDoc:
/** @param {import("getcourse-api").User} user */
function getTelegramId(user) {
return user.bot_link.telegram[0]?.tg_user_id;
}CJS-типы тоже корректны: require в TypeScript-проекте видит те же имена
🚨 Ошибки различаются через instanceof
import { GetCourseApiError, GetCourseNetworkError, GetCourseValidationError } from "getcourse-api";
try {
await gc.getDealFields(99999);
} catch (err) {
if (err instanceof GetCourseValidationError) {
console.error(err.details); // причина с машиночитаемым кодом, запроса к API не было
}
if (err instanceof GetCourseApiError) {
console.error(err.statusCode, err.apiCode, err.errors);
}
if (err instanceof GetCourseNetworkError) {
console.error(err.cause); // таймаут, DNS, connection refused
}
}Общий предок всех трёх — GetCourseError, им ловится любая ошибка SDK разом. Новый класс здесь GetCourseValidationError: он означает, что данные не прошли проверку на стороне пакета и запрос вообще не выполнялся
📞 Звонки
await gc.addCallComment({ callId: 8421, text: "Клиент просил перезвонить в пятницу" });
await gc.addCallTranscription({
callId: 8421,
text: "<p>— Здравствуйте! Вам удобно говорить?</p><p>— Да, слушаю вас</p>",
});Комментарий попадает в поле «Описание» и принимает обычный текст, транскрибация отображается как HTML — переносы делаются через <p> или <br>. Оба метода перезаписывают значение при повторном вызове
У транскрибации есть недокументированный предел длины: на превышении API отвечает 500 с пустым errors. Для русского текста безопасный ориентир — до 4000 символов
🎫 HelpDesk
await gc.sendTicketMessage({
ticketId: 4471,
commentText: "Разобрались, доступ восстановлен",
transport: [1],
userId: 903417,
});
await gc.closeTicket({ ticketId: 4471, closedReason: 2, closedComment: "Вопрос решён" });Плюс getTicketHistory и changeTicketDepartment. Причины закрытия — справочник TicketCloseReason. HelpDesk и «Входящие» — два параллельных функционала платформы, тела их вебхуков совпадают, поэтому подписки должны идти на разные URI
📎 Вложения в сообщениях
import { readFile } from "node:fs/promises";
await gc.sendDialogMessage({
dialogId: 48812,
commentText: "Счёт во вложении",
transport: [1],
userId: 903417,
attachedFiles: [{ filename: "Счёт №1024.pdf", content: await readFile("./invoice.pdf") }],
});До 5 файлов по 5 МБ, байты принимаются как Buffer, Uint8Array или Blob. Лимиты проверяются до отправки — при превышении пакет бросит GetCourseValidationError, не заливая файлы на сервер. Расширение в filename обязательно: GetCourse определяет тип файла только по нему. Без вложений запрос уходит прежним JSON
📋 Анкеты
getUserSurveyAnswers возвращает SurveyAnswer[]: анкета, её поля и ответы, где ключ — id поля строкой. Поле — дискриминированный union по type, у каждого варианта свой набор settings:
import type { SurveyAnswer, SurveyField } from "getcourse-api";
function describeOptions(field: SurveyField): string[] {
// после сужения по type доступен valueList — у остальных полей его нет
return field.type === "select" ? field.settings.valueList.split("\n") : [];
}
function readAnswer(answer: SurveyAnswer, field: SurveyField): string | undefined {
return answer.values[String(field.id)];
}🔔 Вебхуки
Типизированы тела всех четырнадцати событий: заказы, диалоги, ответы на уроки, комментарии к ответам, комментарии вебинаров, звонки, HelpDesk
import type { DealPaidWebhook } from "getcourse-api";
app.post("/gc/deals", (req, res) => {
const event = req.body as DealPaidWebhook;
console.log(event.deal.number, event.deal.payedValue);
res.sendStatus(200);
});Добавились события подписки: сообщение от сотрудника (1.4), HelpDesk (9.1–9.3) и метод unsubscribeWebhook для отписки
Реальные примеры тел вебхуков с обезличенными данными лежат здесь: examples/webhooks
🆘 Если что-то пошло не так
Нашли расхождение с реальным поведением API или не хватает метода — заводите issue. Типы в пакете строятся на живых ответах API, а не на схеме, поэтому такие сообщения ценны
Откатиться на прежнюю версию всегда можно командой npm i getcourse-api@1.2.0