Python

Асинхронный типизированный клиент для Pachca API. Построен на httpx с поддержкой type hints и dataclass-моделей. Требуется Python 3.10+.

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

Установка

pip install pachca-sdk

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

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

from pachca.client import PachcaClient client = PachcaClient("YOUR_TOKEN")

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

# Получение профиляresponse = await client.profile.get_profile()# → User(id: int, first_name: str, last_name: str, nickname: str, email: str, phone_number: str, department: str, title: str, role: UserRole, suspended: bool, invite_status: InviteStatus, list_tags: list[str], custom_properties: list[CustomProperty(id: int, name: str, data_type: CustomPropertyDataType, value: str)], user_status: UserStatus(emoji: str, title: str, expires_at: str | None, is_away: bool, away_message: UserStatusAwayMessage(text: str) | None) | None, bot: bool, sso: bool, created_at: str, last_activity_at: str, time_zone: str, image_url: str | None)
Все методы SDK асинхронные — вызывайте их через await внутри async def.

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

from pachca.client import PachcaClient # Стандартное подключениеclient = PachcaClient("YOUR_TOKEN") # С кастомным базовым URLclient = PachcaClient("YOUR_TOKEN", base_url="https://custom-api.example.com/api/shared/v1")
ПараметрТипПо умолчаниюОписание
tokenstrBearer-токен для авторизации
base_urlstrhttps://api.pachca.com/api/shared/v1Базовый URL API

Клиент использует httpx.AsyncClient — после завершения работы закройте его:

await client.close()

Все методы

МетодМетод API
client.common.request_export()POSTЭкспорт сообщений
client.common.upload_file()POSTЗагрузка файла
client.common.get_upload_params()POSTПолучение подписи, ключа и других параметров
client.common.download_export()GETСкачать архив экспорта
client.common.list_properties()GETСписок дополнительных полей
client.profile.get_token_info()GETИнформация о токене
client.profile.get_profile()GETИнформация о профиле
client.profile.get_status()GETТекущий статус
client.profile.update_status()PUTНовый статус
client.profile.delete_status()DELETEУдаление статуса
client.users.create_user()POSTСоздать сотрудника
client.users.list_users()GETСписок сотрудников
client.users.get_user()GETИнформация о сотруднике
client.users.get_user_status()GETСтатус сотрудника
client.users.update_user()PUTРедактирование сотрудника
client.users.update_user_status()PUTНовый статус сотрудника
client.users.delete_user()DELETEУдаление сотрудника
client.users.delete_user_status()DELETEУдаление статуса сотрудника
client.group_tags.create_tag()POSTНовый тег
client.group_tags.list_tags()GETСписок тегов сотрудников
client.group_tags.get_tag()GETИнформация о теге
client.group_tags.get_tag_users()GETСписок сотрудников тега
client.group_tags.update_tag()PUTРедактирование тега
client.group_tags.delete_tag()DELETEУдаление тега
client.chats.create_chat()POSTНовый чат
client.chats.list_chats()GETСписок чатов
client.chats.get_chat()GETИнформация о чате
client.chats.update_chat()PUTОбновление чата
client.chats.archive_chat()PUTАрхивация чата
client.chats.unarchive_chat()PUTРазархивация чата
client.members.add_tags()POSTДобавление тегов
client.members.add_members()POSTДобавление пользователей
client.members.list_members()GETСписок участников чата
client.members.update_member_role()PUTРедактирование роли
client.members.remove_tag()DELETEИсключение тега
client.members.leave_chat()DELETEВыход из беседы или канала
client.members.remove_member()DELETEИсключение пользователя
client.threads.create_thread()POSTНовый тред
client.threads.get_thread()GETИнформация о треде
client.messages.create_message()POSTНовое сообщение
client.messages.pin_message()POSTЗакрепление сообщения
client.messages.list_chat_messages()GETСписок сообщений чата
client.messages.get_message()GETИнформация о сообщении
client.messages.update_message()PUTРедактирование сообщения
client.messages.delete_message()DELETEУдаление сообщения
client.messages.unpin_message()DELETEОткрепление сообщения
client.read_members.list_read_members()GETСписок прочитавших сообщение
client.reactions.add_reaction()POSTДобавление реакции
client.reactions.list_reactions()GETСписок реакций
client.reactions.remove_reaction()DELETEУдаление реакции
client.link_previews.create_link_previews()POSTUnfurl (разворачивание ссылок)
client.search.search_chats()GETПоиск чатов
client.search.search_messages()GETПоиск сообщений
client.search.search_users()GETПоиск сотрудников
client.tasks.create_task()POSTНовое напоминание
client.tasks.list_tasks()GETСписок напоминаний
client.tasks.get_task()GETИнформация о напоминании
client.tasks.update_task()PUTРедактирование напоминания
client.tasks.delete_task()DELETEУдаление напоминания
client.views.open_view()POSTОткрытие представления
client.bots.get_webhook_events()GETИстория событий
client.bots.update_bot()PUTРедактирование бота
client.bots.delete_webhook_event()DELETEУдаление события
client.security.get_audit_events()GETЖурнал аудита событий

