Разработчикам

Справочник API v1

REST · JSON · OAuth 2.0 Bearer https://api.manilo.app Стабильно — внутри v1 без ломающих изменений

Обзор

Manilo API — это JSON REST API для программной работы с тем же учётом, который вы ведёте в приложении для iOS: счетами, категориями, бюджетами, общими группами и транзакциями. Используйте его, чтобы писать импортеры, экспортеры, мосты синхронизации, дашборды или собственные автоматизации.

  • Базовый URL: https://api.manilo.app — прежний базовый URL api.ledgy.app продолжает работать.
  • Префикс версии: все эндпоинты в этом документе размещены по пути /api/v1/.
  • Транспорт: только HTTPS. HTTP-запросы не принимаются.
  • Кодировка: тела запросов и ответов в JSON. UTF-8. Имена свойств — camelCase.
  • Аутентификация: Authorization: Bearer … в каждом запросе.
  • Подписка Cloud: требуется для каждого эндпоинта v1. См. раздел Проверка подписки.
Нужен ИИ-ассистент? Если вы хотите, чтобы Claude, ChatGPT или Cursor работали с Manilo от вашего имени, используйте эндпоинт Model Context Protocol по адресу https://api.manilo.app/mcp — см. Интеграции. Описанный здесь REST API предназначен для кода, который вы пишете сами.

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

Три шага до вашего первого аутентифицированного запроса.

1. Создайте персональный токен доступа

  1. Войдите в свой дашборд Manilo и откройте Настройки → API Access.
  2. Нажмите + New token.
  3. Дайте токену понятное имя (например, «Zapier — еженедельный экспорт»), выберите нужные скоупы (см. Скоупы) и при желании задайте срок действия.
  4. Скопируйте токен. Он показывается один раз. Токены начинаются с префикса lgpat_, за которым следуют 64 шестнадцатеричных символа.

На этой же странице перечислены ваши активные токены с временем последнего использования и количеством разрешений, появляется предупреждение «Истекает через 30 дней», а любой токен можно мгновенно отозвать по значку корзины. В одном аккаунте одновременно может быть до 25 активных токенов.

2. Выполните запрос

cURLСписок счетов
# Replace lgpat_… with your token
curl "https://api.manilo.app/api/v1/accounts" \
  -H "Authorization: Bearer lgpat_a1b2c3d4e5…"

3. Разберите ответ

200 OKapplication/json
{
  "items": [
    {
      "id": "acc_01HK8V…",
      "name": "Wise EUR",
      "currencyCode": "EUR",
      "initialBalance": 1240.50,
      "icon": "wallet",
      "color": "#4A90E2",
      "order": 0,
      "createdAt": "2026-04-12T08:13:09Z",
      "updatedAt": "2026-05-01T17:02:31Z"
    }
  ],
  "totalCount": 1
}
Относитесь к токену как к паролю. Любой, у кого есть токен, может читать и изменять ваш учёт в пределах выданных вами скоупов. Скомпрометированные токены немедленно отзывайте в разделе Настройки → API Access.

Аутентификация

Каждый запрос к /api/v1/ должен содержать заголовок Authorization. Принимаются два типа токенов:

  • Персональный токен доступа (PAT) — долгоживущий bearer-токен, который вы создаёте в дашборде на странице Настройки → API Access. Формат: lgpat_ + 64 шестнадцатеричных символа. Ограничен скоупами, отзывается, может иметь срок действия. Рекомендуется для всех сторонних интеграций.
  • Сессионный JWT — короткоживущий токен, который выдаётся собственным приложениям (iOS, дашборд). Не имеет ограничений по скоупам. Его можно использовать для разовой проверки, если вы сумеете извлечь его из авторизованной сессии, но поддерживаемый путь — это PAT.

Формат заголовка

HTTP
Authorization: Bearer lgpat_a1b2c3d4e5f6…

