Skip to main content

zenmoney-python

Самостоятельная Python-библиотека публичного HTTP API ZenMoney. Проект находится рядом с ZenImport и развивается независимо. Distribution: zenmoney-python, импорт: zenmoney_api, версия 0.7.0. Python 3.12+, HTTPX 0.28.x, simplejson для точных JSON-чисел.

Возможности

  • Синхронный и асинхронный клиент: полная и инкрементальная синхронизация diff, forceFetch, создание/обновление/удаление пользовательских сущностей.
  • Счета, категории, получатели, операции, бюджеты, напоминания и планируемые операции; чтение системных справочников. Типы полей для редактора в models.
  • Функции создания дохода, расхода, перевода, долговой операции; сохранение оригинальных сумм/валют, нескольких категорий и неизвестных полей при обновлении.
  • Suggest: один объект или список; OAuth code exchange и явное обновление токена.
  • Без автоматических повторов записи, скрытого хранения данных или зависимости от UI/банков. Единственный публичный namespace — zenmoney_api.

Область покрытия и честные ограничения: docs/coverage.md. Сценарии расходов, возвратов, долгов и переводов: docs/basic-operations.md.

Установка

Готовые wheel, sdist и SHA256SUMS доступны в GitHub Releases. Установка версии 0.7.0 из GitHub (Python 3.12+):

python -m pip install "https://github.com/vaslv/zenmoney-python/releases/download/v0.7.0/zenmoney_python-0.7.0-py3-none-any.whl"

Пакет ещё не загружен в PyPI. Установка из исходников: python -m pip install .. Для собственной сборки выполните sh scripts/build.sh: в dist/ появятся wheel, sdist и SHA256SUMS. Twine проверяет метаданные; wheel собирается из sdist. Имя репозитория и дистрибутива — zenmoney-python, Python-import — zenmoney_api. Прежнее локальное имя zenmoney-api-client больше не используется; перед переходом в существующем окружении удалите старый дистрибутив или создайте чистое окружение, чтобы два пакета не владели одним namespace.

Порядок первого GitHub-релиза и интеграции приложений: docs/publication.md.

Чтение

import os
from zenmoney_api import Client

with Client(os.environ['ZENMONEY_TOKEN']) as api:
    initial = api.read_diff()  # cursor=0 — первоначальная синхронизация
    # Сначала атомарно сохраните сущности и удаления, затем курсор в своей БД.
    cursor = initial['serverTimestamp']
    changes = api.read_diff(cursor)
    accounts = api.read_diff(cursor, force_fetch=['account'])

Клиент сохраняет неизвестные поля в словарях; Diff.raw_json содержит исходный ответ. Целые числа читаются как int, десятичные — как Decimal. Для денег используйте Decimal('1.23') или целые числа VND: при отправке они остаются JSON-числами без округления через float. float принимается, но уже возникшую в нём погрешность SDK исправить не может. NaN/Infinity и не-JSON объекты отклоняются до запроса. SDK не пересчитывает валюты. Обычный json.dumps не сериализует Decimal; для исходного ответа используйте Diff.raw_json, для подготовленных объектов — zenmoney_api.protocol.encode_json.

from zenmoney_api import AsyncClient

async def load(token):
    async with AsyncClient(token) as api:
        return await api.read_diff()

Используйте контекстный менеджер либо close() / aclose() для освобождения соединений. Закрытый клиент не используется повторно: он вызывает ClientClosedError; создайте новый экземпляр. is_closed показывает состояние. Один экземпляр асинхронного клиента используйте в одном event loop. Параметр timeout принимает секунды, httpx.Timeout или явно отключённый таймаут None.

Подготовка и отправка

from zenmoney_api import transactions as tx

operation = tx.expense(user=123, account='account-id', instrument=1,
    amount=100000, date='2026-10-13', categories=['category-id'], payee='Shop')
# Сохраните operation и его UUID до отправки. Повтор не должен создавать новый UUID.
# Выполнить запись, когда вызывающее приложение готово:
# result = api.upsert('transaction', [operation], cursor)
# Затем повторно получите данные и проверьте наличие/содержимое операции.

transaction(...) формирует общий объект; income, expense, transfer, debt упрощают типовые случаи. Примеры: examples/operations.py. update(fetched_object, tag=[...]) копирует полный объект с сохранением полей.

api.diff(cursor, changes={'account': [...], 'tag': [...], 'transaction': [...]}, deletions=[...]) позволяет передать несколько типов сущностей одним запросом. upsert(kind, entities, cursor) — удобная обёртка. Для новых объектов каталога есть полные формы с актуальными полями: entities.account(user=..., title=..., instrument=...), entities.tag(...), entities.merchant(...). Полученный объект можно передать в upsert. Для loan/deposit задайте параметры срока и процентов; системный debt-счёт следует получать из diff, а не создавать повторно. Передавайте полные сущности, не patch. Низкоуровневый интерфейс проверяет структуру, идентификаторы, timestamps и JSON, но не подменяет серверную проверку всех полей. Ограничения/пакетирование определяет вызывающее приложение, скрытого лимита в 20 записей в общем SDK нет.

deletion(kind, id, user=..., now=...) создаёт удаление по ID. Для бюджета с составным ключом используйте clear_budget и upsert('budget', ...). Мягкое удаление операции — update(operation, deleted=True).

