Developer API · бета

Делайте из своей системы всё то же, что и в интерфейсе, по тем же правилам.

Kumpara Developer API подключает интернет-магазины, ERP, бухгалтерские программы и интеграторов маркетплейсов. Поверхность /v1 вызывает то же ядро, что и интерфейс: те же проверки, те же проводки, тот же расчёт налога и удержания.

  • Безопасно для книг: каждое движение денег — одна транзакция, исправление — сторно
  • Электронные документы: выпуск, отмена, входящие, проверка плательщика и кредиты — в том же API
  • Под Турцию: построчное удержание, коды освобождения от НДС, мультивалютность и снимок курса

Developer API сейчас в закрытой бете; общий доступ пока не открыт, дата не называется. Участники беты получают свой базовый адрес и ключи от нас.

74
рабочих эндпоинта От контрагентов до электронных документов — все под scope.
28
отдельных scope Ключу выдаётся только необходимое.
3
книги только на добавление Расчёты, касса и склад: без UPDATE/DELETE.
1
ключ = 1 компания Утечка между компаниями исключена архитектурно.

Что можно построить?

Всё перечисленное работает на существующих эндпоинтах — это не планы.

Полная цепочка заказа

Создайте заказ, отгрузите накладную, выставьте и проведите счёт, закройте оплату тем же вызовом. Частичная отгрузка и частичное выставление поддерживаются.

Синхронизация с ERP и бухгалтерией

Поток GET /v1/changes отдаёт тип и идентификатор изменённой записи; детали вы читаете отдельно. Поток не различает интерфейс, мобильное приложение и API.

Задавайте остатки абсолютным значением

POST /v1/stock-levels/actions/set записывает результат инвентаризации; разница становится корректирующим движением. Движения читаются из книги только на чтение.

Выпускайте электронные счета

Один вызов превращает проведённый счёт в электронный документ; сценарий выбирается на сервере. Вы синхронизируете входящие, скачиваете XML/PDF и отвечаете на коммерческие счета.

Состояние контрагента из одного места

Одного баланса мало: проводки, открытые позиции и сроки задолженности — отдельные эндпоинты. Платежи закрываются на открытые счета, курсовая разница читается отдельно.

Перенесите начальные остатки

Начальные остатки по контрагентам и складу заводятся отдельными эндпоинтами, у каждого есть сторнирующая пара. Книги на добавление — сторно единственный способ исправления.

Первый счёт за пять шагов

Каждая запись несёт три заголовка: Authorization, Idempotency-Key, Content-Type.

  1. 1

    Создайте ключ

    В приложении: Настройки → API-ключи. Выберите имя, компанию и scope. Открытый ключ показывается один раз.

  2. 2

    Проверьте контекст

    GET /v1/me возвращает бизнес, компанию, среду и scope ключа.

  3. 3

    Заведите контрагента

    Сопоставление по ИНН или коду: существующие записи обновляются, отсутствующие создаются.

  4. 4

    Выставьте и проведите счёт

    С approve: true создание и проведение выполняются одной транзакцией: номер, долг клиента и списание склада.

  5. 5

    Закройте оплату

    Счёт передаётся при создании платежа: касса, расчёты и распределение пишутся одной транзакцией.

Быстрый старт

1. Проверьте ключ

Каждый запрос несёт Authorization: Bearer. Первый вызов покажет, к какому бизнесу и к какой компании привязан ключ и что ему разрешено:

curl -s "https://api.kumpara.net/v1/me" \
  -H "Authorization: Bearer kp_live_a1b2c3d4_…"
{
  "data": {
    "tenant":    { "id": "…", "name": "Örnek Ticaret A.Ş.", "plan": "Pro" },
    "company":   { "id": "…", "legalName": "Örnek Ticaret A.Ş.", "baseCurrency": "TRY" },
    "apiClient": { "prefix": "kp_live_a1b2c3d4", "environment": "live",
                   "scopes": ["me:read", "contacts:write", "sales:write", "sales:approve"] }
  }
}

GET /v1/capabilities сообщит, подключены ли электронные документы, сколько осталось кредитов и какова базовая валюта компании.

2. Сопоставьте контрагента своим ключом

Не нужно искать клиента каждый раз: используйте upsert по ИНН или коду. Существующая запись обновляется, отсутствующая создаётся.

