Nordlet

← Блог

Як інтегрувати хмарний API бухгалтерії в SaaS-платформу

Посібник практиків зі створення мультитенантного бухгалтерського інтеграційного рішення, яке переживе OAuth, вебхуки, податкові правила та звірку без пошкодження бухгалтерської книги.

Nordlet Team · · 13 хв читання

Більшість команд, які планують «додати бухгалтерію» до свого SaaS-продукту, починають з підключення HTTP-клієнта до кінцевої точки провайдера та надсилання інвойсу. Це працює в межах демо-версії. Але все ламається щоразу, коли клієнт підключає дві бухгалтерські організації, коли вебхук надходить двічі, або коли токен оновлення (refresh token) ротується та втрачається посеред запиту. Надійна версія цієї роботи — це не просто клієнт. Це шар інтеграції.

Цей шар має керувати підключеннями орендарів (tenants), зберіганням та ротацією токенів, специфічними для провайдера бухгалтерськими правилами, мапінгом записів, початковою та інкрементною синхронізацією, обробкою вебхуків із повторними спробами (retries) та дедуплікацією, лімітами запитів (rate limits), версійністю та журналом аудиту, який ваша служба підтримки зможе прочитати о 2 годині ночі. У цій статті ми розглянемо таку архітектуру та рішення, які мають найбільше значення.

Корисна ментальна модель:

SaaS-продукт → служба інтеграції з бухгалтерією → адаптер провайдера (або уніфікований API) → асинхронна синхронізація та звірка

Бухгалтерська система залишається джерелом достовірних даних для об'єктів головної книги: рахунків, податкових кодів, проведених транзакцій та бухгалтерських проведень. Ваша SaaS-платформа зберігає стабільні ідентифікатори між системами, стан синхронізації, метадані мапінгу та операційний журнал аудиту.

Що насправді охоплює термін „хмарний API бухгалтерії“ у цьому контексті

Ця фраза зазвичай означає API платформи для ведення обліку, що розміщується у хмарі, наприклад QuickBooks Online, Xero, Sage, Zoho Books або регіональну систему. Це також може означати уніфікований API бухгалтерії, який нормалізує кілька провайдерів за єдиним інтерфейсом.

Тут варто бути точним, оскільки реалізація відрізняється залежно від мети. Читання інвойсів для звітності — це не те саме, що створення інвойсів на основі SaaS-активності, проведення рахунків постачальників, синхронізація клієнтів і продуктів, створення бухгалтерських проведень або запуск повноцінної двосторонньої синхронізації. Вирішіть, що саме ви будуєте, перш ніж звертатися до будь-якого endpoint.

Для цієї статті важлива ще одна відмінність. Платіжний API переказує кошти. Банківський API витягує дані рахунків. API для інвойсування може створювати документи без розкриття головної книги. Вбудована бухгалтерська книга (embedded accounting ledger) — це зовсім інше: SaaS-компанія володіє самим бухгалтерським рушієм. Саме до такого підходу належить Nordlet. Замість того, щоб підключати ваш продукт до зовнішніх бухгалтерських книг клієнта, Nordlet надає платформам і маркетплейсам справжню систему подвійного запису, незмінний готовий до аудиту реєстр, обробку ПДВ в ЄС та виплати всередині власного продукту завдяки дизайну з пріоритетом API із типізованими SDK та вебхуками. Якщо ви є маркетплейсом і вирішуєте, чи інтегрувати бухгалтерську систему клієнта, чи вести бухгалтерію самостійно, це справжнє роздоріжжя, і ми ще повернемося до цього питання.

Мультитенантність: створюйте область видимості для кожного підключення двічі

У SaaS-продукті одна програма підключається до багатьох організацій-клієнтів. Кожне підключення повинно мати обмежену область видимості (scoped) як за SaaS-орендарем (tenant), так і за ідентифікатором організації провайдера, таким як ID орендаря Xero або realm ID в QuickBooks.

