Документація API
Fintable підключається до ваших банків і синхронізує рахунки, баланси, транзакції та інвестиційні активи з таблицями на кшталт Google Sheets чи Airtable. Fintable API V2 відкриває ці самі дані (і не тільки!) для вашого власного коду: усе, що зберігається у Fintable — банківські підключення, рахунки, транзакції, інвестиційні активи, категоризатор і ваші інтеграції з таблицями — доступне через зрозумілий REST-інтерфейс.
Проте Fintable API — це не лише про ваші приватні фінансові дані. Це також публічний API публічної фінансової інформації, як-от курси валют і ціни акцій. Fintable API задуманий як єдине джерело всього необхідного, щоб побудувати з нуля власний фінансовий застосунок (для себе, а не на перепродаж).
API приватних даних
Використовується, щоб отримувати ваші приватні фінансові дані — як-от баланси банківських рахунків і транзакції.
API публічних даних
Містить публічні фінансові дані, дуже корисні для створення повноцінних фінансових застосунків і дашбордів, — як-от актуальні курси валют і ціни акцій.
API панелі / керування
Використовується, щоб керувати самим Fintable, створювати нові банківські підключення та перевіряти стан їхньої синхронізації — так що вам навіть не доведеться заходити в панель Fintable.
Жодного доступу третіх сторін для платформ чи застосунків — лише ваші дані
Fintable API призначений строго для власних даних — для банківських рахунків, якими ви володієте або які маєте право контролювати безпосередньо (наприклад, рахунки ваших клієнтів, якщо ви бухгалтер). Це не платформа агрегації даних на кшталт Plaid — його не можна й не слід використовувати для створення фінансових застосунків на перепродаж, лише для себе.
Початок роботи
Ніколи раніше не користувалися Fintable? Ось увесь шлях — від нуля до першого виклику API над власними банківськими даними.
| Базова URL-адреса | https://fintable.io/api/v2 |
| Опис OpenAPI 3.1 | https://fintable.io/api/v2/openapi.json |
| MCP-сервер для AI-асистентів | https://fintable.io/mcp |
| AI-скіл або документація для LLM (llms.txt) | https://fintable.io/llms.txt |
| Керування токенами | Панель → API |
1. Створіть акаунт Fintable
Зареєструйтеся тут — почати можна безкоштовно, і безкоштовний тариф включає доступ до API, тож ви можете розробляти на його основі ще до того, як за щось платити.
2. Створіть персональний токен доступу
Відкрийте Панель → API і створіть персональний токен доступу, обравши доступ лише для читання або читання й запис. Токен показується лише один раз, тож скопіюйте його в безпечне місце й ставтеся до нього як до пароля. Саме його ваші скрипти надсилатимуть, щоб автентифікуватися від вашого імені.
3. Підключіть банківський рахунок
Створіть посилання, відкрийте отриману URL-адресу й пройдіть кроки у браузері, щоб завершити підключення банку:
curl -X POST https://fintable.io/api/v2/connections/link \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
{
"data": {
"url": "https://fintable.io/api-link/eyJpdiI6...",
"expires_at": "2026-07-26T15:42:00Z"
}
}
Одноразове посилання діє 30 хвилин; щойно ви його пройдете, Fintable почне синхронізувати
рахунки й транзакції банку. Усі подробиці (попередній вибір установи, перепідключення,
право на підключення) — у розділі
POST /connections/link.
4. Отримайте свої баланси та транзакції
Щойно завершиться перша синхронізація — зазвичай за кілька хвилин — ваші дані вже на місці. Баланси:
curl https://fintable.io/api/v2/accounts \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": [
{
"id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
"name": "Chase Total Checking",
"balance": "5240.12",
"balance_available": "5190.12",
"currency": "USD",
"...": "..."
}
]
}
І транзакції:
curl "https://fintable.io/api/v2/transactions?limit=5" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": [
{
"id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
"date": "2026-07-24",
"amount": "-4.50",
"currency": "USD",
"description": "BLUE BOTTLE COFFEE",
"...": "..."
}
],
"next_cursor": null
}
Повні структури, фільтри й пагінація описані в розділах Рахунок і
Транзакція — і весь Довідник API побудований за тим
самим принципом. Віддаєте перевагу згенерованим клієнтам? Спрямуйте Swagger UI, Postman
чи свій генератор коду на опис OpenAPI 3.1:
https://fintable.io/api/v2/openapi.json.
Автентифікація
Є два способи входу — залежно від того, що саме ви створюєте:
- Персональні токени доступу — для власних скриптів та інструментів. Створіть токен у панелі, додайте його в заголовок — і готово.
- OAuth 2.0 — для застосунків і AI-асистентів, які підключаються до вашого акаунта через повноцінний потік авторизації (саме це використовує MCP-сервер під капотом).
Персональні токени доступу
Створюйте та відкликайте токени на сторінці
Панель → API. Токени діють 1 рік і мають ті
області, які ви обираєте під час створення, — лише читання (read) або читання й запис
(read + write). Надсилайте їх як bearer-заголовок:
Authorization: Bearer YOUR_TOKEN
Відкликання набуває чинності негайно.
OAuth 2.0
Fintable працює як стандартний сервер авторизації OAuth 2.0, тож підійде будь-яка готова клієнтська бібліотека OAuth:
| Endpoint | URL |
|---|---|
| Авторизація | https://fintable.io/oauth/authorize |
| Токен | https://fintable.io/oauth/token |
| Динамічна реєстрація клієнтів | https://fintable.io/oauth/register |
| Виявлення (discovery) | https://fintable.io/.well-known/oauth-authorization-server |
Кілька деталей, які варто знати:
- Підтримуваний grant — Authorization Code + PKCE.
- Токени доступу діють 1 годину; токени оновлення — 30 днів.
- Авторизація завжди вимагає входу та повторного підтвердження пароля акаунта. На екрані згоди чітко вказано, що саме зможе робити застосунок. Ця перешкода навмисна — це ваші банківські дані.
Області доступу
| Область | Що дозволяє |
|---|---|
read |
Читати всі дані акаунта |
write |
Змінювати дані — перейменовувати, категоризувати, вмикати/вимикати, видаляти, синхронізувати |
mcp:use |
Повний доступ на читання та запис для MCP-клієнтів (Claude, ChatGPT) |
mcp:use є надмножиною: він приймається всюди, де приймаються read або write.
Звичайні токени read/write MCP-ендпоїнт відхиляє.
Довідник API
Усе, що описано нижче, використовує ту саму bearer-автентифікацію, а спільні поведінки — конверти, суми у вигляді рядків, помилки, ліміти частоти, пагінація — описані в розділах Домовленості API і Пагінація нижче. Кожен розділ описує один тип ресурсу: що це, його точна структура (реалістичний приклад і пояснення кожного поля), а далі — ендпоїнти, які з ним працюють.
Профіль
| Endpoint | Що робить |
|---|---|
GET /me |
Ваш профіль і платіжні метадані |
Профіль — це ваш акаунт з погляду API: хто ви, на якому плані та скільки запасу вам лишилося. Перевіряйте його перед додаванням підключення чи запуском синхронізації — саме ці ліміти застосовують ендпоїнти запису.
{
"data": {
"name": "Jamie",
"tier": "personal",
"plan_period": "monthly",
"connection_limit": 10,
"connections_used": 3,
"tx_365_limit_usd": null,
"can_sync": true,
"renews_at": "2026-08-14T00:00:00Z",
"renewal_amount": "9.00",
"renewal_currency": "USD",
"will_renew": true,
"expires_at": "2026-08-14T00:00:00Z"
}
}
| Поле | Тип | Значення |
|---|---|---|
name |
string | Ваше видиме ім'я |
tier |
string | Рівень плану: free, trial, personal, office або enterprise |
plan_period |
string | null | Періодичність оплати: monthly, annual, lifetime, trial або manual; null на безкоштовних акаунтах |
connection_limit |
integer | Максимальна кількість банківських підключень, дозволена вашим планом. Додати підключення не вдасться, якщо connections_used уже досяг цього числа. Безкоштовні акаунти повідомляють поточну кількість як ліміт (вільних місць немає). |
connections_used |
integer | Скільки банківських підключень у вас зараз. Порівняйте з connection_limit, щоб дізнатися залишок: connection_limit - connections_used. Відключення банку зменшує це число; сам ліміт не змінюється, поки не зміниться план. |
tx_365_limit_usd |
integer | null | Рухомий ліміт обсягу транзакцій за 365 днів у USD; null означає без обмежень |
can_sync |
boolean | Чи доступні синхронізації (false на безкоштовних акаунтах) |
renews_at |
string | null | Час ISO-8601, коли поновлюється активна підписка |
renewal_amount |
string | null | Ціна поновлення у вигляді десяткового рядка |
renewal_currency |
string | null | Код валюти поновлення |
will_renew |
boolean | Чи поновиться підписка автоматично |
expires_at |
string | null | Коли завершується поточне право користування |
Безкоштовні акаунти отримують "tier": "free", "can_sync": false і поточну кількість
підключень як ліміт.
GET /me
Повертає ваш Профіль — об'єкт вище. Без параметрів:
curl https://fintable.io/api/v2/me \
-H "Authorization: Bearer YOUR_TOKEN"
Підключення
| Endpoint | Що робить |
|---|---|
GET /connections |
Список усіх підключень |
GET /connections/{id} |
Одне підключення |
PATCH /connections/{id} |
Перейменувати або задати дату початку синхронізації |
DELETE /connections/{id} |
Відключити банк і видалити його дані |
POST /connections/link |
Створити браузерне посилання для підключення нового банку |
POST /connections/{id}/link |
Створити браузерне посилання для перепідключення цього банку |
Підключення — це один прив'язаний банк, тобто один вхід в одну установу. Підключення володіє одним або кількома рахунками й містить стан справності та синхронізації цих банківських відносин.
{
"data": {
"id": "conn_plaid_1771845993762884095",
"provider": "PLAID",
"institution_name": "Chase",
"name": null,
"healthy": true,
"status_text": "OK",
"needs_reconnect": false,
"last_successful_update": "2026-07-26T09:12:44Z",
"created_at": "2025-11-02T18:20:11Z",
"accounts_count": 3,
"sync_status": {
"state": "finished",
"progress_now": 4,
"progress_max": 4,
"stage": "Sync complete",
"started_at": "2026-07-26T09:11:58Z",
"finished_at": "2026-07-26T09:12:44Z"
}
}
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор підключення, conn_{provider}_{number} |
provider |
string | Агрегатор, що стоїть за цим підключенням, напр. PLAID, NORDIGEN, AKOYA, FINICITY, MERCURY, SNAPTRADE |
institution_name |
string | Назва банку (ваша власна назва, якщо задана) |
name |
string | null | Ваша власна назва підключення |
healthy |
boolean | Збережений сигнал справності — false означає, що підключення потребує уваги |
status_text |
string | Зрозумілий статус: OK або повідомлення про помилку від провайдера |
needs_reconnect |
boolean | true, коли банк вимагає повторної автентифікації |
last_successful_update |
string | null | Час ISO-8601 останньої успішної синхронізації |
created_at |
string | Коли банк було підключено |
accounts_count |
integer | Кількість рахунків у цьому підключенні |
sync_status |
object | null | Найновіше завдання синхронізації — об'єкт Стан синхронізації |
GET /connections
Повертає список усіх ваших підключень. Без параметрів.
GET /connections/{id}
Одне підключення за ідентифікатором.
PATCH /connections/{id}
Перейменовує підключення або задає дату початку синхронізації. Приймає одне або обидва поля:
name— ваша власна назва, максимум 64 символи;nullочищає її.sync_start_date—YYYY-MM-DD;nullочищає її. Fintable синхронізуватиме транзакції лише починаючи з цієї дати.
curl -X PATCH https://fintable.io/api/v2/connections/conn_plaid_1771845993762884095 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Chase (Jamie)", "sync_start_date": "2026-01-01"}'
Відповідь — оновлений об'єкт підключення. Дві деталі: дата початку застосовується лише до увімкнених рахунків підключення (вимкнені зберігають свою дату до повторного ввімкнення), і дата перевіряється щодо мінімальної глибини історії провайдера та 30-денного ліміту пробних акаунтів (422, якщо поза діапазоном).
DELETE /connections/{id}
Відключає банк і видаляє його рахунки та транзакції з Fintable. Оскільки видалення залучає провайдера, воно завершується асинхронно — відповідь має код 202:
{
"data": {
"id": "conn_plaid_1771845993762884095",
"status": "deleting"
}
}
Підключення та його дані зникають протягом кількох хвилин.
POST /connections/link
Підключити банк означає увійти в нього, а сторінки входу в банк потребують справжнього браузера — тож це єдиний потік, який API не може завершити самостійно. Натомість цей ендпоїнт створює одноразову URL-адресу, дійсну 30 хвилин, яку ви відкриваєте самі (або передаєте власнику акаунта — це ж його акаунт):
curl -X POST https://fintable.io/api/v2/connections/link \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"institution": "12913262_chase"}'
{
"data": {
"url": "https://fintable.io/api-link/eyJpdiI6...",
"expires_at": "2026-07-26T15:42:00Z"
}
}
Поле institution необов'язкове — це slug із
каталогу Установ, який попередньо вибирає банк у потоці. Той, хто відкриє
URL-адресу, побачить, до якого акаунта Fintable виконується підключення, підтвердить
пароль акаунта й потрапить у потік вибору банку від провайдера. Посилання згоряє після
першого успішного підтвердження.
Створення посилання вимагає активного плану із запасом: активної підписки або пробного періоду, у межах ліміту підключень, у межах місячного ліміту спроб і в межах ліміту обсягу транзакцій — інакше 422 з поясненням (і ті самі перевірки виконуються повторно, коли банк справді створюється).
POST /connections/{id}/link
Працює так само, як POST /connections/link, але створює
посилання для перепідключення наявного підключення й звільнений від перевірок для
нових підключень.
Рахунок
| Endpoint | Що робить |
|---|---|
GET /accounts |
Список усіх рахунків, зокрема вимкнених |
GET /accounts/{id} |
Один рахунок |
PATCH /accounts/{id} |
Оновити display_name, sync_start_date та/або enabled |
Рахунок — це окремий банківський рахунок усередині підключення: поточний рахунок, ощадний рахунок, брокерський рахунок. Саме на рахунках зберігаються баланси, і саме їм належать транзакції.
{
"data": {
"id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
"connection_id": "conn_plaid_1771845993762884095",
"name": "Chase Total Checking",
"display_name": "Household checking",
"type": "depository / checking",
"currency": "USD",
"balance": "5240.12",
"balance_available": "5190.12",
"sync_start_date": "2026-01-01",
"last_tx_date": "2026-07-25",
"enabled": true,
"created_at": "2025-11-02T18:20:14Z",
"updated_at": "2026-07-26T09:12:40Z"
}
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор рахунку — непрозорий, зазвичай acc_... |
connection_id |
string | Підключення, якому належить цей рахунок |
name |
string | Назва рахунку в банку |
display_name |
string | null | Ваша власна назва — саме вона відображається у ваших таблицях |
type |
string | Вільний текст у стилі провайдера, як-от depository / checking чи investment / brokerage — показуйте його, але не будуйте на ньому логіку |
currency |
string | Діючий код валюти (враховує будь-яке задане вами перевизначення) |
balance |
string | null | Поточний баланс у вигляді десяткового рядка |
balance_available |
string | null | Доступний баланс, якщо банк його повідомляє |
sync_start_date |
string | null | YYYY-MM-DD — транзакції синхронізуються лише починаючи з цієї дати |
last_tx_date |
string | null | Дата найновішої синхронізованої транзакції |
enabled |
boolean | Чи синхронізується рахунок; вимкнені рахунки й далі показуються тут зі enabled: false |
created_at / updated_at |
string | Мітки часу ISO-8601 |
GET /accounts
Повертає всі рахунки, зокрема вимкнені (enabled: false). Фільтри:
connection_id, ids[] та enabled.
GET /accounts/{id}
Один рахунок за ідентифікатором.
PATCH /accounts/{id}
Оновлює display_name, sync_start_date та/або enabled.
Увага: вимкнення рахунку видаляє його транзакції. Встановлення
"enabled": falseназавжди видаляє всі транзакції цього рахунку у Fintable — так само, як перемикач у панелі. Повторне ввімкнення їх не відновлює; наступна синхронізація має завантажити їх від провайдера заново. Не вимикайте рахунок, якщо це не саме те, чого ви хочете.
Актив
| Endpoint | Що робить |
|---|---|
GET /accounts/{id}/holdings |
Один зріз активів рахунку |
Актив — це одна позиція на інвестиційному рахунку: акція, фонд або інший цінний папір.
Fintable зберігає активи як щоденні зрізи: що ви тримали й за якою ціною, раз на
день. Відповідь із активами — це набір рядків за одну дату зрізу, а сама дата подається
в конверті як snapshot_date.
{
"data": [
{
"id": "hol_01JB7Q2M5X8R4T6W9NKZP3VD1F",
"name": "Vanguard Total Stock Market ETF",
"symbol": "VTI",
"quantity": "42.0000",
"price": "279.35",
"value": "11732.70",
"cost_basis": "9450.00",
"currency": "USD",
"updated_at": "2026-07-26T09:12:41Z"
}
],
"snapshot_date": "2026-07-26"
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор активу — непрозорий, зазвичай hol_... |
name |
string | Назва цінного папера |
symbol |
string | null | Тікер, якщо провайдер його повідомляє |
quantity |
string | null | Кількість одиниць у вигляді десяткового рядка |
price |
string | null | Ціна за одиницю |
value |
string | null | Поточна ринкова вартість позиції |
cost_basis |
string | null | Загальна вартість позиції, а не за одну акцію — особливість провайдера, яку ми передаємо як є, а не намагаємося вгадати |
currency |
string | Діюча валюта рахунку |
updated_at |
string | null | Коли цей рядок було записано востаннє |
snapshot_date (конверт) |
string | null | День зрізу, який описує ця відповідь; null, коли на рахунку немає активів |
GET /accounts/{id}/holdings
За замовчуванням повертає найновіший зріз; ?date=YYYY-MM-DD вибирає конкретний.
Пагінації історії немає — завантажуйте дату за датою.
Транзакція
| Endpoint | Що робить |
|---|---|
GET /transactions |
Усі транзакції, з курсорною пагінацією |
GET /accounts/{id}/transactions |
Транзакції одного рахунку |
GET /transactions/{id} |
Одна транзакція |
PATCH /transactions/{id} |
Задати або очистити категорію |
PATCH /transactions/bulk |
Категоризувати багато транзакцій одразу |
Серце API. Транзакція — це один рух коштів на рахунку: покупка, надходження, переказ, комісія. Транзакції несуть стан категоризації — і призначену категорію, і те, чи була вона задана вручну, чи правилом.
{
"data": {
"id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
"account_id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
"date": "2026-07-24",
"datetime": "2026-07-24T16:41:02Z",
"auth_date": "2026-07-23",
"amount": "-4.50",
"currency": "USD",
"description": "BLUE BOTTLE COFFEE",
"merchant": "Blue Bottle Coffee",
"pending": false,
"check_num": null,
"external_memo": null,
"account_owner": null,
"category": {
"id": "dining-out_aB3xY9k2Lm",
"name": "Dining Out",
"header": "Expenses"
},
"category_manual_override": false,
"created_at": "2026-07-24T18:03:12Z",
"updated_at": "2026-07-25T06:14:09Z"
}
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор транзакції — непрозорий, зазвичай tx_... |
account_id |
string | Рахунок, якому належить ця транзакція |
date |
string | Дата транзакції, YYYY-MM-DD |
datetime |
string | null | Точний час ISO-8601, якщо провайдер його надає |
auth_date |
string | null | Дата авторизації, коли вона відрізняється від дати проведення |
amount |
string | Точний десятковий рядок; від'ємне значення — кошти на вихід |
currency |
string | Діючий код валюти |
description |
string | Опис із виписки |
merchant |
string | null | Очищена назва продавця, якщо відома |
pending |
boolean | true, поки транзакція не проведена — очікувані рядки можуть бути замінені після проведення |
check_num |
string | null | Номер чека для чекових платежів |
external_memo |
string | null | Додатковий текст примітки від банку |
account_owner |
string | null | Ім'я власника на спільних рахунках або рахунках із кількома власниками |
category |
object | null | Призначена Категорія — {id, name, header} — або null, якщо категорії немає |
category_manual_override |
boolean | true, коли категорію задано вручну; правила ніколи не чіпають такі рядки |
created_at / updated_at |
string | Мітки часу ISO-8601; updated_at є основою інкрементної синхронізації |
raw |
object | Сирий JSON провайдера — присутній лише з ?include=raw; ті самі дані, що й у полях **Raw ваших таблиць |
GET /transactions
Усі ваші транзакції, з курсорною пагінацією, за замовчуванням від найновіших. Фільтри:
| Фільтр | Значення |
|---|---|
date_from, date_to |
Діапазон дат (YYYY-MM-DD, включно) |
account_ids[] |
Обмежити конкретними рахунками |
category_ids[] |
Обмежити категоріями — вкажіть літерал uncategorized для рядків без категорії |
pending |
true або false |
amount_min, amount_max |
Діапазон сум |
q |
Пошук підрядка без урахування регістру за описом і продавцем |
description |
Точний збіг опису |
updated_since, order |
Для інкрементної синхронізації; order — це date або updated |
GET /accounts/{id}/transactions
Транзакції одного рахунку — ті самі фільтри, пагінація та структура, що й у
GET /transactions.
GET /transactions/{id}
Одна транзакція за ідентифікатором. ?include=raw працює й тут.
PATCH /transactions/{id}
Робить рівно одну річ — задає категорію:
curl -X PATCH https://fintable.io/api/v2/transactions/tx_01JB2M9QK4R7X3W8N5PDY6TF2H \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"category_id": "dining-out_aB3xY9k2Lm"}'
Задання категорії позначає транзакцію як змінену вручну
(category_manual_override: true) — правила більше ніколи її не торкнуться. Значення
"category_id": null знімає категорію і скасовує позначку ручної зміни, тож правила
можуть застосуватися знову під час наступного проходу. Відповідь — оновлена транзакція.
PATCH /transactions/bulk
Застосовує один category_id (або null) до багатьох транзакцій одразу. Виберіть цілі
рівно одним із двох селекторів:
ids[]— до 10 000 ідентифікаторів (чужі ідентифікатори тихо пропускаються), абоfilters— ті самі ключі, що й в ендпоїнті списку. Щоб через одну одруківку не перекатегоризувати всю вашу історію, фільтр має містити принаймні один звужувальний ключ —date_from,date_to,account_ids,category_ids,qабоdescription(pendingіamount_*можуть уточнювати, але самі по собі не рахуються). Якщо під фільтр підпадає понад 10 000 транзакцій, запит завершується помилкою 422 — звузьте та повторіть.
Не впевнені, що зачепить фільтр? Спершу виконайте пробний запуск:
curl -X PATCH https://fintable.io/api/v2/transactions/bulk \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filters": {"q": "whole foods", "date_from": "2026-01-01"},
"category_id": "groceries_x7Pq2Rv9Zn",
"dry_run": true
}'
{
"data": {
"dry_run": true,
"matched_count": 37,
"sample": [
"... up to 10 matching transactions ..."
]
}
}
Результат влаштовує? Надішліть той самий запит без dry_run:
{
"data": {
"dry_run": false,
"updated_count": 37
}
}
Виконання оновлює всі знайдені рядки й синхронізує категорії з вашими таблицями один раз, як єдиний експорт.
Синхронізація
| Endpoint | Що робить |
|---|---|
GET /sync |
Розклад, поточні синхронізації та статус кожного підключення |
POST /sync |
Синхронізувати всі підключення зараз |
POST /sync/{connection_id} |
Синхронізувати одне підключення зараз |
Синхронізація — це один запуск завантаження свіжих даних із банківського підключення до Fintable. Fintable планує їх автоматично: кожен рахунок бере участь у рандомізованому проході, який виконується кожні 6–23 години, тож точного «часу наступної синхронізації» навмисно не існує. API дозволяє переглянути розклад, спостерігати за поточними синхронізаціями та (на платних планах) запустити синхронізацію на вимогу.
Повторюваною структурою тут є об'єкт Стан синхронізації — він з'являється в кожному
Підключенні і по всьому GET /sync:
{
"state": "finished",
"progress_now": 4,
"progress_max": 4,
"stage": "Sync complete",
"started_at": "2026-07-26T09:11:58Z",
"finished_at": "2026-07-26T09:12:44Z"
}
| Поле | Тип | Значення |
|---|---|---|
state |
string | queued, executing, finished, failed або retrying |
progress_now |
integer | null | Скільки кроків виконано |
progress_max |
integer | null | Загальна кількість кроків у цьому запуску |
stage |
string | null | Зрозумілий опис поточного етапу |
started_at |
string | null | Коли запуск почався |
finished_at |
string | null | Коли запуск завершився; null, поки він триває |
GET /sync
Обгортає об'єкти Стану синхронізації в повну картину — ваш розклад плюс статус кожного підключення:
| Поле | Тип | Значення |
|---|---|---|
schedule.type |
string | default (рандомізований прохід) або custom (є розклади для конкретних провайдерів) |
schedule.last_sync_at |
string | null | Коли прохід востаннє запускав ваші синхронізації |
schedule.next_sync_window |
object | null | Приблизне вікно {earliest, latest} наступного проходу — точного часу не існує |
schedule.custom_schedules |
array | Розклади для конкретних провайдерів: {provider, cron, timezone, next_run_at} |
schedule.default_sweep_applies |
boolean | Типовий прохід застосовується до всіх рахунків, незалежно від власних розкладів |
active_syncs |
array | Завдання, що виконуються (або зависли чи впали): {connection_id, sync_status} |
connections |
array | Найновіший {connection_id, sync_status} кожного підключення |
curl https://fintable.io/api/v2/sync \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": {
"schedule": {
"type": "default",
"last_sync_at": "2026-07-26T09:11:55Z",
"next_sync_window": {
"earliest": "2026-07-26T15:23:00Z",
"latest": "2026-07-27T09:11:55Z"
},
"custom_schedules": [],
"default_sweep_applies": true
},
"active_syncs": [],
"connections": [
{
"connection_id": "conn_plaid_1771845993762884095",
"sync_status": {
"state": "finished",
"progress_now": 4,
"progress_max": 4,
"stage": "Sync complete",
"started_at": "2026-07-26T09:11:58Z",
"finished_at": "2026-07-26T09:12:44Z"
}
}
]
}
}
POST /sync
Це API-версія кнопки «Синхронізувати всі підключення» в панелі. Вона завантажує закешовані дані провайдера — це не оновлення з банку в реальному часі:
{
"data": [
{
"connection_id": "conn_plaid_1771845993762884095",
"status": "started"
},
{
"connection_id": "conn_nordigen_1802214467911184310",
"status": "already_syncing"
}
]
}
Синхронізація, яка вже виконується, повідомляється як already_syncing, а не як
помилка. Потрібна активна підписка або пробний період — безкоштовні акаунти
отримують 403 ще до початку. Стежте за прогресом через GET /sync або за
полем sync_status кожного підключення.
POST /sync/{connection_id}
Синхронізує лише одне підключення — та сама структура відповіді, що й у
POST /sync (один елемент), і та сама вимога до плану.
Категорія
| Endpoint | Що робить |
|---|---|
GET /categorizer/categories |
Список категорій |
GET /categorizer/categories/{id} |
Одна категорія |
POST /categorizer/categories |
Створити категорію (201) |
PATCH /categorizer/categories/{id} |
Перейменувати, змінити групу, змінити колір |
DELETE /categorizer/categories/{id} |
Видалити категорію |
Категорія — це мітка для транзакцій, базовий елемент категоризатора, за допомогою якого транзакції отримують мітки: категорії — це самі мітки, а Правила застосовують їх автоматично в міру надходження транзакцій. Усе, що можна зробити в панелі категоризатора, можна зробити й тут. Ліміт: 1 000 категорій на акаунт.
{
"data": {
"id": "groceries_x7Pq2Rv9Zn",
"name": "Groceries",
"header": "Expenses",
"color": "green",
"created_at": "2026-07-26T14:02:33Z",
"updated_at": "2026-07-26T14:02:33Z"
}
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор категорії, {name-slug}_{10 літер і цифр} — не змінюється при перейменуванні |
name |
string | Мітка, що відображається на транзакціях і у ваших таблицях |
header |
string | Група, під якою показується категорія, як-от Expenses чи Income |
color |
string | Назва з палітри панелі: red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose |
created_at / updated_at |
string | Мітки часу ISO-8601 |
GET /categorizer/categories
Повертає список усіх ваших категорій.
GET /categorizer/categories/{id}
Одна категорія за ідентифікатором.
POST /categorizer/categories
Створює категорію (201) — name, header і необов'язковий color:
curl -X POST https://fintable.io/api/v2/categorizer/categories \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Groceries", "header": "Expenses", "color": "green"}'
Відповідь — створена категорія (як вище).
PATCH /categorizer/categories/{id}
Оновлює name, header та/або color. Перейменування автоматично поширюються на ваші
Airtable і Google Sheets.
DELETE /categorizer/categories/{id}
Видалення захищене: якщо якесь правило досі посилається на категорію, запит завершується помилкою 409 зі списком ідентифікаторів проблемних правил — спершу оновіть або видаліть ці правила. В іншому разі всі транзакції в категорії залишаються без категорії, а сама категорія видаляється:
{
"data": {
"deleted": true,
"uncategorized_count": 118
}
}
Правило
| Endpoint | Що робить |
|---|---|
GET /categorizer/rules |
Список правил — лише метадані, без logic |
GET /categorizer/rules/{id} |
Одне правило разом із повною logic |
POST /categorizer/rules |
Створити правило (202) |
PATCH /categorizer/rules/{id} |
Оновити name, priority та/або logic |
DELETE /categorizer/rules/{id} |
Видалити правило |
POST /categorizer/sync |
Поставити в чергу повний прохід правил + експорт у таблиці (202) |
GET /categorizer/status |
На якому етапі конвеєр |
Правило категоризує транзакції автоматично в міру їх синхронізації — це друга половина категоризатора. Ліміт: 1 000 правил на акаунт.
{
"data": {
"id": "a25a374d-e4d7-4652-aca7-5dd3c3d02d15",
"name": "Big grocery runs",
"type": "advanced",
"priority": 7,
"category_ids": [
"groceries_x7Pq2Rv9Zn"
],
"logic": {
"if": [
"..."
]
},
"created_at": "2026-07-26T14:10:05Z",
"updated_at": "2026-07-26T14:10:05Z"
}
}
| Поле | Тип | Значення |
|---|---|---|
id |
string | Ідентифікатор правила — UUID |
name |
string | Видима назва (для простих правил генерується автоматично) |
type |
string | simple (опис містить текст) або advanced (сирий JSONLogic) |
priority |
integer | Правила виконуються в порядку (priority, id); коли збігається кілька, перемагає правило з вищим пріоритетом |
category_ids |
array of strings | Категорії, які можуть призначати гілки цього правила |
logic |
object | Повний JSONLogic — присутній у GET /categorizer/rules/{id} та у відповідях на створення/оновлення, у списку пропускається |
created_at / updated_at |
string | Мітки часу ISO-8601 |
Як поводяться правила — варто прочитати один раз:
- Правила виконуються в порядку (priority, id). Коли кілька правил збігаються з
однією транзакцією, перемагає правило з вищим пріоритетом (воно застосовується
останнім).
priorityможна змінити через PATCH. - Транзакції, категоризовані вручну (
category_manual_override: true), правила ніколи не чіпають. - Прохід правил зберігає старі категоризації. Він перезаписує лише ті транзакції, які підпадають під поточний набір правил — видалення чи зміна правила не знімає категорії з транзакцій, які раніше під нього підпадали. Це відповідає поведінці панелі й зроблено навмисно. Щоб справді все скинути, зніміть категорії масово й запустіть прохід заново.
GET /categorizer/rules
Повертає список усіх ваших правил — лише метадані (id, name, type, priority,
category_ids[]), без logic.
GET /categorizer/rules/{id}
Одне правило за ідентифікатором, разом із повною logic.
POST /categorizer/rules
Є два види. Прості правила покривають типовий випадок — «якщо опис містить X, віднеси до Y» (без урахування регістру, 3–128 символів):
curl -X POST https://fintable.io/api/v2/categorizer/rules \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "simple", "text": "STARBUCKS", "category_id": "dining-out_aB3xY9k2Lm"}'
Складні правила — це сирий JSONLogic: довільні умови щодо
суми, дат, рахунку, опису й навіть сирих полів провайдера (див.
довідник JSONLogic нижче). Зверніть увагу:
logic — це рядок, закодований у JSON, а не вкладений об'єкт:
curl -X POST https://fintable.io/api/v2/categorizer/rules \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "advanced",
"name": "Big grocery runs",
"logic": "{\"if\": [{\"and\": [{\"in\": [\"WHOLE FOODS\", {\"var\": \"transaction.description\"}]}, {\"<\": [{\"var\": \"transaction.amount\"}, -100]}]}, \"groceries_x7Pq2Rv9Zn\", null]}"
}'
Створення або оновлення правила повертає 202 з об'єктом правила (як вище) плюс поле
верхнього рівня "application": "queued". Цей код 202 повідомляє щось важливе: правило
збережено, і в чергу поставлено повний упорядкований прохід усіх ваших правил по
всіх ваших транзакціях разом із об'єднаним експортом у ваші таблиці. Опитуйте
GET /categorizer/status, щоб побачити завершення. Багато
швидких змін дають один прохід і один експорт, а не по одному на кожну зміну.
PATCH /categorizer/rules/{id}
Оновлює name, priority та/або logic. Зміни поведінки (логіки чи пріоритету)
повертають 202 і ставлять у чергу прохід правил, так само як створення; просте
перейменування повертає 200 із "application": "none".
DELETE /categorizer/rules/{id}
Видаляє правило. Транзакції, які воно раніше категоризувало, зберігають свої категорії (див. примітки щодо поведінки вище).
Написання складних правил у JSONLogic
logic має бути JSON-об'єктом, єдиний оператор верхнього рівня якого — if. Кожна
гілка результату має бути літеральним рядком з ідентифікатором категорії або
літеральним null — ніколи не обчислюваним виразом. Ваша логіка обчислюється щодо
такого входу для кожної транзакції:
{
"transaction": {
"fin_id": "tx_01JB2M9QK4R7X3W8N5PDY6TF2H",
"ext_id": "plaid-tx-4821bd0e",
"account_id": "acc_01J9V5R9WQD3M8Y2KXN4T7PB6C",
"date": "2026-07-24",
"auth_date": "2026-07-23",
"amount": "-4.50",
"currency": "USD",
"description": "BLUE BOTTLE COFFEE",
"payee": "Blue Bottle Coffee",
"sub_account": null,
"acc_name": "Chase Total Checking",
"raw": {
"provider fields": "..."
}
}
}
Дві зручності, які варто помітити: description уже переведено у верхній регістр (тож
пошук підрядка фактично не залежить від регістру), а amount — звичний десятковий
рядок.
Розібраний приклад — «карткові транзакції понад 100 $ у Whole Foods належать до
Groceries» (пам'ятайте: від'ємне = кошти на вихід, тож витрачено понад 100 $ означає
< -100):
{
"if": [
{
"and": [
{
"in": [
"WHOLE FOODS",
{
"var": "transaction.description"
}
]
},
{
"<": [
{
"var": "transaction.amount"
},
-100
]
}
]
},
"groceries_x7Pq2Rv9Zn",
null
]
}
Дозволені оператори: var, missing, missing_some, if, ==, ===, !=, !==,
!, !!, or, and, >, >=, <, <=, max, min, +, -, *, /, %,
map, reduce, filter, all, none, some, merge, in, cat, substr.
(log не дозволено.)
Ліміти на одне правило: 16 КБ, глибина вкладеності 20 і бюджет складності у 100 вузлів
операторів — операції над масивами (map, filter, reduce, all, none, some)
рахуються з коефіцієнтом 10× і не можуть вкладатися одна в одну. Є також сукупний бюджет
для всіх ваших правил; якщо ви його вичерпали, спростіть або видаліть частину правил.
POST /categorizer/sync
Ставить у чергу повний прохід правил плюс експорт у таблиці (202,
{"data": {"application": "queued"}}). Зміни правил ставлять проходи в чергу
автоматично, тож це рідко потрібно — воно існує для випадку «просто перезапусти все
зараз».
GET /categorizer/status
Чесна картина конвеєра:
curl https://fintable.io/api/v2/categorizer/status \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": {
"requested_version": 12,
"completed_version": 12,
"active_version": null,
"settled": true,
"failed_at": null,
"destinations": [
{
"destination": "airtable",
"requested_version": 12,
"completed_version": 12,
"failed_at": null
},
{
"destination": "gsheet:184",
"requested_version": 12,
"completed_version": 12,
"failed_at": null
}
]
}
}
Кожна запитана зміна збільшує requested_version; проходи та експорти його наздоганяють.
active_version — це прохід, який виконується просто зараз; null, коли нічого не
виконується.
settled: true означає, що все, про що ви просили, повністю завершилося — і в базі
даних, і в кожному призначенні-таблиці. Щоб дочекатися, поки зміна правила набуде
чинності, опитуйте статус, доки settled не стане true.
Інтеграція
| Endpoint | Що робить |
|---|---|
GET /integrations |
Стан і справність ваших інтеграцій із таблицями |
Інтеграція — це призначення, у яке Fintable синхронізує дані: ваша база Airtable або
ваші таблиці Google Sheets. Це міст між цим API і світом таблиць: візьміть тут base_id
чи spreadsheet_id, а далі працюйте безпосередньо з власними API Airtable чи Google над
синхронізованими даними.
GET /integrations
curl https://fintable.io/api/v2/integrations \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": {
"airtable": {
"base_id": "appXk2fW9qLmN3vT8",
"url": "https://airtable.com/appXk2fW9qLmN3vT8",
"accounts_table_name": "Accounts",
"transactions_table_name": "Transactions",
"holdings_table_name": "Holdings",
"transactions_enabled": true,
"token_type": "OAUTH",
"healthy": true,
"error": null
},
"google_sheets": [
{
"spreadsheet_id": "1vQx8mP2kL9nR4tY7wZ3jB6cD5eF8gH0iJ2kL4mN6oP8",
"url": "https://docs.google.com/spreadsheets/d/1vQx8mP2kL9nR4tY7wZ3jB6cD5eF8gH0iJ2kL4mN6oP8",
"title": "Family finances",
"tabs": {
"accounts": {
"sheet": "Accounts",
"range": "A1:Z"
},
"transactions": {
"sheet": "Transactions",
"range": "A1:Z"
},
"holdings": {
"sheet": null,
"range": null
}
},
"healthy": true,
"error": null
}
]
}
}
Об'єкт airtable (null, якщо ви не підключали Airtable):
| Поле | Тип | Значення |
|---|---|---|
base_id |
string | База Airtable, у яку синхронізує Fintable — використовуйте її з власним API Airtable |
url |
string | Пряме посилання на базу |
accounts_table_name |
string | Налаштована таблиця для рахунків |
transactions_table_name |
string | Налаштована таблиця для транзакцій |
holdings_table_name |
string | null | Налаштована таблиця для активів, коли її ввімкнено |
transactions_enabled |
boolean | Чи ввімкнено синхронізацію транзакцій у цю базу |
token_type |
string | OAUTH, PERSONAL або DEPRECATED |
healthy |
boolean | Чи пройшла остання перевірка |
error |
string | null | Що саме не так, коли healthy дорівнює false |
Кожен запис у google_sheets[]:
| Поле | Тип | Значення |
|---|---|---|
spreadsheet_id |
string | Таблиця, у яку синхронізує Fintable — використовуйте її з власним API Google |
url |
string | Пряме посилання на таблицю |
title |
string | Назва таблиці |
tabs |
object | Налаштовані вкладки accounts / transactions / holdings, кожна у форматі {sheet, range} (null, якщо не налаштовано) |
healthy |
boolean | Чи пройшла остання перевірка |
error |
string | null | Що саме не так, коли healthy дорівнює false |
Стан справності надається з кешу перевірок — перший виклик після періоду простою може зайняти кілька секунд, поки виконується перевірка наживо. Налаштуйте інтеграції в розділі Панель → Інтеграції.
Установа
| Endpoint | Що робить |
|---|---|
GET /institutions |
Пошук у каталозі (публічний, з пагінацією за зсувом) |
Установа — це банк або брокер, до якого Fintable може підключитися: запис у каталозі з
можливістю пошуку, що налічує близько 50 000 установ. Каталог публічний — без
автентифікації — тож ви можете використовувати його у потоках реєстрації чи для
перевірки доступності. Його значення slug використовуються в
POST /connections/link.
{
"data": [
{
"slug": "12913262_chase",
"name": "Chase",
"domain": "chase.com",
"supported": true,
"countries": [
"US"
],
"coverage_url": "https://fintable.io/coverage/us/12913262_chase",
"updated_at": "2026-07-19T02:11:36Z"
}
],
"meta": {
"page": 1,
"has_more": true
}
}
| Поле | Тип | Значення |
|---|---|---|
slug |
string | Ідентифікатор установи — передавайте його в POST /connections/link |
name |
string | Видима назва |
domain |
string | null | Домен вебсайту установи |
supported |
boolean | Чи може Fintable підключитися до неї просто зараз |
countries |
array of strings | Коди країн ISO, у яких вона працює |
coverage_url |
string | null | Публічна сторінка покриття; null, якщо її немає |
updated_at |
string | null | Коли запис каталогу востаннє змінювався |
GET /institutions
Параметри запиту:
| Параметр | Значення |
|---|---|
q |
Нечіткий пошук за назвою, мінімум 3 символи |
domain |
Збіг за доменом вебсайту |
country |
Код країни ISO, напр. US |
provider |
PLAID, NORDIGEN, AKOYA, FINICITY, MERCURY, SNAPTRADE (GoCardless внутрішньо позначається як NORDIGEN) |
page |
Номер сторінки — завжди 10 результатів на сторінку |
curl "https://fintable.io/api/v2/institutions?q=chase&country=US"
Це єдиний ендпоїнт API з пагінацією за зсувом — гортайте за допомогою page, доки
has_more не стане false.
Документація та посібник як дані
| Endpoint | Що повертає |
|---|---|
GET /guide |
Повний посібник користувача Fintable у форматі markdown |
GET /docs |
Цей документ у форматі markdown |
GET /openapi.json |
Опис цього API у форматі OpenAPI 3.1 |
Сама документація доступна у вигляді звичайного markdown — зручно, щоб передати її LLM або відрендерити у власних інструментах. Усе публічне, без автентифікації.
GET /guide
Повний посібник користувача Fintable у форматі markdown. ?locale=main|uk|es вибирає
мову.
GET /docs
Цей документ у форматі markdown. ?locale=main|uk|es вибирає мову.
GET /openapi.json
Опис цього API у форматі OpenAPI 3.1 — спрямуйте на нього Swagger UI, Postman чи генератор коду.
Домовленості API
Кілька домовленостей діють усюди, тож вивчити їх достатньо один раз.
Конверт відповіді
Списки повертають {"data": [...]}, а окремі об'єкти — {"data": {...}}. Списки
транзакцій додатково містять next_cursor (див. Пагінація). Єдиний
виняток: публічний каталог установ використовує пагінацію за зсувом і поле
meta: {page, has_more}.
Запити мають надсилати Accept: application/json.
Гроші — це рядок
Суми — це точні десяткові рядки ("-4.50", "1234.56"), а не числа з рухомою
комою, тож ви ніколи не втратите копійку через округлення. Від'ємні суми — це кошти на
вихід. Кожна сума супроводжується окремим полем currency (діюча валюта з урахуванням
будь-якого заданого вами перевизначення). Баланси рахунків дотримуються тієї самої
домовленості.
Мітки часу та дати
Мітки часу подано в ISO-8601 UTC, як-от 2026-07-26T15:04:05Z. Поля транзакцій date
та auth_date — це звичайні рядки YYYY-MM-DD.
Ідентифікатори об'єктів непрозорі
Ідентифікатори — це непрозорі рядки довжиною до 64 символів. Зберігайте їх як є й не намагайтеся видобути з них зміст: наведені нижче форми потрібні для впізнавання, а не для розбору.
| Об'єкт | Який має вигляд |
|---|---|
| Транзакція | tx_01J0AB... (у давніх акаунтів можуть бути успадковані числові рядки на кшталт "48214321") |
| Рахунок | acc_01J0AB... (тут теж трапляються успадковані числові рядки) |
| Актив | hol_01J0AB... або успадкований числовий рядок |
| Категорія | {name-slug}_{10 літер і цифр}, напр. dining-out_aB3xY9k2Lm |
| Правило | UUID, напр. a25a374d-e4d7-4652-aca7-5dd3c3d02d15 |
| Підключення | conn_{provider}_{number}, напр. conn_plaid_1771845993762884095 |
Помилки
Кожна відповідь, що не належить до 2xx, має рівно одну структуру, тож один обробник помилок покриває весь API:
{
"error": {
"type": "not_found",
"message": "No transaction with that id."
}
}
Помилки валідації (422) додатково містять повідомлення для кожного поля:
{
"error": {
"type": "validation_failed",
"message": "The given data was invalid.",
"errors": {
"sync_start_date": [
"Trial accounts can sync at most 30 days of history."
]
}
}
}
| HTTP | type |
Коли ви це побачите |
|---|---|---|
| 400 | bad_request / invalid_cursor |
Некоректний запит; або курсор, повторно використаний з іншим порядком сортування |
| 401 | unauthenticated |
Токен відсутній, прострочений або відкликаний |
| 403 | forbidden |
Токен дійсний, але дія не дозволена (напр. синхронізація на безкоштовному акаунті) |
| 404 | not_found |
Такого об'єкта немає — зокрема об'єкти, що належать іншому акаунту |
| 405 | method_not_allowed |
Неправильний HTTP-метод |
| 409 | conflict |
Дія конфліктує з поточним станом (напр. видалення категорії, яку ще використовують правила) |
| 413 | payload_too_large |
Тіло запиту перевищує ліміт |
| 422 | validation_failed |
Запит зрозумілий, але якесь поле некоректне |
| 429 | rate_limited |
Пригальмуйте — надходить із заголовком Retry-After |
| 500 | server_error |
Наша провина; спробуйте ще раз або зв'яжіться з нами |
| 503 | service_unavailable |
Тимчасовий збій або технічні роботи |
Ліміти частоти
Ліміти щедрі для ввічливих, коректно написаних клієнтів; ви натрапите на них, лише якщо
надто активно довбите якийсь ендпоїнт. Кожен маршрут має рівно один кошик, а виклики
MCP-інструментів витрачають ті самі кошики, що й їхні REST-відповідники. Коли ви
досягаєте ліміту, отримуєте 429 із заголовком Retry-After — дотримуйтеся його.
| Кошик | Ліміт |
|---|---|
| Автентифіковані читання | 300/хв на токен |
| Загальні записи (PATCH/DELETE, категорії) | 60/хв на акаунт |
| Створення/оновлення правил | 12/год на акаунт |
POST /sync (і для окремого підключення) |
Personal/Trial: 2/день · Office/Enterprise: 1/год |
POST /connections/link (і перепідключення) |
1/хв на акаунт |
PATCH /transactions/bulk |
10/год на акаунт |
POST /categorizer/sync |
6/день на акаунт |
Публічний GET /institutions |
60/хв на IP |
Публічні /guide, /docs, openapi.json |
60/хв на IP |
| MCP-ендпоїнт | 120/хв на токен |
POST /oauth/register |
5/год на IP |
Кешування
Автентифіковані відповіді завжди віддаються свіжими (Cache-Control: no-store).
Публічні ендпоїнти (/institutions, /guide, /docs) можна кешувати до однієї години.
Пагінація
Роки історії транзакцій можуть налічувати десятки тисяч рядків, тож
GET /transactions (і варіант для окремого рахунку) ніколи не повертає все одразу —
він використовує пагінацію з непрозорим курсором. Чому курсор, а не номери сторінок?
Бо ваші дані рухаються: синхронізація може додавати чи оновлювати транзакції, поки ви
гортаєте, і сторінки за зсувом мовчки пропускали б або дублювали рядки. Курсор фіксує
вашу точну позицію в послідовності, тож повний обхід бачить кожен рядок рівно один раз.
Запросіть сторінку — і якщо є ще, відповідь підкаже, звідки продовжити:
curl "https://fintable.io/api/v2/transactions?limit=100" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": [
"... 100 transactions ..."
],
"next_cursor": "eyJ2IjoxLCJvIjoiZGF0ZSIsazoi..."
}
Передайте курсор назад, щоб отримати наступну сторінку, і повторюйте, доки
next_cursor не стане null:
curl "https://fintable.io/api/v2/transactions?cursor=eyJ2IjoxLC..." \
-H "Authorization: Bearer YOUR_TOKEN"
Правила:
limitза замовчуванням дорівнює 100 і не може перевищувати 500.- Курсори непрозорі й прив'язані до свого порядку сортування. Курсор, створений у
списку з
order=date, відхиляється (400invalid_cursor), якщо його повторно використати зorder=updated, і навпаки. - Типовий порядок — від найновіших за датою транзакції.
Інкрементна синхронізація
Якщо ви дзеркалите транзакції у власну базу даних чи застосунок, повторне завантаження
всієї історії лише заради вчорашніх змін — повільно й марнотратно, та й ліміти частоти
не розраховані на це. Інкрементна синхронізація — ефективна альтернатива: кожна
транзакція має мітку updated_at, а ендпоїнт списку вміє сортувати за нею, тож ви
можете запросити рівно «усе, що змінилося відтоді, як я дивився востаннє».
Опитування змін
Опитуйте з ?order=updated&updated_since=<мітка часу ISO>. Результати повертаються
відсортованими за зростанням updated_at, з тією самою курсорною пагінацією, що й вище.
Рецепт:
- Викличте
GET /transactions?order=updated&updated_since=2026-07-25T00:00:00Z. - Пройдіть сторінки за допомогою
next_cursor, обробляючи кожну транзакцію. - Запам'ятайте найбільше значення
updated_at, яке ви обробили; використайте його як наступнеupdated_since.
Чесний дрібний шрифт: видалення
Видалення непомітні для інкрементного опитування — жодних «надгробків» чи журналу видалень не існує. Дві ситуації, які варто передбачити:
Ми працюємо над кращим рішенням, яке зробить видалення видимими. А поки наша найкраща
порада — не завантажувати очікувані транзакції: використовуйте pending=false,
коли переносите транзакції у власну базу даних чи застосунок.
- Плинність очікуваних транзакцій. Очікувані транзакції можуть бути замінені після проведення (новий ідентифікатор, скоригована сума чи дата). Якщо ви все ж їх імпортуєте, періодично перезавантажуйте вікно останніх 30 днів, щоб це вловити.
- Видалення цілих рахунків. Коли рахунок зникає з
GET /accountsабо переходить уenabled: false, відкиньте всі транзакції, які ви кешували для цього рахунку.
Якщо вам потрібна більша певність, періодично перезавантажуйте все повністю.
Запитання чи відгуки?
Якщо щось тут незрозуміле, чогось бракує або щось просто неправильне — ми хочемо про це знати: напишіть нам або скористайтеся бульбашкою підтримки на будь-якій сторінці. Якщо ви створюєте щось на основі API, ми залюбки допоможемо вам це запустити.