curl -s -X POST "https://api.kumpara.net/v1/contacts/actions/upsert?matchBy=taxNumber" \
  -H "Authorization: Bearer kp_live_…" \
  -H "Idempotency-Key: contact-4711-2026-09-23" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Örnek Gıda Ltd. Şti.", "type": "customer", "taxNumber": "1234567890", "preferredCurrency": "TRY" }'

Поле created в ответе говорит, создана запись или обновлена. matchBy принимает только taxNumber или code.

3. Выставьте и проведите счёт

В строке счёта нет поля суммы. Вы передаёте количество, цену, скидку и ставку НДС; итог строки, удержанный НДС, базовую сумму и номер документа считает сервер.

curl -s -X POST "https://api.kumpara.net/v1/sales-invoices" \
  -H "Authorization: Bearer kp_live_…" \
  -H "Idempotency-Key: order-88213-invoice" \
  -H "Content-Type: application/json" \
  -d '{
        "contactId": "6f1c…",
        "currency": "TRY",
        "approve": true,
        "lines": [ { "productId": "9a3e…", "quantity": 10, "unitPrice": 250, "vatRate": 20 } ]
      }'

approve: true выполняет создание и проведение одной транзакцией. Это денежная мутация, поэтому ключу нужен sales:approve вместе с sales:write, иначе вернётся 403 insufficient_scope.

4. Проведите оплату и закройте счёт

curl -s -X POST "https://api.kumpara.net/v1/payments" \
  -H "Authorization: Bearer kp_live_…" \
  -H "Idempotency-Key: payment-88213" \
  -H "Content-Type: application/json" \
  -d '{ "contactId": "6f1c…", "cashAccountId": "2b77…", "direction": "incoming",
        "amount": 3060, "invoiceType": "sales_invoice", "invoiceId": "c41b…" }'

Касса, расчёты с контрагентом и распределение пишутся одной транзакцией. Для нескольких счетов — allocations[], для закрытия позже — POST /v1/payments/{id}/actions/allocate.

5. Забирайте изменения

curl -s "https://api.kumpara.net/v1/changes?since=2026-09-23T06:00:00Z&types=sales_invoice,payment" \
  -H "Authorization: Bearer kp_live_…"

В следующем вызове передайте meta.checkpoint как since — граница строгая, одна и та же запись не придёт дважды. Рекомендуем перекрытие в пять минут: чтение идемпотентно, повтор безвреден.

Базовый контракт

Идентификация и права

Ключ передаётся как Authorization: Bearer kp_live_… (или X-Api-Key). Открытое значение не хранится — Kumpara держит только SHA-256-хеш и префикс. Каждый ключ привязан к одной компании; данные другой компании вернуться не могут архитектурно. Права ключа не могут превышать роль создавшего его пользователя.

Права имеют вид {ресурс}:{действие}, их двадцать восемь: read — просмотр, write — создание и изменение, approve — проведение, отмена и сторно, issue/cancel/incoming — электронные документы. Недоступный эндпоинт возвращает 403 insufficient_scope и называет недостающее право.

Идемпотентность

Каждая запись требует Idempotency-Key. Ключ сохраняется внутри той же транзакции, что и запись — двойной записи нет. Повторный вызов с тем же ключом не выполняет работу заново. Ответ приходит в одной из двух форм: 409 idempotency_replayed (созданную запись вы читаете через GET) либо 200 с телом первого ответа и флагом replayed: true. Обе означают «операция уже применена»; ваш клиент должен считать успехом и ту и другую.

Деньги, курс и числовые типы

Суммы хранятся как numeric(19,4) и возвращаются в JSON строкой — без ошибок округления. Сумма никогда не отделяется от валюты.

Каждая финансовая строка несёт собственный снимок курса: originalAmount, originalCurrency, exchangeRate, baseAmount, baseCurrency. Даже если курс обновится позже, прошлый документ не изменится. Курс можно передать в exchangeRate; если не передать — применяется 1.

Пагинация

Списки страничатся курсором, offset отсутствует. Ответ несёт meta.nextCursor и meta.hasMore. Размер страницы — pageSize: по умолчанию 50, максимум 200. Для дельты — параметр запроса updatedAfter или поток /v1/changes.

Ошибки

Ошибки — RFC 9457 application/problem+json со стабильным полем code. Словарь зафиксирован.

Статус Значение Частые коды
400 Запрос не прочитан invalid_request, invalid_value
401 Ключ недействителен unauthorized
403 Нет нужного права insufficient_scope
404 Записи нет или она не этой компании not_found
409 Конфликт idempotency_replayed, duplicate_code
422 Нарушено бизнес-правило validation_failed, currency_not_enabled
429 Превышен лимит rate_limit_exceeded