Не прив'язуйте підключення виключно до ідентифікатора користувача OAuth. Один користувач може авторизувати кілька бухгалтерських організацій, а одну організацію з часом можуть підключати заново різні користувачі. Якщо зробити це неправильно, зрештою ви надішлете інвойс одного клієнта в бухгалтерську книгу іншого, а це не та помилка, яку можна виправити непомітно.

Перше архітектурне рішення: прямий конектор, уніфікований API чи вбудована книга

Прямі інтеграції з провайдерами

Пряма інтеграція надає найбільший контроль: функції, специфічні для провайдера, кастомні поля, обробку помилок, частоту синхронізації, зберігання даних та структуру витрат. Ціна за це реальна. Кожен провайдер пропонує власний процес OAuth, схему даних, особливості, ліміти запитів, поведінку вебхуків, сертифікацію та подальше обслуговування.

Уніфіковані API бухгалтерії

Уніфікований API пропонує єдиний інтерфейс для кількох бухгалтерських систем, нормалізуючи такі сутності, як клієнти, інвойси, постачальники, рахунки, платежі та продукти. Це може скоротити час початкової розробки. Проте це не усуває складність інтеграції, і вважати інакше — поширена помилка.

Перш ніж братися за роботу, запитайте: які провайдери та операції підтримуються? Чи працює запис даних, чи лише читання? Чи є записи синхронними, чи надсилаються в чергу? Чи доступні специфічні для провайдера поля через passthrough? Чи кешуються дані і наскільки вони свіжі? Хто займається збоями у провайдера та змінами в API? Як формується ціноутворення: за виклик, за зв'язаний акаунт, за запис чи як плата за платформу? Чи можете ви експортувати свої правила мапінгу та безпечно розірвати зв'язок? Термін „уніфікований“ рідко означає „ідентичний за функціоналом для всіх провайдерів“.

Вбудована бухгалтерська книга

Якщо головна проблема вашої платформи полягає у веденні бухгалтерії для ваших користувачів, а не у відтворенні її в їхніх існуючих книгах, вбудована книга змінює підхід. Маркетплейсу з тисячами продавців або SaaS-продукту, якому потрібні вбудовані правила ПДВ ЄС, готові до аудиту, та компайнс для кожної країни, вигідніше володіти бухгалтерським рушієм, ніж підключати N зовнішніх конекторів. Це позиціювання Nordlet: справжні книги через API, незмінний подвійний запис, ПДВ для кожної країни з перевіркою VIES та генерацією реєстру i.SAF, експорт SEPA та звітів в XLSX, PDF або JSON всередині вашого продукту, а не через сторонній сервіс оформлення замовлень.

Правило прийняття рішень, яким я користуюся:

Ситуація Найкращий вибір
Один бухгалтерський провайдер домінує у вашій клієнтській базі; специфічна поведінка провайдера є ключовою Прямий конектор
Широке покриття провайдерів та швидкість виходу на ринок важливіші за контроль Уніфікований API
Ви є платформою або маркетплейсом, яким потрібно самостійно вести бухгалтерію, з ПДВ ЄС та журналами аудиту Вбудована книга (Nordlet)
Змішані умови Гібридний варіант: уніфікований для типових потоків, прямі конектори для стратегічних провайдерів

Рекомендована архітектура інтеграції

Ізолюйте інтеграцію від основної бізнес-логіки

Не розкидайте виклики провайдера по модулях білінгу, замовлень, підписок та звітності. Створіть виділену службу інтеграції, яка міститиме адаптери провайдерів, управління OAuth-підключеннями, канонічні моделі, мапінг ідентифікаторів, завдання та черги синхронізації, кінцеві точки вебхуків, обробку повторних спроб і черги невдалих повідомлень (dead-letter), журнали аудиту та інструменти звірки. Це запобігає витоку назв полів Xero або QuickBooks у вашу доменну модель.

Визначте вузьку канонічну модель

Моделюйте лише ті робочі процеси, які ви підтримуєте. Типові об'єкти: клієнт, товар або послуга, інвойс, рядок інвойсу, платіж, кредит-нота, постачальник, рахунок, податкова ставка, валюта, бухгалтерське проведення.

