← Документация / Руководства
Соглашения об API
Структура запросов, права доступа, списочные запросы, денежные суммы, ошибки, идемпотентность, ограничения частоты запросов.
Структура запросов
Каждая операция представляет собой 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.
Аутентификация и права доступа
Authorization: Bearer <api key>. Ключи содержат права доступа (scopes), которые проверяются для каждого действия:
{module}:read- операции чтения и получения списков{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"), и никогда не передаются в виде чисел с плавающей точкой. НДС рассчитывается по каждой строке с применением округления к ближайшему большему (half-up). Даты имеют формат 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> к любому запросу, изменяющему данные:
- Повторный запрос с тем же ключом и полезной нагрузкой возвращает сохраненный ответ байт-в-байт с заголовком
x-idempotent-replay: true. - Тот же ключ с другой полезной нагрузкой возвращает ошибку 422
idempotency_key_reuse. - Одновременный дублирующийся запрос, пока первый находится в обработке, возвращает ошибку 409
idempotency_in_progress. - Ключи привязываются к API-ключу или пользователю, который их отправляет, в контексте компании, для которой выполняется вызов, поэтому две разные интеграции одной компании могут использовать один и тот же ключ. Вызовы, сделанные до создания компании, а также вызовы
account/*, сохраняют ключи в разрезе пользователей, благодаря чему повторный вызовaccount/companies/createсоздает ровно одну компанию. - Сохраненный ответ возвращается только после того, как вызывающая сторона повторно пройдет все проверки прав (права доступа, роль, компания и статус выставления счетов); в противном случае запрос получит актуальную ошибку.
- Ключи истекают через 24 часа. Ответы с ошибками (4xx) также воспроизводятся при повторных запросах; ответы 5xx не сохраняются, поэтому повторные запросы выполняются заново.
Ограничения частоты запросов (Rate limits)
300 запросов в минуту на один API-ключ (на предоставленные учетные данные; для неаутентифицированных запросов лимиты применяются по IP-адресу). При получении ошибки 429 учитывайте заголовок retry-after. Заголовки x-ratelimit-* информируют об оставшемся лимите.
Вебхуки
События записываются в транзакционную таблицу исходящих сообщений (outbox) в рамках той же транзакции базы данных, что и само изменение: для отмененной транзакции событие никогда не отправляется, а ни одно подтвержденное событие не теряется. Доставка:
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, или перенаправление (redirect) приводят к повторной попытке через 30 секунд, 2 минуты, 10 минут, 30 минут, 1 час, 3 часа, 6 часов и 12 часов (всего в течение примерно 24 часов), после чего доставка помечается как неудавшаяся
- Каждая доставка отправляется только одним сервером одновременно, поэтому запуск нескольких экземпляров API не приведет к дублированию отправки
Перед доверием к полезной нагрузке проверьте заголовок x-nordlet-signature-v2 с помощью сравнения за постоянное время (constant-time comparison) и отклоните доставку, если ее временная метка отличается от системных часов более чем на 5 минут. Временная метка входит в состав подписанного текста, поэтому перехваченную доставку нельзя воспроизвести позже со свежей временной меткой. Сохраняйте идентификаторы обработанных доставок из заголовка x-nordlet-delivery, чтобы игнорировать повторы в пределах этого окна. Неудавшуюся доставку можно отправить повторно через webhooks/deliveries/redeliver.
Аудит
Любое изменение данных фиксируется в системе (actor, action, entity, diff) и доступно для выборки через audit/list.
Бухгалтерские гарантии
- Проводки в журнале всегда сбалансированы. Это контролируется отложенным триггером базы данных в момент фиксации транзакции (commit), а не только кодом приложения.
- Нумерация документов идет без пропусков в разрезе серий и лет; выделение номеров безопасно при высокой параллельности.
- Заблокированные отчетные периоды отклоняют любые проводки с датой внутри них (409).
- Документы с мягким удалением (soft-deleted) сохраняют свою историю в аудите; проведение или регистрация документов исключает возможность их удаления.