Лимиты

Чтение и запись — разные корзины. По умолчанию 600 чтений и 120 записей в минуту на ключ; в каждом ответе есть RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset. При превышении — 429 и Retry-After.

Идентификатор запроса и спецификация

Каждый ответ несёт X-Request-Id; это же значение видно как requestId в теле ошибки — им и делитесь с поддержкой. Полный контракт опубликован как OpenAPI 3: https://api.kumpara.net/v1/openapi.json.

Ресурсы

Таблица ниже — вся поверхность, работающая сегодня. Полные параметры, тела и схемы ответов — в OpenAPI: https://api.kumpara.net/v1/docs.

Область Основные эндпоинты Права
Контекст GET /v1/me, GET /v1/capabilities me:read
Карточка контрагента GET · POST /v1/contacts, PATCH /v1/contacts/{id}, POST /v1/contacts/actions/upsert contacts:read · contacts:write
Состояние контрагента GET /v1/contacts/{id}/balance, …/ledger-entries, …/open-items, GET /v1/aging contacts:read
Начальный остаток POST /v1/contacts/{id}/actions/set-opening-balance, …/actions/reverse-opening-balance contacts:write
Товары и варианты GET · POST /v1/products, POST /v1/products/actions/upsert, POST /v1/products/{id}/variants products:read · products:write
Склад GET /v1/stock-levels, POST /v1/stock-levels/actions/set, GET /v1/stock-movements stock:read · stock:write
Заказы GET · POST /v1/orders, PUT /v1/orders/{id}, POST /v1/orders/{id}/actions/cancel sales:read · sales:write
Накладные GET · POST /v1/delivery-notes, …/actions/ship, …/actions/cancel sales:read · sales:write
Счета продаж GET · POST /v1/sales-invoices, …/{id}/actions/approve, …/{id}/actions/cancel sales:read · sales:write · sales:approve
Счета закупок GET · POST /v1/purchase-invoices, …/{id}/actions/approve purchase:read · purchase:write · purchase:approve
Платежи GET · POST /v1/payments, POST /v1/payments/{id}/actions/allocate payments:read · payments:write
Касса и банк GET /v1/cash-accounts, GET /v1/cash-accounts/{id}/ledger-entries cash:read
Чеки и векселя GET /v1/cheques cheques:read
Электронные документы POST /v1/sales-invoices/{id}/actions/issue-e-document, GET /v1/e-documents, GET /v1/incoming-e-documents edocuments:*
Справочники GET /v1/warehouses, GET /v1/categories, GET /v1/reference/{type} catalog:read
Поток изменений GET /v1/changes changes:read

Как связывается цепочка документов. В теле накладной есть orderId, в теле счёта — orderId и deliveryNoteIds[], а строки сопоставляются через orderLineId и deliveryNoteLineId. Остаток не хранится счётчиком — он выводится из непогашенных счетов, поэтому отменённый счёт снова освобождает заказ.

Списание склада происходит в одном месте. Отгрузка и проведение счёта не списывают товар дважды: итоговое списание равно max(Σ отгрузок, Σ проведённых счетов), и каждый документ пишет только свою разницу.

Пока нет — в планах

Мы пишем и о том, чего нет, чтобы вы не строили на неверном допущении.

Вебхуки Скоро

Сегодня рабочий путь — опрос GET /v1/changes; scope webhooks:manage есть в каталоге, но эндпоинта нет.

Изолированная песочница Скоро

Префикс kp_test_ сегодня лишь метка и пишет в реальные данные. Для экспериментов заведите отдельную компанию.

ETag / If-Match Скоро

Контроль параллелизма не добавляется наполовину без опорной колонки версии: иллюзия защиты хуже её отсутствия.

OAuth 2.1 и каталог приложений Скоро

На бете клиент сам создаёт для вас узкий ключ; поток с экраном согласия — в планах.

Преобразование входящего документа в счёт закупки Скоро

Чтение, ответ и игнорирование входящих работают; сопоставление строк с товарами пока делается в интерфейсе.

Эндпоинты отчётов и выгрузок Скоро

Сроки задолженности (GET /v1/aging) работают; P&L, НДС и асинхронные выгрузки пока отсутствуют.

Безопасность, изоляция и персональные данные

