Kotlin
Типизированный клиент для Pachca API на Kotlin. Построен на Ktor с корутинами (suspend), kotlinx.serialization и встроенным retry. Требуется Kotlin 2.2+ и Java 11+.
Быстрый старт
Установка
Пакет публикуется через JitPack. Добавьте его репозиторий в settings.gradle.kts:
И зависимость в build.gradle.kts:
Версия — номер выпуска SDK, все выпуски перечислены в обновлениях.
Создание клиента
Клиенту нужен токен бота или персональный токен. Какой выбрать и кто может его выпустить, описано в разделе Какой токен выбрать.
Первый запрос
suspend-функции. Вызывайте их из корутин (runBlocking, launch, async).Инициализация
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
token | String | — | Bearer-токен для авторизации |
baseUrl | String | https://api.pachca.com/api/shared/v1 | Базовый URL API |
Клиент реализует Closeable — закройте его после использования:
Все методы
| Метод | Метод API |
|---|---|
client.oauth.revokeToken() | POSTОтзыв токена |
client.oauth.exchangeToken() | POSTОбмен кода на токен |
client.oauth.getTokenInfo() | GETИнформация о токене |
client.chats.createChat() | POSTНовый чат |
client.chats.requestExport() | POSTЭкспорт сообщений |
client.chats.listChats() | GETСписок чатов |
client.chats.downloadExport() | GETСкачать архив экспорта |
client.chats.getChat() | GETИнформация о чате |
client.chats.listCompanyChats() | GETСписок чатов пространства |
client.chats.updateChat() | PUTРедактирование чата |
client.chats.archiveChat() | PUTАрхивация чата |
client.chats.updateChatAvatar() | PUTЗагрузка аватара чата |
client.chats.unarchiveChat() | PUTРазархивация чата |
client.chats.markChatUnread() | PUTОтметка чата непрочитанным |
client.chats.deleteChatAvatar() | DELETEУдаление аватара чата |
client.profile.getProfile() | GETСвой профиль |
client.profile.getStatus() | GETСвой статус |
client.profile.updateProfileAvatar() | PUTЗагрузка своего аватара |
client.profile.updateStatus() | PUTНовый свой статус |
client.profile.deleteProfileAvatar() | DELETEУдаление своего аватара |
client.profile.deleteStatus() | DELETEУдаление своего статуса |
client.users.createUser() | POSTНовый сотрудник |
client.users.listUsers() | GETСписок сотрудников |
client.users.getUser() | GETИнформация о сотруднике |
client.users.getUserStatus() | GETСтатус сотрудника |
client.users.updateUser() | PUTРедактирование сотрудника |
client.users.updateUserAvatar() | PUTЗагрузка аватара сотрудника |
client.users.updateUserStatus() | PUTНовый статус сотрудника |
client.users.deleteUser() | DELETEУдаление сотрудника |
client.users.deleteUserAvatar() | DELETEУдаление аватара сотрудника |
client.users.deleteUserStatus() | DELETEУдаление статуса сотрудника |
client.groupTags.createTag() | POSTНовый тег |
client.groupTags.listTags() | GETСписок тегов |
client.groupTags.getTag() | GETИнформация о теге |
client.groupTags.getTagUsers() | GETСписок сотрудников тега |
client.groupTags.updateTag() | PUTРедактирование тега |
client.groupTags.deleteTag() | DELETEУдаление тега |
client.members.addTags() | POSTДобавление тегов |
client.members.addMembers() | POSTДобавление участников |
client.members.listMembers() | GETСписок участников чата |
client.members.updateMemberRole() | PUTРедактирование роли участника |
client.members.removeTag() | DELETEИсключение тега из чата |
client.members.leaveChat() | DELETEВыход из чата |
client.members.removeMember() | DELETEИсключение участника |
client.threads.createThread() | POSTНовый тред |
client.threads.createStandaloneThread() | POSTНовый самостоятельный тред |
client.threads.listThreads() | GETСписок тредов |
client.threads.getThread() | GETИнформация о треде |
client.messages.createMessage() | POSTНовое сообщение |
client.messages.unfurl() | POSTUnfurl (разворачивание ссылок) |
client.messages.pinMessage() | POSTЗакрепление сообщения |
client.messages.listChatMessages() | GETСписок сообщений чата |
client.messages.getMessage() | GETИнформация о сообщении |
client.messages.updateMessage() | PUTРедактирование сообщения |
client.messages.deleteMessage() | DELETEУдаление сообщения |
client.messages.unpinMessage() | DELETEОткрепление сообщения |
client.readMembers.listReadMembers() | GETСписок прочитавших сообщение |
client.reactions.addReaction() | POSTДобавление реакции |
client.reactions.listReactions() | GETСписок реакций |
client.reactions.removeReaction() | DELETEУдаление реакции |
client.importantMessages.addMessageToImportant() | POSTДобавление сообщения в важные |
client.importantMessages.listImportantMessages() | GETСписок важных сообщений |
client.importantMessages.removeMessageFromImportant() | DELETEУдаление сообщения из важных |
client.search.searchChats() | GETПоиск чатов |
client.search.searchMessages() | GETПоиск сообщений |
client.search.searchUsers() | GETПоиск сотрудников |
client.tasks.createTask() | POSTНовое напоминание |
client.tasks.listTasks() | GETСписок напоминаний |
client.tasks.getTask() | GETИнформация о напоминании |
client.tasks.updateTask() | PUTРедактирование напоминания |
client.tasks.deleteTask() | DELETEУдаление напоминания |
client.drafts.createDraft() | POSTНовый черновик |
client.drafts.listDrafts() | GETСписок черновиков |
client.drafts.getDraft() | GETИнформация о черновике |
client.drafts.updateDraft() | PUTРедактирование черновика |
client.drafts.deleteDraft() | DELETEУдаление черновика |
client.views.openView() | POSTОткрытие представления |
client.views.submitViewResponse() | POSTОтвет на отправку формы |
client.bots.selfRecreateBotToken() | POSTРотация собственного токена бота |
client.bots.createBot() | POSTНовый бот |
client.bots.recreateBotToken() | POSTРотация токена бота |
client.bots.rotateBotClientSecret() | POSTРотация секрета клиента |
client.bots.createBotToken() | POSTНовый токен бота |
client.bots.reissueBotToken() | POSTПеревыпуск токена бота |
client.bots.listBots() | GETСписок ботов |
client.bots.getBot() | GETИнформация о боте |
client.bots.getBotScopes() | GETКаталог прав бота |
client.bots.listBotTokens() | GETСписок токенов бота |
client.bots.listCompanyBots() | GETСписок ботов пространства |
client.bots.getWebhookEvents() | GETИстория событий |
client.bots.getWebhookEventsStream() | GETПоток событий |
client.bots.selfUpdateBotWebhook() | PUTСаморегистрация вебхука бота |
client.bots.updateBot() | PUTРедактирование бота |
client.bots.updateBotAvatar() | PUTЗагрузка аватара бота |
client.bots.updateBotToken() | PUTИзменение токена бота |
client.bots.deleteBot() | DELETEУдаление бота |
client.bots.deleteBotAvatar() | DELETEУдаление аватара бота |
client.bots.deleteBotToken() | DELETEУдаление токена бота |
client.bots.deleteWebhookEvent() | DELETEУдаление события истории |
client.security.getAuditEvents() | GETЖурнал аудита событий |
client.customProperties.listProperties() | GETСписок дополнительных полей |
client.files.uploadFile() | POSTЗагрузка файла |
client.files.getUploadParams() | POSTПолучение подписи, ключа и других параметров |
client.files.downloadFile() | GETСкачивание файла |
Запросы
Все методы — suspend-функции.
GET с параметрами:
POST с телом запроса:
Простой вызов по ID:
Значение null
Необязательное поле, которое не задано, в запрос не попадает, поэтому метод обновления меняет только то, что вы передали. Некоторые поля API принимают null: например, null в oauth_client выключает у бота авторизацию от имени сотрудника, а в webhook.kind удаляет входящий вебхук. Чтобы отправить null, назовите поле в nullFields той же модели запроса так, как оно называется в Kotlin:
nullFields есть у моделей запроса с такими полями, а в его описании перечислены имена, которые в нём можно указать. С другим именем SDK выбрасывает SerializationException и запрос не отправляет.
Пагинация
Поля пагинации называются как в API, но в camelCase: meta.paginate.nextPage, prevPage, hasNext и hasPrev, а у методов поиска ещё meta.total. Какие поля приходят у каждого метода и как понять, что страницы закончились, описано в разделе Пагинация.
Ручная пагинация
В модели поле hasNext имеет тип Boolean?. Если оно null, цикл идёт дальше и останавливается на пустой странице. Так же обходят страницы методы *All().
Автопагинация
Для каждого метода с пагинацией есть *All() вариант:
Доступные методы автопагинации:
| Метод | Возвращает |
|---|---|
security.getAuditEventsAll() | List<AuditEvent> |
bots.listBotsAll() | List<BotResponse> |
bots.listBotTokensAll() | List<BotAccessToken> |
bots.listCompanyBotsAll() | List<CompanyBotResponse> |
bots.getWebhookEventsAll() | List<WebhookEvent> |
chats.listChatsAll() | List<Chat> |
chats.listCompanyChatsAll() | List<Chat> |
drafts.listDraftsAll() | List<Draft> |
groupTags.listTagsAll() | List<GroupTag> |
groupTags.getTagUsersAll() | List<User> |
importantMessages.listImportantMessagesAll() | List<Message> |
members.listMembersAll() | List<User> |
messages.listChatMessagesAll() | List<Message> |
reactions.listReactionsAll() | List<Reaction> |
search.searchChatsAll() | List<Chat> |
search.searchMessagesAll() | List<Message> |
search.searchUsersAll() | List<User> |
tasks.listTasksAll() | List<Task> |
threads.listThreadsAll() | List<Thread> |
users.listUsersAll() | List<User> |
Обработка ошибок
SDK выбрасывает два типа исключений:
ApiError
Возникает при ошибках 400, 403, 404, 409, 410, 422 с массивом errors в теле:
Поля ApiErrorItem:
| Поле | Тип | Описание |
|---|---|---|
key | String | Поле, вызвавшее ошибку |
value | JsonElement? | Переданное значение |
message | String | Текст ошибки |
code | ValidationErrorCode | Код валидации |
payload | Map<String, JsonElement>? | Дополнительные данные |
Код статуса ответа — в поле statusCode. Если ответ с ошибкой пришёл без тела или не в JSON, SDK тоже выбрасывает ApiError: с кодом статуса и пустым errors. Так бывает с ответом 404 без тела от метода GETПоток событий, когда история событий выключена, и со страницей прокси при 502.
OAuthError
Возникает при ошибке авторизации: 401, а также 403 с кодом insufficient_scope или role_forbidden и отказе при обмене кода на токен. Код — в поле error, список кодов — в разделе Ошибки авторизации:
Поле error — перечисление OAuthErrorCode: его сравнивают с константой, например error.error == OAuthErrorCode.INSUFFICIENT_SCOPE, а строку кода даёт error.error.value.
Повторные запросы
Паузы между попытками, к каждой SDK добавляет случайную величину до 25%:
- 429 с заголовком
Retry-After: срок из заголовка - 429 без заголовка: 1 сек, 2 сек, 4 сек
- 5xx: ~10 сек, ~20 сек, ~40 сек
- Сетевая ошибка у GET, PUT и DELETE: ~10 сек, ~20 сек, ~40 сек
Таймаут запроса и сетевую ошибку у POST SDK не повторяет. Повторы делает плагин Ktor HttpRequestRetry.
Общие правила повторов — в разделе Повторные запросы.
Типы
Все типы — @Serializable data class'ы:
Перечисление в ответе — value class со строкой value: значение, которого SDK ещё не знает, приходит как есть, и isKnown у него false. Поэтому when по такому перечислению заканчивается веткой else. Строку значения возвращает и toString(), а имя константы даёт name.
Все перечисления SDK: AuditEventKey, AuditLoginGrantDenyReason, AuditLoginGrantDevicePlatform, BotCanEdit, BotEventName, BotTemplateEngine, BotTriggerOn, BotWebhookKind, BotWhoCanAdd, ChatActivity, ChatAvailability, ChatMemberRole, ChatMemberRoleFilter, ChatSortField, ChatSubtype, CustomPropertyDataType, DraftRepetitionInterval, DraftType, FileTarget, FileType, InviteStatus, MemberEventType, MessageEntityType, MessageSearchSort, MessageSortField, OAuthErrorCode, OAuthScope, OAuthTokenTypeHint, ReactionEventType, SearchEntityType, SearchSortOrder, SortOrder, TaskKind, TaskStatus, UserCreateRole, UserEventType, UserRole, UserRoleInput, ValidationErrorCode, VideoCallEventType, VoiceTranscriptStatus и WebhookEventType.
Тело вебхука
Тела событий вебхука описаны классами MessageWebhookPayload, ReactionWebhookPayload, ButtonWebhookPayload, ViewSubmitWebhookPayload, ChatMemberWebhookPayload, CompanyMemberWebhookPayload, LinkSharedWebhookPayload и VideoCallWebhookPayload. Их общий интерфейс WebhookPayloadUnion разбирается своим сериализатором: класс он выбирает по полям type и event. Разбирает тело Json из kotlinx.serialization, эта библиотека приходит в проект вместе с SDK:
Подпись проверяйте по исходному телу до разбора, как в разделе Безопасность. Те же классы отдают функции pollWebhookEvents и pollWebhookPayloads, которые забирают события из истории: пример — в разделе Пример поллинга.
Зависимости
| Пакет | Версия | Назначение |
|---|---|---|
kotlinx-serialization-json | 1.9.0 | JSON-сериализация |
kotlinx-coroutines-core | 1.10.2 | Корутины |
ktor-client-core | 3.2.3 | HTTP-клиент |
ktor-client-cio | 3.2.3 | CIO-движок |
ktor-client-auth | 3.2.3 | Bearer-авторизация |
ktor-client-content-negotiation | 3.2.3 | Content negotiation |
ktor-serialization-kotlinx-json | 3.2.3 | JSON для Ktor |
Первые три пакета приходят в проект вместе с SDK и доступны в вашем коде: их типы есть в API SDK (JsonElement, Flow и HttpClient), поэтому отдельно их подключать не нужно. Остальные SDK использует внутри.
Примеры
Отправка сообщения:
Список сотрудников:
Создание напоминания: