Для разработчиков

TypeScript

Типизированный клиент для Pachca API. Работает в Node.js 18+ и в любом окружении с поддержкой fetch. ES Module с TypeScript-декларациями.

Быстрый старт

Установка

npm install @pachca/sdk

Создание клиента

Получите API-токен в интерфейсе Пачки: Настройки > Автоматизации > API (подробнее — Авторизация).

import { PachcaClient } from "@pachca/sdk" const client = new PachcaClient("YOUR_TOKEN")

Первый запрос

// Получение профиляconst response = client.profile.getProfile()// → User({ id: number, firstName: string | null, lastName: string | null, nickname: string, email: string | null, phoneNumber: string | null, department: string | null, title: string | null, role: UserRole, suspended: boolean, inviteStatus: InviteStatus, inviterId: number | null, listTags: string[], customProperties: CustomProperty({ id: number, name: string, dataType: CustomPropertyDataType, value: string | null })[], userStatus: UserStatus({ emoji: string, title: string, expiresAt: string | null, isAway: boolean, awayMessage: UserStatusAwayMessage({ text: string }) | null }) | null, bot: boolean, sso: boolean, createdAt: string, lastActivityAt: string | null, timeZone: string | null, imageUrl: string | null })

Инициализация

import { PachcaClient } from "@pachca/sdk" // Стандартное подключениеconst client = new PachcaClient("YOUR_TOKEN") // С кастомным базовым URLconst client = new PachcaClient("YOUR_TOKEN", "https://custom-api.example.com/api/shared/v1")
ПараметрТипПо умолчаниюОписание
tokenstringBearer-токен для авторизации
baseUrlstringhttps://api.pachca.com/api/shared/v1Базовый URL API

Клиент не требует явного закрытия — все запросы используют глобальный fetch.

Все методы

МетодМетод API
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.updateChat()PUTРедактирование чата
client.chats.archiveChat()PUTАрхивация чата
client.chats.unarchiveChat()PUTРазархивация чата
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.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.views.openView()POSTОткрытие представления
client.bots.selfRecreateBotToken()POSTРотация собственного токена бота
client.bots.createBot()POSTНовый бот
client.bots.recreateBotToken()POSTРотация токена бота
client.bots.listBots()GETСписок ботов
client.bots.getBot()GETИнформация о боте
client.bots.getWebhookEvents()GETИстория событий
client.bots.selfUpdateBotWebhook()PUTСаморегистрация вебхука бота
client.bots.updateBot()PUTРедактирование бота
client.bots.deleteBot()DELETEУдаление бота
client.bots.deleteWebhookEvent()DELETEУдаление события
client.security.getAuditEvents()GETЖурнал аудита событий
client.customProperties.listProperties()GETСписок дополнительных полей
client.files.uploadFile()POSTЗагрузка файла
client.files.getUploadParams()POSTПолучение подписи, ключа и других параметров

Запросы

Все методы — асинхронные и возвращают Promise.

GET с параметрами:

import { ChatAvailability, ChatSortField, SortOrder } from "@pachca/sdk" // Список чатовconst response = client.chats.listChats({  sort: ChatSortField.Id,  order: SortOrder.Desc,  availability: ChatAvailability.IsMember,  archived: true,  lastMessageAtAfter: "2025-01-01T00:00:00.000Z",  lastMessageAtBefore: "2025-02-01T00:00:00.000Z",  personal: false,  limit: 1,  cursor: "eyJpZCI6MTAsImRpciI6ImFzYyJ9"})// → ListChatsResponse({ data: Chat[], meta: PaginationMeta })

POST с телом запроса:

import { ChatCreateRequest, ChatCreateRequestChat } from "@pachca/sdk" // Создание чатаconst request: ChatCreateRequest = {  chat: {    name: "🤿 aqua",    memberIds: [123],    groupTagIds: [123],    channel: true,    public: false  }}const response = client.chats.createChat(request)// → Chat({ id: number, name: string, createdAt: string, ownerId: number, memberIds: number[], groupTagIds: number[], channel: boolean, archived: boolean, personal: boolean, public: boolean, lastMessageAt: string, meetRoomUrl: string })