Ограничения на токены

  • До 25 активных PAT на один аккаунт Manilo.
  • При создании можно задать необязательный срок действия. Просроченные токены возвращают 401 Unauthorized.
  • Отозванные токены перестают работать немедленно: Manilo хранит только SHA-256-хеш токена, но не его значение, поэтому утёкший токен нельзя восстановить — только отозвать и заменить.

Типичные ошибки аутентификации

401
Токен отсутствует, повреждён, просрочен или отозван.
403
Токен действителен, но запрошенный эндпоинт требует скоуп, которого нет у вашего PAT, либо ваша подписка Cloud неактивна.

Скоупы

PAT работают по модели «запрещено по умолчанию». Токен может вызывать только те эндпоинты, требуемый скоуп которых у него есть; всё остальное возвращает 403 Forbidden. Выдавайте самый узкий набор скоупов, который действительно нужен вашей интеграции.

Доступные скоупы:

accounts:read accounts:write categories:read categories:write budgets:read budgets:write groups:read groups:write transactions:read transactions:write tags:read tags:write recurring:read recurring:write settings:read settings:write

У каждого эндпоинта ниже требуемый скоуп показан маленьким фиолетовым чипом. Скоупы :write не подразумевают :read — запрашивайте оба, если нужны оба.

Проверка подписки

Все эндпоинты v1 — включая работающие только на чтение — требуют, чтобы у вызывающего пользователя была активная подписка Manilo Cloud. Если подписка прервана, истекла или никогда не оформлялась, API отвечает так:

403 Forbidden
HTTP/1.1 403 Forbidden
X-Subscription-Required: true
Content-Type: application/json

{ "error": "Active cloud subscription required" }

Заголовок X-Subscription-Required позволяет клиентам отличить блокировку из-за подписки от обычного отказа в доступе. Восстановить доступ можно, снова активировав Cloud в приложении для iOS или на dashboard.manilo.app/upgrade.

Ошибки

Ошибки используют стандартные коды состояния HTTP. Тело ответа — JSON-объект с единственным полем:

JSON
{ "error": "Human-readable message" }

Коды состояния, которые стоит обрабатывать:

200
OK — возвращён ресурс или возвращён список.
201
Created — создан новый ресурс. Заголовок Location указывает на канонический URL.
204
No Content — удаление выполнено успешно; тела нет.
400
Проверка не пройдена — не указано обязательное поле, значение вне диапазона, некорректный JSON.
401
Аутентификация не пройдена — см. раздел Аутентификация.
403
Доступ запрещён — недостаточно скоупов или неактивна подписка.
404
Ресурс не найден или скрыт правами доступа.
409
Конфликт — например, нарушение уникальности.
5xx
Сбой на стороне сервера. Идемпотентные чтения можно безопасно повторить с экспоненциальной задержкой.

Пагинация и фильтры

Списочные эндпоинты по умолчанию возвращают все подходящие элементы. Транзакции — единственный ресурс, который может сильно вырасти, — поддерживают курсорную пагинацию.

Курсор транзакций

cURLСписок с пагинацией
curl "https://api.manilo.app/api/v1/transactions?limit=50&type=expense&dateFrom=2026-01-01" \
  -H "Authorization: Bearer lgpat_…"

В ответ включается nextCursor. Передайте его обратно в query-параметре cursor, чтобы получить следующую страницу; когда nextCursor равен null, вы дошли до конца.

  • limit — размер страницы, ограничен диапазоном 1..200. По умолчанию 50.
  • cursor — непрозрачный токен. Считайте его чёрным ящиком.
  • type, dateFrom, dateTo, categoryId, accountId, groupId — необязательные фильтры; см. эндпоинт Список транзакций.

