Обзор
Manilo API — это JSON REST API для программной работы с тем же учётом, который вы ведёте в приложении для iOS: счетами, категориями, бюджетами, общими группами и транзакциями. Используйте его, чтобы писать импортеры, экспортеры, мосты синхронизации, дашборды или собственные автоматизации.
- Базовый URL:
https://api.manilo.app— прежний базовый URLapi.ledgy.appпродолжает работать. - Префикс версии: все эндпоинты в этом документе размещены по пути
/api/v1/. - Транспорт: только HTTPS. HTTP-запросы не принимаются.
- Кодировка: тела запросов и ответов в JSON. UTF-8. Имена свойств —
camelCase. - Аутентификация:
Authorization: Bearer …в каждом запросе. - Подписка Cloud: требуется для каждого эндпоинта v1. См. раздел Проверка подписки.
https://api.manilo.app/mcp — см. Интеграции. Описанный здесь REST API предназначен для кода, который вы пишете сами.
Быстрый старт
Три шага до вашего первого аутентифицированного запроса.
1. Создайте персональный токен доступа
- Войдите в свой дашборд Manilo и откройте Настройки → API Access.
- Нажмите + New token.
- Дайте токену понятное имя (например, «Zapier — еженедельный экспорт»), выберите нужные скоупы (см. Скоупы) и при желании задайте срок действия.
- Скопируйте токен. Он показывается один раз. Токены начинаются с префикса
lgpat_, за которым следуют 64 шестнадцатеричных символа.
На этой же странице перечислены ваши активные токены с временем последнего использования и количеством разрешений, появляется предупреждение «Истекает через 30 дней», а любой токен можно мгновенно отозвать по значку корзины. В одном аккаунте одновременно может быть до 25 активных токенов.
2. Выполните запрос
# Replace lgpat_… with your token curl "https://api.manilo.app/api/v1/accounts" \ -H "Authorization: Bearer lgpat_a1b2c3d4e5…"
3. Разберите ответ
{
"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/v1/ должен содержать заголовок Authorization. Принимаются два типа токенов:
- Персональный токен доступа (PAT) — долгоживущий bearer-токен, который вы создаёте в дашборде на странице Настройки → API Access. Формат:
lgpat_+ 64 шестнадцатеричных символа. Ограничен скоупами, отзывается, может иметь срок действия. Рекомендуется для всех сторонних интеграций. - Сессионный JWT — короткоживущий токен, который выдаётся собственным приложениям (iOS, дашборд). Не имеет ограничений по скоупам. Его можно использовать для разовой проверки, если вы сумеете извлечь его из авторизованной сессии, но поддерживаемый путь — это PAT.
Формат заголовка
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 отвечает так:
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-объект с единственным полем:
{ "error": "Human-readable message" }
Коды состояния, которые стоит обрабатывать:
- 200
- OK — возвращён ресурс или возвращён список.
- 201
- Created — создан новый ресурс. Заголовок
Locationуказывает на канонический URL. - 204
- No Content — удаление выполнено успешно; тела нет.
- 400
- Проверка не пройдена — не указано обязательное поле, значение вне диапазона, некорректный JSON.
- 401
- Аутентификация не пройдена — см. раздел Аутентификация.
- 403
- Доступ запрещён — недостаточно скоупов или неактивна подписка.
- 404
- Ресурс не найден или скрыт правами доступа.
- 409
- Конфликт — например, нарушение уникальности.
- 5xx
- Сбой на стороне сервера. Идемпотентные чтения можно безопасно повторить с экспоненциальной задержкой.
Пагинация и фильтры
Списочные эндпоинты по умолчанию возвращают все подходящие элементы. Транзакции — единственный ресурс, который может сильно вырасти, — поддерживают курсорную пагинацию.
Курсор транзакций
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; участники совместного доступа и ранее прикреплённые чеки сохраняются.
- Побочные эффекты — удаление счёта, категории или группы не затрагивает связанные транзакции; их ссылки просто отвязываются. Эндпоинт Удаление счёта принимает явную стратегию.
Счета
Счета — это ёмкости, в которых лежат балансы: банковский счёт, кредитная карта, наличные, брокерский счёт. Каждая транзакция привязана к одному счёту (или к двум — в случае перевода).
/api/v1/accounts
accounts:read
Возвращает все счета, которыми владеет аутентифицированный пользователь или к которым у него есть доступ.
/api/v1/accounts/{id}
accounts:read
Возвращает один счёт по id. Если счёт не найден — 404.
/api/v1/accounts
accounts:write
Создаёт новый счёт. Возвращает 201 с созданным объектом и заголовком Location.
| Поле | Тип | Описание |
|---|---|---|
| name | string | обязательноеОтображаемое имя. Не более 100 символов. |
| currencyCode | string | обязательноеISO-4217. Ровно 3 буквы. |
| initialBalance | number | обязательноеНачальный баланс в currencyCode. |
| order | integer | обязательноеПозиция сортировки. Меньшее значение — выше. |
| icon | string | необязательноеИдентификатор иконки из /api/v1/icons. Не более 50 символов. |
| color | string | необязательноеЦвет в hex, например "#4A90E2". Не более 20 символов. |
| iconColor | string | необязательноеПереопределяет цвет иконки. |
POST /api/v1/accounts
{
"name": "Cash",
"currencyCode": "EUR",
"initialBalance": 50.00,
"order": 2,
"icon": "wallet",
"color": "#22C55E"
}
{
"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"
}
/api/v1/accounts/{id}
accounts:write
Полностью заменяет существующий счёт. Тело запроса такое же, как в разделе Создание; передать нужно все поля.
/api/v1/accounts/{id}
accounts:write
Мягко удаляет счёт. Судьбу его транзакций определяет query-параметр action.
| Поле | Тип | Описание |
|---|---|---|
| action | enum | необязательноеDetach (по умолчанию): очищает ссылку на счёт в каждой транзакции. Move: переносит транзакции на счёт из moveTargetAccountId. DeleteAll: мягко удаляет все связанные транзакции, которыми вы владеете. |
| moveTargetAccountId | string | необязательноеОбязателен, когда action=Move. Идентификатор счёта-получателя. |
Категории
Категории обозначают, на что идёт транзакция (продукты, аренда, доход от фриланса). Системные категории доступны только для чтения и общие для всех пользователей; пользовательские категории вы ведёте сами. Группы категорий объединяют связанные категории.
/api/v1/categories/system-categories
categories:read
Возвращает подобранный набор «общеизвестных» категорий Manilo — стартовый набор, с которым поставляется приложение для iOS. Он версионируется глобально, поэтому его можно безопасно кешировать по полю version.
Пользовательские категории
/api/v1/categories
categories:read
Возвращает все пользовательские категории.
/api/v1/categories/{id}
categories:read
Возвращает одну пользовательскую категорию по id.
/api/v1/categories
categories:write
Создаёт пользовательскую категорию.
| Поле | Тип | Описание |
|---|---|---|
| name | string | обязательноеОтображаемое имя. Не более 100. |
| type | string | обязательное"income" или "expense". |
| order | integer | обязательноеПозиция сортировки внутри своей группы. |
| isPinned | boolean | обязательноеЗакрепить вверху списка выбора. |
| categoryGroupId | string | необязательноеИдентификатор родительской группы или null — для категорий без группы. |
| icon | string | необязательноеИдентификатор иконки. |
| color | string | необязательноеЦвет в hex. |
/api/v1/categories/{id}
categories:write
Полностью заменяет пользовательскую категорию. Тело запроса такое же, как в разделе Создание.
/api/v1/categories/{id}
categories:write
Мягко удаляет пользовательскую категорию. Транзакции не удаляются; у них очищается поле categoryId.
Группы категорий
/api/v1/categories/groups
categories:read
Возвращает ваши группы категорий.
/api/v1/categories/groups/{id}
categories:read
Возвращает одну группу категорий.
/api/v1/categories/groups
categories:write
Создаёт группу категорий.
| Поле | Тип | Описание |
|---|---|---|
| name | string | обязательноеОтображаемое имя. Не более 100. |
| order | integer | обязательноеПозиция сортировки. |
| icon | string | необязательноеИдентификатор иконки. |
| color | string | необязательноеЦвет в hex. |
/api/v1/categories/groups/{id}
categories:write
Полностью заменяет группу категорий.
/api/v1/categories/groups/{id}
categories:write
Мягко удаляет группу. Вложенные категории сохраняются — у них очищается поле categoryGroupId.
Бюджеты
Бюджет ограничивает траты по категории (а если categoryId равен null — по всему учёту) в рамках повторяющегося периода. Чтобы поделиться бюджетом с группой, задайте groupId.
/api/v1/budgets
budgets:read
Возвращает все бюджеты.
/api/v1/budgets/{id}
budgets:read
Возвращает один бюджет.
/api/v1/budgets
budgets:write
Создаёт бюджет.
| Поле | Тип | Описание |
|---|---|---|
| amount | number | обязательноеЛимит на период. Должен быть больше 0. |
| currencyCode | string | обязательноеISO-4217. |
| period | integer | обязательное0 — неделя · 1 — месяц · 2 — квартал · 3 — год. |
| startDate | string (ISO-8601) | обязательноеНачало первого периода. |
| isActive | boolean | обязательноеДействует ли этот бюджет сейчас. |
| endDate | string (ISO-8601) | необязательноеПрекратить отслеживание после этой даты. |
| name | string | необязательноеНазвание. Не более 200. |
| categoryId | string | необязательноеКатегория для отслеживания. Не указывайте, чтобы охватить все траты. |
| groupId | string | необязательноеГруппа для совместного доступа. Не указывайте для личного бюджета. |
/api/v1/budgets/{id}
budgets:write
Полностью заменяет бюджет.
/api/v1/budgets/{id}
budgets:write
Мягко удаляет бюджет.
Группы
Группы — это общие учёты: домохозяйство, поездка, съёмная квартира. Все участники видят одни и те же транзакции, но владение остаётся личным. Участниками и приглашениями вы управляете в приложении для iOS; в API доступен сам ресурс.
/api/v1/groups
groups:read
Возвращает группы, которыми вы владеете или в которых состоите.
/api/v1/groups/{id}
groups:read
Возвращает одну группу.
/api/v1/groups
groups:write
Создаёт группу. Вы становитесь её владельцем; приглашайте участников из приложения для iOS.
| Поле | Тип | Описание |
|---|---|---|
| name | string | обязательноеОтображаемое имя. Не более 100. |
| description | string | необязательноеПроизвольный текст. Не более 500. |
| icon | string | необязательноеИдентификатор иконки. |
| color | string | необязательноеЦвет в hex. |
/api/v1/groups/{id}
groups:write
Полностью заменяет метаданные группы.
/api/v1/groups/{id}
groups:write
Мягко удаляет группу. Участники теряют доступ к просмотру; связанные транзакции возвращаются в личный учёт.
Транзакции
Транзакции — это глаголы учёта. Они бывают четырёх видов: income, expense, transfer (со счёта на счёт) и adjustment (разовая корректировка баланса). Базовый эндпоинт создаёт доходы и расходы; у переводов свой эндпоинт; для импортеров с большими объёмами есть пакетные варианты.
/api/v1/transactions
transactions:read
Возвращает транзакции с курсорной пагинацией и фильтрами.
| Поле | Тип | Описание |
|---|---|---|
| limit | integer | необязательноеРазмер страницы. Диапазон 1..200. По умолчанию 50. |
| cursor | string | необязательноеНепрозрачный токен продолжения из предыдущего ответа. |
| type | string | необязательное"income", "expense", "transfer" или "adjustment". |
| dateFrom | string (ISO-8601) | необязательноеНижняя граница включительно. |
| dateTo | string (ISO-8601) | необязательноеВерхняя граница включительно. |
| categoryId | string | необязательноеФильтр по одной категории. |
| accountId | string | необязательноеФильтр по одному счёту. |
| groupId | string | необязательноеФильтр по общей группе. |
{
"items": [ /* TransactionDto[] */ ],
"totalCount": 317,
"nextCursor": "eyJrIjoiMjAyNi0wNS0xM1QxMDoz…"
}
/api/v1/transactions/{id}
transactions:read
Возвращает одну транзакцию.
/api/v1/transactions
transactions:write
Создаёт одну транзакцию дохода или расхода. Для переводов используйте /transfer.
| Поле | Тип | Описание |
|---|---|---|
| type | string | обязательное"income" или "expense". |
| amount | number | обязательноеПоложительная сумма в currencyCode. |
| currencyCode | string | обязательноеISO-4217. |
| date | string (ISO-8601) | обязательноеКогда произошла транзакция (UTC). |
| accountId | string | необязательноеСчёт списания или зачисления. |
| categoryId | string | необязательноеКатегория. |
| payee | string | необязательноеПродавец или контрагент. Не более 200. |
| note | string | необязательноеПроизвольная заметка. Не более 2000. |
| groupId | string | необязательноеПоделиться с группой. |
| exchangeRate | number | необязательноеКурс обмена, если currencyCode ≠ основной валюты пользователя. |
| convertedAmount | number | необязательноеСумма в основной валюте пользователя. |
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"
}
/api/v1/transactions/{id}
transactions:write
Полностью заменяет транзакцию. Тело запроса такое же, как в разделе Создание.
/api/v1/transactions/{id}
transactions:write
Мягко удаляет одну транзакцию.
/api/v1/transactions/transfer
transactions:write
Создаёт перевод между двумя счетами. Без категории. Для переводов между валютами укажите exchangeRate и convertedAmount в валюте счёта-получателя.
| Поле | Тип | Описание |
|---|---|---|
| fromAccountId | string | обязательноеСчёт списания. |
| toAccountId | string | обязательноеСчёт зачисления. Должен отличаться от счёта списания. |
| amount | number | обязательноеОтправляемая сумма в currencyCode. |
| currencyCode | string | обязательноеВалюта списания, ISO-4217. |
| date | string (ISO-8601) | обязательноеДата перевода. |
| exchangeRate | number | необязательноеОбязателен, когда валюты счёта списания и счёта зачисления различаются. |
| convertedAmount | number | необязательноеСумма, зачисленная на счёт-получатель, в его валюте. |
| note | string | необязательноеНе более 2000. |
Пакетные операции
Рассчитано на импортеры. Каждый пакет ограничен 100 элементами и выполняется по принципу best-effort: одна ошибочная строка не откатывает остальные. Успешные элементы и построчные ошибки возвращаются отдельно, чтобы вы могли повторить только неудачные.
/api/v1/transactions/bulk
transactions:write
Создаёт до 100 транзакций за один вызов.
{
"items": [ /* successful TransactionDto[] */ ],
"errors": [
{ "index": 3, "error": "Invalid currency code" }
]
}
/api/v1/transactions/bulk
transactions:write
Обновляет до 100 транзакций за один вызов. Каждый элемент должен содержать свой id вместе с полным телом транзакции.
/api/v1/transactions/bulk-delete
transactions:write
Мягко удаляет до 100 транзакций за один вызов. Использует POST вместо DELETE, чтобы тело запроса принимали все HTTP-клиенты.
| Поле | Тип | Описание |
|---|---|---|
| ids | string[] | обязательноеОт 1 до 100 идентификаторов транзакций. |
{
"deleted": 97,
"notFound": [ "tx_old1", "tx_old2", "tx_old3" ]
}
Объект транзакции
| Поле | Тип | Описание |
|---|---|---|
| id | string | Непрозрачный идентификатор. |
| type | string | income · expense · transfer · adjustment. |
| amount | number | В currencyCode. |
| currencyCode | string | ISO-4217. |
| exchangeRate | number | null | Задаётся для записей в другой валюте. |
| convertedAmount | number | null | То же значение в основной валюте пользователя. |
| date | string | ISO-8601 UTC. |
| accountId | string | null | Для переводов это счёт списания. |
| toAccountId | string | null | Счёт зачисления — только для переводов. |
| categoryId | string | null | Null для переводов. |
| groupId | string | null | Задан, если запись общая с группой. |
| payee | string | null | Продавец или контрагент. |
| note | string | null | Произвольный текст. |
| receiptImagePath | string | null | Путь к прикреплённому чеку. Загружается через эндпоинт чеков (отдельный от v1). |
| recurringTransactionId | string | null | Задан, если запись создана повторяющимся правилом. |
| source | string | Метка источника — api, mobile, web, import и т. д. |
| createdAt | string | ISO-8601 UTC. |
| updatedAt | string | ISO-8601 UTC. |
Иконки
Manilo поставляется с подобранным набором иконок и палитрой цветов, которые используются везде — для счетов, категорий, групп. Получите каталог один раз, закешируйте его и переиспользуйте идентификаторы при создании ресурсов.
/api/v1/icons
Возвращает полную библиотеку иконок, сгруппированную по категориям, вместе с поддерживаемой палитрой цветов. Версионируется — можно безопасно кешировать по полю version.
{
"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.