Простой вызов по ID:

// Получение чатаconst response = client.chats.getChat(334)// → Chat({ id: number, name: string, createdAt: string, ownerId: number, memberIds: number[], groupTagIds: number[], channel: boolean, archived: boolean, personal: boolean, public: boolean, lastMessageAt: string, meetRoomUrl: string })

Пагинация

SDK работает с двумя группами методов, возвращающих списки, у которых разная структура meta — это важно учитывать при ручной пагинации:

  • Списочные методы (client.users.listUsers(), client.chats.listChats(), client.messages.listChatMessages() и т.д.) — meta.paginate с полями nextPage, prevPage, hasNext, hasPrev. Признак конца — hasNext: false. Курсор prevPage нужен для polling новых записей «сверху» списка.
  • Методы поиска (client.search.searchUsers(), client.search.searchChats(), client.search.searchMessages()) — meta с полями total и paginate.nextPage (без prevPage/hasNext/hasPrev). Признак конца — пустой data или совпадение числа полученных записей с total.

Курсоры — непрозрачные токены, никогда не бывают null/пустыми. Подробное описание полей и примеры — на странице Пагинация.

Ручная пагинация

let cursor: string | undefinedlet hasNext = true while (hasNext) {  const response = await client.users.listUsers({ limit: 50, cursor })  for (const user of response.data) {    console.log(user.firstName, user.lastName)  }  cursor = response.meta.paginate.nextPage  hasNext = response.meta.paginate.hasNext}

Автопагинация

Для каждого метода с пагинацией есть *All() вариант, который автоматически обходит все страницы и возвращает плоский массив:

// Все пользователи одним массивомconst users = await client.users.listUsersAll()console.log(`Всего: ${users.length}`)

Доступные методы автопагинации:

МетодВозвращает
security.getAuditEventsAll()AuditEvent[]
bots.getWebhookEventsAll()WebhookEvent[]
chats.listChatsAll()Chat[]
groupTags.listTagsAll()GroupTag[]
groupTags.getTagUsersAll()User[]
members.listMembersAll()User[]
messages.listChatMessagesAll()Message[]
reactions.listReactionsAll()Reaction[]
search.searchChatsAll()Chat[]
search.searchMessagesAll()Message[]
search.searchUsersAll()User[]
tasks.listTasksAll()Task[]
users.listUsersAll()User[]

Обработка ошибок

SDK выбрасывает два типа ошибок:

ApiError

Возникает при ошибках 400, 403, 404, 409, 410, 422:

import { PachcaClient, ApiError } from "@pachca/sdk" try {  await client.chats.createChat(request)} catch (error) {  if (error instanceof ApiError) {    for (const e of error.errors) {      console.log(e.key, e.message)   // "name", "не может быть пустым"      console.log(e.code)             // "blank"    }  }}

Поля ApiErrorItem:

ПолеТипОписание
keystringПоле, вызвавшее ошибку
valuestring | nullПереданное значение
messagestringТекст ошибки
codeValidationErrorCodeКод валидации (blank, invalid, taken, ...)
payloadstring | nullДополнительные данные

OAuthError

Возникает при ошибке авторизации (401):

import { OAuthError } from "@pachca/sdk" try {  await client.profile.getProfile()} catch (error) {  if (error instanceof OAuthError) {    console.log(error.message) // "Token not found"  }}

Повторные запросы

SDK автоматически повторяет запрос при получении 429 Too Many Requests и ошибок сервера 5xx (500, 502, 503, 504):

  • До 3 повторов на каждый запрос
  • 429: если сервер вернул заголовок Retry-After — ждёт указанное время, иначе — экспоненциальный backoff: 1 сек, 2 сек, 4 сек
  • 5xx: экспоненциальный backoff с jitter: ~10 сек, ~20 сек, ~40 сек
  • Ошибки клиента (4xx, кроме 429) возвращаются сразу без повторов

Сериализация

SDK автоматически конвертирует имена полей между camelCase (TypeScript) и snake_case (API):

// Вы пишете:{ memberIds: [123], groupTagIds: [456] } // SDK отправляет:{ "member_ids": [123], "group_tag_ids": [456] } // API возвращает:{ "last_message_at": "2025-01-01T00:00:00Z" } // Вы получаете:{ lastMessageAt: "2025-01-01T00:00:00Z" }

Типы

Все типы экспортируются из пакета:

import {  // Модели  Chat, Message, User, Task, GroupTag, Thread, Reaction,  // Запросы  ChatCreateRequest, MessageCreateRequest, TaskCreateRequest,  // Параметры  ListChatsParams, ListUsersParams, SearchMessagesParams,  // Ответы  ListChatsResponse, ListMembersResponse,  // Перечисления  AuditEventKey, ChatAvailability, ChatMemberRole, ChatMemberRoleFilter,  ChatSubtype, CustomPropertyDataType, FileType, InviteStatus,  MemberEventType, MessageEntityType, OAuthScope, ReactionEventType,  SearchEntityType, SearchSortOrder, SortOrder, TaskKind, TaskStatus,  UserEventType, UserRole, ValidationErrorCode, WebhookEventType,  // Ошибки  ApiError, OAuthError,} from "@pachca/sdk"

Примеры

import { Button, FileType, MessageCreateRequest, MessageCreateRequestFile, MessageCreateRequestMessage, MessageEntityType, PachcaClient, TaskCreateRequest, TaskCreateRequestCustomProperty, TaskCreateRequestTask, TaskKind } from "@pachca/sdk" const client = new PachcaClient("YOUR_TOKEN") // Отправка сообщенияconst request: MessageCreateRequest = {  message: {    entityType: MessageEntityType.Discussion,    entityId: 334,    content: "Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье)",    files: [{      key: "attaches/files/93746/e354fd79-4f3e-4b5a-9c8d-1a2b3c4d5e6f/logo.png",      name: "logo.png",      fileType: FileType.Image,      size: 12345,      width: 800,      height: 600,      durationMs: 5400,      waveform: "4,8,12,20,16,10,6,3"    }],    buttons: [[{      text: "Подробнее",      url: "https://example.com/details",      data: "awesome"    }]],    parentMessageId: 194270,    displayAvatarUrl: "https://example.com/avatar.png",    displayName: "Бот Поддержки",    skipInviteMentions: false  },  linkPreview: false}const response = client.messages.createMessage(request)// → Message({ id: number, entityType: MessageEntityType, entityId: number, chatId: number, rootChatId: number, content: string, userId: number, createdAt: string, url: string, files: File({ id: number, key: string, name: string, fileType: FileType, url: string, width?: number | null, height?: number | null })[], voiceContent: VoiceContent({ durationMs: number, waveform: string, transcript: string | null }) | null, buttons: Button({ text: string, url?: string, data?: string })[][] | null, thread: MessageThread({ id: number, chatId: number }) | null, forwarding: Forwarding({ originalMessageId: number, originalChatId: number, authorId: number, originalCreatedAt: string, originalThreadId: number | null, originalThreadMessageId: number | null, originalThreadParentChatId: number | null }) | null, parentMessageId: number | null, displayAvatarUrl?: string | null, displayName?: string | null, changedAt: string | null, deletedAt: string | null }) // Список сотрудниковconst response = client.users.listUsers({  query: "Олег",  limit: 1,  cursor: "eyJpZCI6MTAsImRpciI6ImFzYyJ9"})// → ListUsersResponse({ data: User[], meta: PaginationMeta }) // Создание задачиconst request: TaskCreateRequest = {  task: {    kind: TaskKind.Reminder,    content: "Забрать со склада 21 заказ",    dueAt: "2020-06-05T12:00:00.000+03:00",    priority: 2,    performerIds: [123],    chatId: 456,    allDay: false,    customProperties: [{ id: 78, value: "Синий склад" }]  }}const response = client.tasks.createTask(request)// → Task({ id: number, kind: TaskKind, content: string, dueAt: string | null, priority: number, userId: number, chatId: number | null, status: TaskStatus, createdAt: string, performerIds: number[], allDay: boolean, customProperties: CustomProperty({ id: number, name: string, dataType: CustomPropertyDataType, value: string | null })[] })