Типы и форматы

  • Идентификаторы — непрозрачные строки. Не разбирайте их; считайте их регистрозависимыми UTF-8-идентификаторами.
  • Отметки времени — ISO-8601 в UTC с завершающим Z, например "2026-05-13T10:30:00Z".
  • Даты (например, поле транзакции date) — тот же формат ISO-8601, но значима только календарная часть.
  • Деньги — JSON-числа в основных единицах с точностью до 4 знаков после запятой (например, 12.50). Никогда не в разменных единицах. Всегда вместе с currencyCode.
  • Коды валют — ISO-4217, ровно три заглавные буквы (например, "EUR", "USD", "GBP").
  • Удаление — все операции удаления выполняются как мягкое удаление. Удалённые элементы перестают появляться в ответах на запросы списка и получения по id; участники совместного доступа и ранее прикреплённые чеки сохраняются.
  • Побочные эффекты — удаление счёта, категории или группы не затрагивает связанные транзакции; их ссылки просто отвязываются. Эндпоинт Удаление счёта принимает явную стратегию.

Счета

Счета — это ёмкости, в которых лежат балансы: банковский счёт, кредитная карта, наличные, брокерский счёт. Каждая транзакция привязана к одному счёту (или к двум — в случае перевода).

GET /api/v1/accounts accounts:read

Возвращает все счета, которыми владеет аутентифицированный пользователь или к которым у него есть доступ.

GET /api/v1/accounts/{id} accounts:read

Возвращает один счёт по id. Если счёт не найден — 404.

POST /api/v1/accounts accounts:write

Создаёт новый счёт. Возвращает 201 с созданным объектом и заголовком Location.

Тело запроса
ПолеТипОписание
namestringобязательноеОтображаемое имя. Не более 100 символов.
currencyCodestringобязательноеISO-4217. Ровно 3 буквы.
initialBalancenumberобязательноеНачальный баланс в currencyCode.
orderintegerобязательноеПозиция сортировки. Меньшее значение — выше.
iconstringнеобязательноеИдентификатор иконки из /api/v1/icons. Не более 50 символов.
colorstringнеобязательноеЦвет в hex, например "#4A90E2". Не более 20 символов.
iconColorstringнеобязательноеПереопределяет цвет иконки.
Запрос
POST /api/v1/accounts
{
  "name": "Cash",
  "currencyCode": "EUR",
  "initialBalance": 50.00,
  "order": 2,
  "icon": "wallet",
  "color": "#22C55E"
}
201 Created
{
  "id": "acc_01HK8V…",
  "name": "Cash",
  "currencyCode": "EUR",
  "initialBalance": 50.00,
  "order": 2,
  "icon": "wallet",
  "color": "#22C55E",
  "iconColor": null,
  "shareInviteToken": null,
  "createdAt": "2026-05-13T10:30:00Z",
  "updatedAt": "2026-05-13T10:30:00Z"
}
PUT /api/v1/accounts/{id} accounts:write

Полностью заменяет существующий счёт. Тело запроса такое же, как в разделе Создание; передать нужно все поля.

DELETE /api/v1/accounts/{id} accounts:write

Мягко удаляет счёт. Судьбу его транзакций определяет query-параметр action.

Query-параметры
ПолеТипОписание
actionenumнеобязательноеDetach (по умолчанию): очищает ссылку на счёт в каждой транзакции. Move: переносит транзакции на счёт из moveTargetAccountId. DeleteAll: мягко удаляет все связанные транзакции, которыми вы владеете.
moveTargetAccountIdstringнеобязательноеОбязателен, когда action=Move. Идентификатор счёта-получателя.

Категории

Категории обозначают, на что идёт транзакция (продукты, аренда, доход от фриланса). Системные категории доступны только для чтения и общие для всех пользователей; пользовательские категории вы ведёте сами. Группы категорий объединяют связанные категории.

GET /api/v1/categories/system-categories categories:read

Возвращает подобранный набор «общеизвестных» категорий Manilo — стартовый набор, с которым поставляется приложение для iOS. Он версионируется глобально, поэтому его можно безопасно кешировать по полю version.

Пользовательские категории

GET /api/v1/categories categories:read

Возвращает все пользовательские категории.

GET /api/v1/categories/{id} categories:read