Изоляция реализована в базе данных. Компании разделяет не фильтр в приложении, а собственный механизм безопасности строк PostgreSQL. Запрос API подключается ролью с минимальными правами, а контекст пишется в базу при открытии соединения — даже неверный запрос не вернёт строку другого бизнеса. Разделение компаний добавляется сверху: ключ привязан к одной компании.

Ключ не хранится. Хранятся только SHA-256-хеш и префикс (kp_live_a1b2c3d4). Открытое значение показывается один раз при создании; восстановить его нельзя — выпускается новый. В логи ключ не пишется, только префикс. Отзыв действует немедленно.

Повышения прав нет. Права ключа не превышают роль создавшего его пользователя. Создание счёта с approve: true требует sales:approve вместе с sales:write; при отсутствии запрос отклоняется, а не сохраняется черновиком.

Каждое действие оставляет след. Любая запись через API попадает в журнал аудита с префиксом ключа в роли актора (api:kp_live_a1b2c3d4). Интерфейс, мобильное приложение и API пишут в один журнал.

Персональные данные — узкие права. Поля вроде ИНН, IBAN, имени и адреса возвращаются ключам без права pii:read в замаскированном виде: видны последние четыре символа, а эндпоинт продолжает работать. Если интеграции это не нужно — не выдавайте его: лучшая защита, когда данные никуда не уходят.

Как хранить ключ. На сервере, в переменной окружения или менеджере секретов; никогда не в исходном коде, браузере или мобильном приложении. Для каждой интеграции — свой ключ. В обращении в поддержку передавайте requestId и Idempotency-Key, но никогда сам ключ.

Вопросы разработчиков

В какой тариф входит API?

Доступ не зависит от тарифа. Тарифы отличаются лимитами запросов и квотами, их можно настроить. На этапе беты доступ открывается по заявке.

Могу ли я сам считать суммы?

Нет — сервер является единственным авторитетом. Вы передаёте количество, цену, скидку, ставку НДС, код удержания и валюту. Итоги строки, удержанный НДС, базовую сумму и номер документа считает сервер; поля суммы в строке нет.

Создастся ли дубль при повторной отправке?

Нет. Каждая запись требует Idempotency-Key; ключ сохраняется в той же транзакции, что и запись. Повторный вызов с тем же ключом не выполняет работу заново: вы получаете либо 409 idempotency_replayed и читаете созданную запись через GET, либо 200 с телом первого ответа и флагом replayed: true. Обе формы считаются успехом.

Можно ли изменить проведённый счёт?

Нет, проведённый документ неизменяем. Исправление — отмена плюс новый документ; отмена пишет сторнирующие проводки. В книгах расчётов, кассы и склада нет UPDATE/DELETE. Перед отменой GET /v1/sales-invoices/{id}/cancel-eligibility покажет препятствия.

Увижу ли я изменения, сделанные в интерфейсе?

Да. Поток GET /v1/changes не различает источник: интерфейс, мобильное приложение и API попадают в один поток. Поток отдаёт только тип и идентификатор записи — детали вы читаете отдельным запросом.

Есть ли отдельная песочница?

Пока нет — говорим прямо. Ключ с префиксом kp_test_ сегодня лишь метка и пишет в ваши реальные данные. Для экспериментов заведите отдельную компанию; изолированная песочница — в планах.

Есть ли вебхуки?

Пока нет. Рабочий путь сегодня — опрос GET /v1/changes: передавайте полученный meta.checkpoint как since в следующем запросе. Вебхуки — в планах.

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

Каждый ключ привязан к одной компании и видит только её данные. Для нескольких компаний создайте по ключу на компанию. Переключение компании одним ключом — в планах.

Тратит ли выставление счёта кредиты?

Нет. Кредиты расходуются только на электронные документы: каждый исходящий и входящий документ — 1 кредит. Счета, заказы и накладные внутри системы не расходуют кредиты. Баланс — GET /v1/e-credits.

Что если я потеряю ключ?

Восстановить нельзя. Kumpara хранит только SHA-256-хеш и префикс; открытое значение показывается один раз при создании. Потеряли — отзовите старый ключ и создайте новый; отзыв действует немедленно.

Присоединяйтесь к бете

В бету принимаются платформы интернет-магазинов, ERP и бухгалтерские программы, бухгалтерские бюро и интеграторы маркетплейсов. Участники получают доступ, заблаговременные уведомления об изменениях контракта и прямой канал обратной связи.