Nordlet

← Документація / Посібники

Угода щодо API

Формат запитів, області дії (scopes), спискові запити, грошові одиниці, помилки, ідемпотентність, ліміти частоти запитів.

Формат запитів

Кожна операція виконується як POST-запит у стилі RPC:

POST /v1/{module}/{resource}/{action}

Модулі: reference, partners, catalog, sales, purchases, ledger, bank, declarations, files, webhooks, audit. Дії є дієсловами: create, get, update, delete, list, а також предметні дії, як-от issue, register, match, apply-advance, generate.

Автентифікація та області дії (scopes)

Authorization: Bearer <api key>. Ключі містять області дії (scopes), які перевіряються для кожної дії:

  • {module}:read - дії отримання/списку (get/list)
  • {module}:write - модифікації
  • {module}:* або * - підстановочні знаки (wildcards)

Відсутність області дії призводить до помилки 403 forbidden. Відсутній або недійсний ключ призводить до 401 unauthorized.

Спискові запити

Усі дії list мають спільний контракт:

{
  "page": 1,
  "pageSize": 50,
  "sort": [{ "field": "createdAt", "dir": "desc" }],
  "filter": [{ "field": "paymentStatus", "op": "eq", "value": "unpaid" }]
}

Оператори фільтрації: eq (дорівнює), ne (не дорівнює), contains (текстовий збіг без урахування регістру, лише для текстових полів), gte (більше або дорівнює), lte (менше або дорівнює), in (будь-яке зі списку до 500 значень). Поля, за якими можна сортувати та фільтрувати, визначено в білому списку для кожного ендпоінту (див. специфікацію OpenAPI), а невідомі поля повертають помилку 400. Додайте totals: ["field", …] до запиту, щоб підсумувати числові поля за всіма рядками, що відповідають умовам; коли записи мають валюту, параметр totalsByCurrency надає такі ж суми, розділені за кодами валют. Відповіді: { rows, total, page, pageSize, totals?, totalsByCurrency? }.

Грошові одиниці та дати

Грошові суми подаються у вигляді десяткових рядків із кількістю знаків після коми до 4 ("121.0000") і ніколи не у вигляді чисел із плаваючою комою (floats). ПДВ (VAT) розраховується для кожного рядка з округленням до найближчого більшого (half-up rounding). Дати мають формат YYYY-MM-DD, а мітки часу (timestamps) відповідають стандарту ISO 8601 у форматі UTC.

Помилки

Єдиний конверт для всіх відповідей:

{
  "error": {
    "code": "validation",
    "message": "Request validation failed",
    "requestId": "k1x…",
    "key": "request_invalid",
    "fieldErrors": { "lines.0.unitPriceExclVat": ["Invalid value"] }
  }
}

Коди: validation (400/422, а також 413, якщо завантажений файл або тіло запиту завеликі), unauthorized (401), payment_required (402, термін пробного періоду або передплаченого кредиту закінчився, а повідомлення містить інструкції щодо подальших дій), forbidden (403), not_found (404), conflict (409), idempotency_key_reuse (422), idempotency_in_progress (409), rate_limited (429), internal (5xx). Коли повідомлення є одним із фіксованих, поле key визначає його, щоб клієнт міг показати власний переклад, а params містить значення для нього (наприклад, { "period": "2026-09" } для заблокованого облікового періоду). Включайте requestId під час звернення щодо проблем.

Ідемпотентність

Додайте Idempotency-Key: <any string ≤255 chars> до будь-якого запиту на модифікацію:

  • Повторний запит із тим самим ключем і корисним навантаженням (payload) - збережена відповідь відтворюється байт-у-байт із заголовком x-idempotent-replay: true.
  • Той самий ключ, інше корисне навантаження (payload) - 422 idempotency_key_reuse.
  • Одночасний дублікат, поки перший запит ще виконується - 409 idempotency_in_progress.
  • Ключі належать тому API-ключу або користувачу, який їх надсилає, у межах компанії, для якої виконується виклик, тому дві інтеграції однієї компанії можуть використовувати однаковий ключ. Виклики, зроблені до створення компанії, та виклики account/* зберігають ключі окремо для кожного користувача, тому повторний виклик account/companies/create створює лише одну компанію.
  • Збережена відповідь повертається лише після того, як викликаюча сторона знову пройде перевірку прав доступу (область дії (scope), роль, компанія та стан розрахунків); інакше запит отримує поточну помилку.
  • Ключі втрачають чинність через 24 години. Відповіді з помилками (4xx) також відтворюються; відповіді 5xx не зберігаються, тому повторні спроби виконуються заново.

Ліміти частоти запитів (Rate limits)

300 запитів на хвилину для кожного API-ключа (за наданими обліковими даними; неавтентифіковані запити обмежуються за IP-адресою). У разі отримання помилки 429 дотримуйтеся заголовка retry-after. Заголовки x-ratelimit-* інформують про стан вашого ліміту.

Вебхуки (Webhooks)

Події записуються до транзакційної черги вихідних повідомлень (transactional outbox) у межах тієї ж транзакції бази даних, що й сама зміна. Документ, чию транзакцію було скасовано (rolled back), ніколи не генерує подію, і жодна подія не втрачається. Доставка:

  • POST-запит на вашу URL-адресу з JSON-подією
  • x-nordlet-timestamp: <unix seconds> - час підписання доставки
  • x-nordlet-signature-v2: t=<timestamp>,v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>"> з використанням вашого секрету підписки
  • x-nordlet-signature: sha256=<hex HMAC-SHA256 of the raw body> - залишено без змін для сумісності з наявними приймачами
  • x-nordlet-delivery містить ідентифікатор доставки, який є однаковим під час кожної повторної спроби доставки однієї події
  • Будь-яка відповідь, окрім діапазону 2xx, або перенаправлення призводять до повторної спроби через 30 секунд, 2 хвилини, 10 хвилин, 30 хвилин, 1 годину, 3 години, 6 годин і 12 годин (загалом приблизно через 24 години), після чого доставка позначається як невдала
  • Кожна доставка надсилається лише одним сервером водночас, тому запуск кількох екземплярів API не призведе до подвійної відправки

Перевіряйте x-nordlet-signature-v2 за допомогою порівняння за константний час (constant-time comparison), перш ніж довіряти корисному навантаженню (payload), і відхиляйте доставку, якщо її мітка часу відрізняється від годинника вашого сервера більш ніж на 5 хвилин. Мітка часу є частиною підписаного тексту, тому перехоплену доставку не можна відтворити пізніше зі свіжою міткою часу. Зберігайте ідентифікатори x-nordlet-delivery, які ви вже опрацювали, щоб ігнорувати повтори в межах цього вікна. Невдалу доставку можна надіслати повторно за допомогою webhooks/deliveries/redeliver.

Аудит

Кожна модифікація записується (actor, action, entity, diff) і доступна для запитів через audit/list.

Бухгалтерські гарантії

  • Бухгалтерські проведення (journal postings) завжди збалансовані. Це забезпечується відкладеним тригером бази даних під час фіксації транзакції (commit), а не лише кодом додатку.
  • Номера документів є безперервними в межах кожної серії чи року, а їх виділення є безпечним щодо паралельного виконання (concurrency-safe).
  • Заблоковані облікові періоди відхиляють будь-які проводки з датою всередині них (409).
  • М'яко видалені документи (soft-deleted documents) зберігають свій слід аудиту; випущені або зареєстровані документи не можна видалити.