Возвращает одну пользовательскую категорию по id.

POST /api/v1/categories categories:write

Создаёт пользовательскую категорию.

Тело запроса
ПолеТипОписание
namestringобязательноеОтображаемое имя. Не более 100.
typestringобязательное"income" или "expense".
orderintegerобязательноеПозиция сортировки внутри своей группы.
isPinnedbooleanобязательноеЗакрепить вверху списка выбора.
categoryGroupIdstringнеобязательноеИдентификатор родительской группы или null — для категорий без группы.
iconstringнеобязательноеИдентификатор иконки.
colorstringнеобязательноеЦвет в hex.
PUT /api/v1/categories/{id} categories:write

Полностью заменяет пользовательскую категорию. Тело запроса такое же, как в разделе Создание.

DELETE /api/v1/categories/{id} categories:write

Мягко удаляет пользовательскую категорию. Транзакции не удаляются; у них очищается поле categoryId.

Группы категорий

GET /api/v1/categories/groups categories:read

Возвращает ваши группы категорий.

GET /api/v1/categories/groups/{id} categories:read

Возвращает одну группу категорий.

POST /api/v1/categories/groups categories:write

Создаёт группу категорий.

Тело запроса
ПолеТипОписание
namestringобязательноеОтображаемое имя. Не более 100.
orderintegerобязательноеПозиция сортировки.
iconstringнеобязательноеИдентификатор иконки.
colorstringнеобязательноеЦвет в hex.
PUT /api/v1/categories/groups/{id} categories:write

Полностью заменяет группу категорий.

DELETE /api/v1/categories/groups/{id} categories:write

Мягко удаляет группу. Вложенные категории сохраняются — у них очищается поле categoryGroupId.

Бюджеты

Бюджет ограничивает траты по категории (а если categoryId равен null — по всему учёту) в рамках повторяющегося периода. Чтобы поделиться бюджетом с группой, задайте groupId.

GET /api/v1/budgets budgets:read

Возвращает все бюджеты.

GET /api/v1/budgets/{id} budgets:read

Возвращает один бюджет.

POST /api/v1/budgets budgets:write

Создаёт бюджет.

Тело запроса
ПолеТипОписание
amountnumberобязательноеЛимит на период. Должен быть больше 0.
currencyCodestringобязательноеISO-4217.
periodintegerобязательное0 — неделя · 1 — месяц · 2 — квартал · 3 — год.
startDatestring (ISO-8601)обязательноеНачало первого периода.
isActivebooleanобязательноеДействует ли этот бюджет сейчас.
endDatestring (ISO-8601)необязательноеПрекратить отслеживание после этой даты.
namestringнеобязательноеНазвание. Не более 200.
categoryIdstringнеобязательноеКатегория для отслеживания. Не указывайте, чтобы охватить все траты.
groupIdstringнеобязательноеГруппа для совместного доступа. Не указывайте для личного бюджета.
PUT /api/v1/budgets/{id} budgets:write

Полностью заменяет бюджет.

DELETE /api/v1/budgets/{id} budgets:write

Мягко удаляет бюджет.

Группы

Группы — это общие учёты: домохозяйство, поездка, съёмная квартира. Все участники видят одни и те же транзакции, но владение остаётся личным. Участниками и приглашениями вы управляете в приложении для iOS; в API доступен сам ресурс.

GET /api/v1/groups groups:read

Возвращает группы, которыми вы владеете или в которых состоите.

GET /api/v1/groups/{id} groups:read

Возвращает одну группу.

POST /api/v1/groups groups:write

Создаёт группу. Вы становитесь её владельцем; приглашайте участников из приложения для iOS.

Тело запроса
ПолеТипОписание
namestringобязательноеОтображаемое имя. Не более 100.
descriptionstringнеобязательноеПроизвольный текст. Не более 500.
iconstringнеобязательноеИдентификатор иконки.
colorstringнеобязательноеЦвет в hex.
PUT /api/v1/groups/{id} groups:write