Запросы

Все методы — асинхронные (async def) и возвращают корутины.

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

from pachca.models import ChatAvailability, ListChatsParams, SortOrder # Список чатовparams = ListChatsParams(    sort_id=SortOrder.DESC,    availability=ChatAvailability.IS_MEMBER,    last_message_at_after="2025-01-01T00:00:00.000Z",    last_message_at_before="2025-02-01T00:00:00.000Z",    personal=False,    limit=1,    cursor="eyJpZCI6MTAsImRpciI6ImFzYyJ9")response = await client.chats.list_chats(params=params)# → ListChatsResponse(data: list[Chat], meta: PaginationMeta | None)

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

from pachca.models import ChatCreateRequest, ChatCreateRequestChat # Создание чатаrequest = ChatCreateRequest(    chat=ChatCreateRequestChat(        name="🤿 aqua",        member_ids=[123],        group_tag_ids=[123],        channel=True,        public=False    ))response = await client.chats.create_chat(request=request)# → Chat(id: int, name: str, created_at: str, owner_id: int, member_ids: list[int], group_tag_ids: list[int], channel: bool, personal: bool, public: bool, last_message_at: str, meet_room_url: str)

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

# Получение чатаresponse = await client.chats.get_chat(id=334)# → Chat(id: int, name: str, created_at: str, owner_id: int, member_ids: list[int], group_tag_ids: list[int], channel: bool, personal: bool, public: bool, last_message_at: str, meet_room_url: str)

Пагинация

Методы, возвращающие списки, используют cursor-based пагинацию. Ответ содержит meta.paginate.next_page — курсор для следующей страницы.

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

from pachca.models import ListUsersParams cursor = Nonewhile True:    response = await client.users.list_users(ListUsersParams(limit=50, cursor=cursor))    for user in response.data:        print(user.first_name, user.last_name)    if not response.meta or not response.meta.paginate or not response.meta.paginate.next_page:        break    cursor = response.meta.paginate.next_page

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

Для каждого метода с пагинацией есть *_all() вариант:

# Все пользователи одним спискомusers = await client.users.list_users_all()print(f"Всего: {len(users)}")

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

МетодВозвращает
security.get_audit_events_all()list[AuditEvent]
bots.get_webhook_events_all()list[WebhookEvent]
chats.list_chats_all()list[Chat]
group_tags.list_tags_all()list[GroupTag]
group_tags.get_tag_users_all()list[User]
members.list_members_all()list[User]
messages.list_chat_messages_all()list[Message]
reactions.list_reactions_all()list[Reaction]
search.search_chats_all()list[Chat]
search.search_messages_all()list[Message]
search.search_users_all()list[User]
tasks.list_tasks_all()list[Task]
users.list_users_all()list[User]

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

SDK выбрасывает два типа исключений:

ApiError

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

from pachca.models import ApiError try:    await client.chats.create_chat(request)except ApiError as error:    for e in error.errors:        print(e.key, e.message)   # "name", "не может быть пустым"        print(e.code)             # ValidationErrorCode.BLANK

Поля ApiErrorItem:

ПолеТипОписание
keystrПоле, вызвавшее ошибку
valuestr | NoneПереданное значение
messagestrТекст ошибки
codeValidationErrorCodeКод валидации
payloadstr | NoneДополнительные данные

OAuthError

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

from pachca.models import OAuthError try:    await client.profile.get_profile()except OAuthError as error:    print(error.error)              # "Token not found"    print(error.error_description)  # описание ошибки

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

SDK автоматически повторяет запрос при получении 429 Too Many Requests:

  • До 3 повторов на каждый запрос
  • Если сервер вернул заголовок Retry-After — ждёт указанное время
  • Иначе — экспоненциальный backoff: 1 сек, 2 сек, 4 сек
  • Реализовано через RetryTransport — обёртку над httpx-транспортом

Типы

Все модели — Python dataclass'ы с type hints:

from pachca.models 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,)

Зависимости

ПакетВерсияНазначение
httpx>=0.23.0Асинхронный HTTP-клиент
attrs>=22.2.0Dataclass'ы
python-dateutil^2.8.0Парсинг дат

Примеры

from pachca.client import PachcaClientfrom pachca.models import Button, FileType, ListUsersParams, MessageCreateRequest, MessageCreateRequestFile, MessageCreateRequestMessage, MessageEntityType, TaskCreateRequest, TaskCreateRequestCustomProperty, TaskCreateRequestTask, TaskKind client = PachcaClient("YOUR_TOKEN") # Отправка сообщенияrequest = MessageCreateRequest(    message=MessageCreateRequestMessage(        entity_type=MessageEntityType.DISCUSSION,        entity_id=334,        content="Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье)",        files=[MessageCreateRequestFile(            key="attaches/files/93746/e354fd79-4f3e-4b5a-9c8d-1a2b3c4d5e6f/logo.png",            name="logo.png",            file_type=FileType.IMAGE,            size=12345,            width=800,            height=600        )],        buttons=[[Button(            text="Подробнее",            url="https://example.com/details",            data="awesome"        )]],        parent_message_id=194270,        display_avatar_url="https://example.com/avatar.png",        display_name="Бот Поддержки",        skip_invite_mentions=False,        link_preview=False    ))response = await client.messages.create_message(request=request)# → Message(id: int, entity_type: MessageEntityType, entity_id: int, chat_id: int, root_chat_id: int, content: str, user_id: int, created_at: str, url: str, files: list[File(id: int, key: str, name: str, file_type: FileType, url: str, width: int | None, height: int | None)], buttons: list[list[Button(text: str, url: str | None, data: str | None)]] | None, thread: Thread(id: int, chat_id: int, message_id: int, message_chat_id: int, updated_at: str) | None, forwarding: Forwarding(original_message_id: int, original_chat_id: int, author_id: int, original_created_at: str, original_thread_id: int | None, original_thread_message_id: int | None, original_thread_parent_chat_id: int | None) | None, parent_message_id: int | None, display_avatar_url: str | None, display_name: str | None, changed_at: str | None, deleted_at: str | None) # Список сотрудниковparams = ListUsersParams(    query="Олег",    limit=1,    cursor="eyJpZCI6MTAsImRpciI6ImFzYyJ9")response = await client.users.list_users(params=params)# → ListUsersResponse(data: list[User], meta: PaginationMeta | None) # Создание задачиrequest = TaskCreateRequest(    task=TaskCreateRequestTask(        kind=TaskKind.REMINDER,        content="Забрать со склада 21 заказ",        due_at="2020-06-05T12:00:00.000+03:00",        priority=2,        performer_ids=[123],        chat_id=456,        all_day=False,        custom_properties=[TaskCreateRequestCustomProperty(id=78, value="Синий склад")]    ))response = await client.tasks.create_task(request=request)# → Task(id: int, kind: TaskKind, content: str, due_at: str | None, priority: int, user_id: int, chat_id: int | None, status: TaskStatus, created_at: str, performer_ids: list[int], all_day: bool, custom_properties: list[CustomProperty(id: int, name: str, data_type: CustomPropertyDataType, value: str)])