Зберігайте відмінності, які впливають на облік. Не зводьте до спільного знаменника чорне і біле: чернетки порівняно із затвердженими та проведеними документами, суми з ПДВ та без ПДВ, кредит-ноти проти від'ємних інвойсів, прив'язку платежу до факту його існування, або ж номер інвойсу для клієнта порівняно з ідентифікатором об'єкта у провайдера. Кожен запис повинен містити SaaS ID, ID провайдера, назву провайдера та версію API, індикатор джерела достовірних даних, статус, часові мітки, час останньої синхронізації, зовнішнє посилання та статус помилки чи звірки.

Підтримуйте чіткі таблиці мапінгу

Зіставляйте SaaS-орендаря з бухгалтерською організацією, SaaS-клієнта з контактом провайдера, SaaS-продукт з товаром або рахунком провайдера, SaaS-інвойс з інвойсом провайдера, SaaS-платіж з платежем провайдера, податкову категорію з податковим кодом, а категорію доходу — з рахунком головної книги.

Ніколи не використовуйте імена або електронні адреси як постійні ідентифікатори. Імена змінюються, існують дублікати, а два клієнти можуть користуватися однією електронною поштою. Зберігайте незмінний ID провайдера та початковий SaaS ID.

Додайте статеві машини (state machines)

Надайте підключенню чіткі стани: не підключено, очікування авторизації, підключено, очікування початкової синхронізації, синхронізація, працездатний, перевищено ліміт запитів, потрібна повторна авторизація, провайдер недоступний, відключено, остаточний збій. Записи повинні мати власні стани: очікування, надіслано, підтверджено, помилка з можливістю повтору, помилка (потребує дій користувача), звірено, виявлено конфлікт. Бінарний прапорець „підключено / не підключено“ нічого корисного вашій службі підтримки не скаже.

OAuth та підключення користувачів

Використовуйте потік із використанням коду авторизації (authorization code flow). Клієнт натискає кнопку „Підключити“, ваш сервер створює короткострокову транзакцію авторизації, клієнт проходить аутентифікацію у провайдера та надає дозволи (scopes), ви обмінюєте код на токени, визначаєте авторизовану організацію, зберігаєте підключення для правильного орендаря та ставите в чергу початкову синхронізацію.

Ретельно перевіряйте зворотний виклик (callback): параметр state проти транзакції на сервері, точну URI перенаправлення, видавця провайдера та контекст орендаря. Стандарт RFC 9700, Найкращі поточні практики безпеки OAuth 2.0, формалізує поточні рекомендації: використовуйте PKCE для потоків з кодом авторизації, уникайте неявних (implicit) грантів і грантів з паролем, а також використовуйте точну відповідність URI перенаправлення.

Запитуйте мінімально необхідні права доступу (least-privilege scopes). Використовуйте режим лише для читання там, де вам не потрібно виконувати запис. Моделі прав доступу змінюються, тому не копіюйте застарілі приклади. Документація Xero щодо OAuth зазначає, що широкі бухгалтерські дозволи замінюються на деталізовані: для нових додатків деталізовані дозволи призначаються з березня 2026 року, тоді як широкі дозволи залишатимуться доступними до вересня 2027 року.

Зберігайте токени лише на сервері. Ніколи не передавайте їх у браузерний JavaScript, мобільні клієнти, логи інтерфейсу, системи аналітики чи повідомлення про помилки для клієнтів. Шифруйте їх у стані покою, видаляйте з логів та зберігайте метадані для кожного підключення: зашифровані токени доступу та оновлення, термін дії, ID організації провайдера, надані дозволи, час видачі, час останнього успішного оновлення, статус відкликання.

Ротація токенів оновлення — це місце, де ламається продакшен

Відповідь на запит оновлення може повернути новий токен оновлення. Ви повинні зберегти нове значення атомарно, інакше ви заблокуєте доступ клієнту. Згідно з питаннями та відповідями розробників Xero, кожне оновлення створює новий токен оновлення, токени оновлення діють до 60 днів, а також існує 30-хвилинний пільговий період для повторної спроби з наявним токеном, якщо відповідь було втрачено. QuickBooks Online радить розробникам зберігати останній токен оновлення з найсвіжішої відповіді: токени оновлення діють до 100 днів, а їхнє значення може ротуватися кожні 24 години.