Полностью заменяет метаданные группы.

DELETE /api/v1/groups/{id} groups:write

Мягко удаляет группу. Участники теряют доступ к просмотру; связанные транзакции возвращаются в личный учёт.

Транзакции

Транзакции — это глаголы учёта. Они бывают четырёх видов: income, expense, transfer (со счёта на счёт) и adjustment (разовая корректировка баланса). Базовый эндпоинт создаёт доходы и расходы; у переводов свой эндпоинт; для импортеров с большими объёмами есть пакетные варианты.

GET /api/v1/transactions transactions:read

Возвращает транзакции с курсорной пагинацией и фильтрами.

Query-параметры
ПолеТипОписание
limitintegerнеобязательноеРазмер страницы. Диапазон 1..200. По умолчанию 50.
cursorstringнеобязательноеНепрозрачный токен продолжения из предыдущего ответа.
typestringнеобязательное"income", "expense", "transfer" или "adjustment".
dateFromstring (ISO-8601)необязательноеНижняя граница включительно.
dateTostring (ISO-8601)необязательноеВерхняя граница включительно.
categoryIdstringнеобязательноеФильтр по одной категории.
accountIdstringнеобязательноеФильтр по одному счёту.
groupIdstringнеобязательноеФильтр по общей группе.
200 OK
{
  "items": [ /* TransactionDto[] */ ],
  "totalCount": 317,
  "nextCursor": "eyJrIjoiMjAyNi0wNS0xM1QxMDoz…"
}
GET /api/v1/transactions/{id} transactions:read

Возвращает одну транзакцию.

POST /api/v1/transactions transactions:write

Создаёт одну транзакцию дохода или расхода. Для переводов используйте /transfer.

Тело запроса
ПолеТипОписание
typestringобязательное"income" или "expense".
amountnumberобязательноеПоложительная сумма в currencyCode.
currencyCodestringобязательноеISO-4217.
datestring (ISO-8601)обязательноеКогда произошла транзакция (UTC).
accountIdstringнеобязательноеСчёт списания или зачисления.
categoryIdstringнеобязательноеКатегория.
payeestringнеобязательноеПродавец или контрагент. Не более 200.
notestringнеобязательноеПроизвольная заметка. Не более 2000.
groupIdstringнеобязательноеПоделиться с группой.
exchangeRatenumberнеобязательноеКурс обмена, если currencyCode ≠ основной валюты пользователя.
convertedAmountnumberнеобязательноеСумма в основной валюте пользователя.
ЗапросКофе за €8.50 вчера через Wise
POST /api/v1/transactions
{
  "type": "expense",
  "amount": 8.50,
  "currencyCode": "EUR",
  "date": "2026-05-12T09:14:00Z",
  "accountId": "acc_01HK8V…",
  "categoryId": "cat_food_drinks",
  "payee": "Pret",
  "note": "Flat white"
}
PUT /api/v1/transactions/{id} transactions:write

Полностью заменяет транзакцию. Тело запроса такое же, как в разделе Создание.

DELETE /api/v1/transactions/{id} transactions:write

Мягко удаляет одну транзакцию.

POST /api/v1/transactions/transfer transactions:write

Создаёт перевод между двумя счетами. Без категории. Для переводов между валютами укажите exchangeRate и convertedAmount в валюте счёта-получателя.

Тело запроса
ПолеТипОписание
fromAccountIdstringобязательноеСчёт списания.
toAccountIdstringобязательноеСчёт зачисления. Должен отличаться от счёта списания.
amountnumberобязательноеОтправляемая сумма в currencyCode.
currencyCodestringобязательноеВалюта списания, ISO-4217.
datestring (ISO-8601)обязательноеДата перевода.
exchangeRatenumberнеобязательноеОбязателен, когда валюты счёта списания и счёта зачисления различаются.
convertedAmountnumberнеобязательноеСумма, зачисленная на счёт-получатель, в его валюте.
notestringнеобязательноеНе более 2000.

