Розробникам

Довідник 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. Див. Обмеження за підпискою.
Потрібен AI-асистент? Якщо ви хочете, щоб Claude, ChatGPT чи Cursor працювали з Manilo від вашого імені, скористайтеся ендпоїнтом Model Context Protocol за адресою https://api.manilo.app/mcp — див. Інтеграції. Описаний тут REST API призначений для коду, який ви пишете самі.

Швидкий старт

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

1. Створіть Personal Access Token

  1. Увійдіть у дашборд Manilo і відкрийте Налаштування → API Access.
  2. Натисніть + Новий токен.
  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. Приймаються два типи токенів:

  • Personal Access Token (PAT) — довгоживучий bearer-токен, який ви створюєте в дашборді на сторінці Налаштування → API Access. Формат: lgpat_ + 64 шістнадцяткові символи. Обмежений скоупами, відкликається, за бажанням із терміном дії. Рекомендовано для всіх сторонніх інтеграцій.
  • Session JWT — короткоживучий токен, що видається власним застосункам (iOS, дашборд). Не має обмежень за скоупами. Його можна використати для разового тестування, якщо вдасться дістати його із сеансу зі входом, але підтримуваний шлях — це PAT.

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

HTTP
Authorization: Bearer lgpat_a1b2c3d4e5f6…

Обмеження токенів

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

Типові помилки автентифікації

401
Токен відсутній, має неправильний формат, прострочений або відкликаний.
403
Токен дійсний, але запитаний ендпоїнт потребує скоупа, якого немає у вашого PAT, або ваша підписка Cloud неактивна.

Скоупи

PAT працюють за моделлю deny-by-default. Токен може викликати лише ті ендпоїнти, потрібний скоуп яких він має; усе інше повертає 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
Conflict — наприклад, порушення обмеження унікальності.
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").
  • Видалення — усі операції видалення є м’якими видаленнями. Видалені елементи перестають з’являтися у відповідях списку та отримання; партнери зі спільного доступу й історичні чеки зберігаються.
  • Побічні ефекти — видалення рахунку, категорії чи групи залишає залежні транзакції недоторканими; їхні посилання від’єднуються. Ендпоїнт Видалити рахунок приймає явну стратегію.

Рахунки

Рахунки — це контейнери, що зберігають баланси: банківський рахунок, кредитна картка, готівковий гаманець, брокерський рахунок. Кожна транзакція прив’язана до одного рахунку (або до двох — для переказів).

GET /api/v1/accounts accounts:read

Повертає кожен рахунок, яким володіє автентифікований користувач або до якого він має доступ.

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

Отримати один рахунок за ідентифікатором. Якщо не знайдено — 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

Отримати одну користувацьку категорію за ідентифікатором.

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 (разове вирівнювання балансу). Базовий ендпоїнт створює income/expense; для переказів є власний ендпоїнт; для імпортерів великих обсягів існують пакетні варіанти.

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.