На практиці: використовуйте блокування оновлення для кожного підключення, замінюйте токен оновлення атомарно, обробляйте тимчасові збої кінцевої точки токенів за допомогою повторних спроб, відображайте зрозумілий стан повторної авторизації і ніколи не оновлюйте токен на кожний виклик API, доки діє наявний токен доступу.

Початкова синхронізація

Виконуйте початкову синхронізацію як фоновий процес. Не блокуйте нею зворотний виклик OAuth або інтерфейс користувача.

Надійна послідовність: отримати метадані організації, витягти рахунки, податкові ставки, валюти, контакти та товари, зберегти ID провайдера та правила мапінгу, імпортувати лише той історичний період, який потрібен продукту, поставити залежні записи в чергу в порядку їхньої залежності, записати контрольну точку (checkpoint) і позначити підключення працездатним лише після перевірки.

Порядок залежностей має значення. Для створення інвойсу спочатку можуть знадобитися контакт, товар, рахунок доходів, податковий код та валюта. Не створюйте дублікати наосліп. Здійснюйте пошук відповідностей за збереженим зовнішнім ID, наданим клієнтом посиланням, визначеним правилом зіставлення або чітким кроком вибору користувача для неоднозначних випадків.

Інкрементна синхронізація

Сприймайте вебхуки як сигнали, а не авторитетні записи

Вебхук зазвичай означає, що щось змінилося. Перевірте підпис, запишіть сиру подію, швидко поверніть обов'язкову успішну відповідь, виконайте дедуплікацію, поставте в чергу додатковий запит, отримайте поточний об'єкт від провайдера, застосуйте оновлення транзакційно, оновіть контрольну точку та спрямуйте помилки на повторну спробу або звірку. Це дозволяє обробляти неповні корисні дані (payloads) та події, що надходять не за порядком.

Правила провайдерів відрізняються, тому не варто обіцяти єдину універсальну поведінку. Вебхуки Xero містять підпис HMAC-SHA256 у заголовку x-xero-signature, вимагають HTTPS, повторюють спроби з поступовим зменшенням частоти до 24 годин, можуть бути вимкнені після повторних збоїв та можуть зберігати події до 31 дня для повторного відтворення після відновлення. QuickBooks Online виконує перевірку за допомогою HMAC-SHA256 та токена перевірки, очікує відповіді HTTP 200 протягом трьох секунд і повторює спроби за фіксованим графіком, який зрештою переходить на інтервали в шість годин, причому Intuit рекомендує асинхронну обробку.

Дедуплікація та ідемпотентність

Доставка принаймні один раз (at-least-once delivery) є стандартною ситуацією. Очікуйте на дублювання вебхуків, повторні спроби після тайм-ауту, коли запис насправді був успішним, зміну порядку подій та повторні кліки користувача. Використовуйте ідентифікатор події провайдера, якщо він доступний, унікальний ключ події в надійному сховищі, ідентифікатор операції, згенерований перед кожним записом, обмеження унікальності бази даних, семантику upsert та запит звірки після неоднозначних тайм-аутів.

Не припускайте, що кожен API бухгалтерії пропонує вбудовані ключі ідемпотентності. Якщо провайдер цього не робить, зберігайте внутрішній ключ операції та перевіряйте, чи існує вже очікуваний віддалений об'єкт перед повторною спробою. Шаблони з ідемпотентних запитів Stripe та загальні рекомендації щодо ідемпотентності вебхуків добре підходять для цього.

Опитування (polling) та виявлення змін