Пакетные операции

Рассчитано на импортеры. Каждый пакет ограничен 100 элементами и выполняется по принципу best-effort: одна ошибочная строка не откатывает остальные. Успешные элементы и построчные ошибки возвращаются отдельно, чтобы вы могли повторить только неудачные.

POST /api/v1/transactions/bulk transactions:write

Создаёт до 100 транзакций за один вызов.

200 OK
{
  "items": [ /* successful TransactionDto[] */ ],
  "errors": [
    { "index": 3, "error": "Invalid currency code" }
  ]
}
PUT /api/v1/transactions/bulk transactions:write

Обновляет до 100 транзакций за один вызов. Каждый элемент должен содержать свой id вместе с полным телом транзакции.

POST /api/v1/transactions/bulk-delete transactions:write

Мягко удаляет до 100 транзакций за один вызов. Использует POST вместо DELETE, чтобы тело запроса принимали все HTTP-клиенты.

Тело запроса
ПолеТипОписание
idsstring[]обязательноеОт 1 до 100 идентификаторов транзакций.
200 OK
{
  "deleted": 97,
  "notFound": [ "tx_old1", "tx_old2", "tx_old3" ]
}

Объект транзакции

ПолеТипОписание
idstringНепрозрачный идентификатор.
typestringincome · expense · transfer · adjustment.
amountnumberВ currencyCode.
currencyCodestringISO-4217.
exchangeRatenumber | nullЗадаётся для записей в другой валюте.
convertedAmountnumber | nullТо же значение в основной валюте пользователя.
datestringISO-8601 UTC.
accountIdstring | nullДля переводов это счёт списания.
toAccountIdstring | nullСчёт зачисления — только для переводов.
categoryIdstring | nullNull для переводов.
groupIdstring | nullЗадан, если запись общая с группой.
payeestring | nullПродавец или контрагент.
notestring | nullПроизвольный текст.
receiptImagePathstring | nullПуть к прикреплённому чеку. Загружается через эндпоинт чеков (отдельный от v1).
recurringTransactionIdstring | nullЗадан, если запись создана повторяющимся правилом.
sourcestringМетка источника — api, mobile, web, import и т. д.
createdAtstringISO-8601 UTC.
updatedAtstringISO-8601 UTC.

Иконки

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

GET /api/v1/icons

Возвращает полную библиотеку иконок, сгруппированную по категориям, вместе с поддерживаемой палитрой цветов. Версионируется — можно безопасно кешировать по полю version.

200 OK
{
  "version": "2026.05.10",
  "library": "font-awesome-6",
  "categories": [
    {
      "id": "finance",
      "name": "Finance",
      "icons": [ "wallet", "credit-card", "piggy-bank" ]
    }
  ],
  "colors": [
    { "name": "Blue", "hex": "#4A90E2" },
    { "name": "Green", "hex": "#22C55E" }
  ]
}

Версионирование

  • Внутри v1 ломающих изменений не будет. Мы будем только добавлять новые эндпоинты, новые необязательные поля и новые значения перечислений. Тип поля, его обязательность и допустимость null меняться не будут.
  • Новые значения перечислений не считаются ломающими. Неизвестные значения type, source или action обрабатывайте как «не отображать», а не падайте с ошибкой — мы будем добавлять их по мере развития продукта.
  • Ломающие изменения формата дат (если они когда-нибудь понадобятся) выйдут под /api/v2/ — с параллельной доступностью не менее 6 месяцев и заголовком об устаревании в ответах v1.

Поддержка

Нашли баг, нужен новый эндпоинт или столкнулись с чем-то, чего нет в документации? Откройте центр поддержки или напишите на support@manilo.app — сообщая о проблеме, укажите, пожалуйста, идентификатор запроса (он возвращается в заголовке ответа X-Request-Id).

О проблемах безопасности (утечка токена, обход прав доступа, несанкционированное чтение) пишите на security@manilo.app.