api.suggest({'payee': 'Shop'}) или список объектов возвращает подсказки API, не изменяя записи.

OAuth (необязательно)

Для diff/suggest достаточно готового Bearer-токена в Client/AsyncClient. Регистрация приложения и собственный OAuth не требуются для использования SDK. Методы ниже предназначены для владельцев уже выданных реквизитов приложения; их живая проверка не является условием приёмки основного API.

import secrets
from zenmoney_api import OAuthClient, callback_code

with OAuthClient('registered-client-id', 'client-secret', 'https://your-app/callback') as oauth:
    state = secrets.token_urlsafe(32)  # сохраните в сессии до открытия URL
    url = oauth.authorization_url(state=state)
    # code = callback_code(received_callback_url, expected_state=state)
    # token = oauth.exchange_code(code)
    # if token.refresh_token is not None:
    #     refreshed = oauth.refresh(token.refresh_token)

Для async есть независимый AsyncOAuthClient с теми же аргументами: используйте async with, а exchange_code и refresh вызывайте с await. OAuth-клиенты переиспользуют HTTPX-клиент и переданный транспорт между запросами. При работе без контекстного менеджера вызовите close() / await aclose(). Оба способа освобождают открытый HTTPX-клиент и его транспорт; повторное закрытие безопасно. После закрытия is_closed равен True, а обмен кода, обновление токена и повторный вход в контекст вызывают ClientClosedError. Создайте новый экземпляр для следующего сеанса. AsyncOAuthClient используйте в рамках одного event loop. SDK не поднимает callback-сервер, не регистрирует приложение, не хранит токены и не обновляет их автоматически. Если refresh-ответ не содержит нового refresh_token, приложение сохраняет прежний. Token.__repr__ скрывает токены. State проверяется до обмена code; привязка callback к сессии — задача приложения.

Ошибки и подтверждение записи

HTTPError.status_code, TransportError, ResponseError не включают тело ответа и токен. HTTP 200 не гарантирует принятия всех изменений: более новый changed на сервере может победить. После записи требуется отдельное чтение и сверка; при неопределённом результате нельзя создавать другой UUID и слепо повторять. Синхронизация БД, пользовательское подтверждение, журнал отправок и reconciliation принадлежат приложению, а не SDK.

Разработка и Docker

sh scripts/test.sh
sh scripts/build.sh

Тесты используют установленный wheel без дерева исходников, без сети и без настоящих токенов. Есть проверка реального HTTP на локальном тестовом сервере. Тестовый образ проверяет строгую типизацию mypy, типовые примеры использования публичного API и выводит покрытие. Сборка требует доступа к реестру образов и PyPI.

Переход с 0.4

Версия 0.5 намеренно меняет контракт: zenimport_zenmoney удалён, десятичные числа ответа теперь Decimal, закрытый клиент не открывается повторно. Для записи используйте diff/upsert, для типовых объектов — transactions. Старые приложения следует адаптировать после приёмки SDK; их ограничения не определяют дизайн библиотеки. Архитектура · Покрытие API · Проверка на настоящем API · История.

Живая приёмка

Результаты проверки на тестовом аккаунте. Для собственного отдельного тестового аккаунта скопируйте .env.example в .env и заполните ZENMONEY_TEST_TOKEN. Шаблон содержит также все необязательные переменные OAuth. Файл не попадает в Git и образ Docker.

sh scripts/live-check.sh выполняет только чтение. --write явно включает запись искусственных данных и требует первоначально пустого отдельного аккаунта; --soft-delete и --cleanup работают только с UUID сохранённого тестового журнала. После ошибки автоматического повтора нет. --resume разрешает только повторную сверку и продолжение подтверждённых шагов, без повторения неизвестной записи. Завершённый очищенный журнал не используется для нового запуска. Для нового запуска задайте другой путь --journal /state/new-run.json.

--write --basic --journal /state/basic-run.json проверяет согласованный базовый набор операций, баланс после каждого шага, долговые движения и отсутствие дубля при явной записи того же UUID. --cleanup --journal /state/basic-run.json убирает тестовые объекты; --inspect выводит только названия отличающихся полей.

Metadata

Release files for zenmoney-python 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zenmoney-python 0.7.0
File Size Uploaded
zenmoney_python-0.7.0.tar.gz 63.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zenmoney-python 0.7.0
File Interpreter ABI Platform
zenmoney_python-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 84.6 kB

Release files / zenmoney_python-0.7.0.tar.gz

Download URL zenmoney_python-0.7.0.tar.gz
Size 63.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9a70d3eb14b96bd61811644bfbbf019b42097a4ad0ff4a5a6b920b60c5f3de50
BLAKE2b-256 checksum
How to use checksums
c0fcc26b5abc99c0c01f7b0779a422e814192288c6df4c3ec7636411e739d241
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release files / zenmoney_python-0.7.0-py3-none-any.whl

Download URL zenmoney_python-0.7.0-py3-none-any.whl
Size 20.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
529cd89ce941ddfabbe8a08c4ab5c587389680cda0e0b9b1f1abaf3e5f2734b7
BLAKE2b-256 checksum
How to use checksums
c4670a58fea1cb691d20c3ed9dbaed2b908fd61e766f69b32b4f210044071fe6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page