Поєднуйте вебхуки з періодичним опитуванням. Вебхуки можуть вимикатися, затримуватися, губитися через неправильну конфігурацію або обмежуватися певними об'єктами. Xero підтримує заголовок If-Modified-Since для отримання змін після мітки часу UTC, але в його документації попереджається, що не кожна зміна оновлює поле UpdatedDateUTC, тому деякі частково оплачені транзакції та поля контактів не з'являться за таким фільтром. Функція відстеження змін Change Data Capture у QuickBooks Online відстежує зміни за останні 30 днів, обмежує відповіді 1 000 об'єктів, повертає видалені сутності зі статусом Deleted і найкраще працює з короткими вікнами опитування.

Зберігайте контрольну точку для кожного провайдера та орендаря й використовуйте вікна перекриття. Запитуйте зміни з моменту трохи раніше останньої контрольної точки, а потім виконуйте дедуплікацію за ID провайдера та версією модифікації. Це захищає від розсинхронізації годинника та часткових збоїв.

Бухгалтерська цілісність даних

Це саме той аспект, який відрізняє робочу інтеграцію від надійної.

Податкова поведінка не є взаємозамінною. У документації Xero зазначається, що інвойси, кредит-ноти та замовлення на купівлю за замовчуванням не містять податку (tax-exclusive), якщо поле LineAmountTypes не встановлено, квитанції та банківські транзакції за замовчуванням містять податок (tax-inclusive), а ручні журнали не містять податку. Використовуйте поле TaxType, а не назву податкової ставки. Ніколи не припускайте, що „ПДВ 20%“ однозначно ідентифікує податковий код; він може відрізнятися залежно від країни, типу транзакції, дати набуття чинності та налаштувань організації. Саме тут багатопартісний ПДВ в ЄС стає дорогим у реалізації власними силами, і саме тут вбудована книга з вбудованим комплаєнсом для кожної країни повністю виправдовує себе.

Використовуйте арифметику з фіксованою комою або десяткові числа для грошових сум, ніколи не використовуйте двійкову плаваючу точку (binary floating point). Зберігайте код і точність валюти, суму за одиницю, кількість, знижку, суму податку, нетто, брутто та курс обміну. Чітко вирішіть, чи надсилаєте ви суми на рівні рядків, дозволяючи провайдеру обчислювати підсумки, чи надсилаєте заздалегідь обчислений підсумок. Змішування цих двох підходів створює розбіжності в округленні, які ваш бухгалтер обов'язково знайде.

Звертайтеся до рахунків головної книги за ID провайдера або кодом, а не за назвою для відображення. Перед записом переконайтеся, що рахунки, податкові коди, клієнти, товари та валюта є активними й підтримуються. Невдалий запис інвойсу зазвичай є проблемою мапінгу або конфігурації, а не тимчасовою помилкою API, тому інтерфейс користувача повинен пояснювати спосіб виправлення, а не показувати повідомлення „не вдалося синхронізувати“.

Не вважайте об'єкти еквивалентними. „Платіж“ може означати квитанцію, розподіл, депозит, банківську транзакцію або бухгалтерське проведення. SaaS-\„підписка“ може не чітко відповідати бухгалтерському „інвойсу“. Визначте бухгалтерську подію, яку ви хочете відобразити, перш ніж обирати об'єкт API. Перегляньте документацію Xero щодо платежів, щоб зрозуміти, як один провайдер моделює це.

Ліміти запитів та версійність

Ліміти зазвичай встановлюються для орендаря, організації, додатку або їхньої комбінації. Згідно з довідкою про ліміти Xero: п'ять одночасних запитів на орендаря, 60 на хвилину на орендаря, 5 000 на день на орендаря та 10 000 на хвилину для всього додатка, із заголовками залишку ліміту та Retry-After у разі отримання статусу 429. У документації QuickBooks Online зазначено 500 запитів на хвилину і 10 на секунду на realm ID з кінцевою точкою пакетної обробки, що підтримує до 30 операцій за запит.

Налаштуйте обмеження кількості запитів для кожного орендаря, глобальне обмеження швидкості (throttling), експоненційне затухання із випадковою затримкою (jitter), дотримання заголовка Retry-After, обмежену паралельність, пагінацію та метрики для відповідей 429 і залишку квоти. Не використовуйте необмежений паралелізм для імпорту; один великий клієнт може заблокувати будь-яке інше завдання для цього орендаря.

Закріплюйте версії API або керуйте ними явним чином. За замовчуванням QuickBooks Online використовує мінорну версію 75, якщо вона не вказана. Централізуйте версії в конфігурації, запускайте тести контрактів у пісочницях, стежте за нотатками до випусків та сприймайте невідомі поля у відповіді як сумісні зі зворотним напрямком (forward-compatible). Пісочниці не відтворять кожну умову продакшену, тому перед запуском протестуйте відключення, повторне підключення, відкликання згоди, прострочені токени, ліміти запитів та редагування на боці провайдера.

Що я побудував би насамперед

Якби я починав це завтра, то робив би це в такому порядку:

  1. Визначте точний бухгалтерський робочий процес: які події та об'єкти ви читаєте або записуєте.
  2. Виберіть стратегію провайдера: прямий, уніфікований, вбудований або гібридний.
  3. Створіть модель підключення з прив'язкою до орендаря, що містить ID організацій провайдера, дозволи, статус та метадані токенів.
  4. Реалізуйте OAuth з потоком коду авторизації, PKCE, перевіркою state, мінімально необхідними дозволами та зберіганням токенів на сервері.
  5. Створіть один адаптер провайдера за стабільним внутрішнім інтерфейсом.
  6. Створіть таблиці мапінгу ідентифікаторів на основі незмінних ID провайдера.
  7. Реалізуйте операції читання насамперед; імпортуйте довідкові дані перед будь-яким записом.
  8. Додайте завдання початкової синхронізації з пагінацією, лімітами запитів, контрольними точками та впорядкуванням за залежностями.
  9. Реалізуйте один вузький запис (створення інвойсу) лише після перевірки мапінгу клієнтів, товарів, податків та рахунків.
  10. Зробіть записи стійкими до повторних спроб за допомогою внутрішніх ідентифікаторів операцій, обмежень унікальності та перевірок віддаленого стану.
  11. Додайте підписані вебхуки, які швидко підтверджують отримання та виконують обробку асинхронно.
  12. Додайте опитування та звірку, щоб вебхуки були засобом прискорення, а не єдиним джерелом достовірних даних.
  13. Навмисно протестуйте сценарії збоїв.
  14. Додайте інструменти підтримки та аудиту, які роблять помилки зрозумілими та такими, що підлягають виправленню.
  15. Розширюйте покриття об'єктів поступово.

FAQ

Чи варто використовувати уніфікований API, чи краще створювати прямі конектори?

Використовуйте прямий конектор, коли один провайдер домінує серед ваших клієнтів або специфічна поведінка провайдера є ключовою. Розгляньте уніфікований API, коли широке покриття та швидкість важливіші за контроль. Якщо ваша справжня мета — самостійне ведення обліку, а не синхронізація з системою клієнта, жоден із варіантів не дає відповіді; натомість зверніть увагу на вбудовану книгу на кшталт Nordlet.

Чи достатньо вебхуків для підтримання актуальності даних?

Ні. Вебхуки вимикаються, затримуються або губляться, а їхні дані можуть бути неповними чи надходити не за порядком. Сприймайте їх як сигнали про зміни, запитуйте актуальний об'єкт після них і підкріплюйте періодичним опитуванням та звіркою.

Як запобігти тому, щоб збої токенів оновлення блокували доступ клієнтам?

Зберігайте найновіший токен оновлення атомарно при кожному оновленні, використовуйте блокування для кожного підключення, повторюйте спроби у разі тимчасових збоїв кінцевої точки токенів та відображайте зрозумілий стан повторної авторизації. 30-хвилинний пільговий період Xero допомагає, але саме атомарне збереження рятує ситуацію.

Чи можу я зіставляти записи за ім'ям клієнта чи електронною поштою?

Ні як постійний ідентифікатор. Імена змінюються, трапляються дублікати, а двоє клієнтів можуть ділити одну електронну пошту. Зберігайте незмінний ID провайдера і тримайте поруч власний SaaS ID.

Подальше читання