Unicraft API Открыть Unicraft →

API Unicraft

Читайте финансы строительной компании по мере того, как сотрудники вносят их в Unicraft - закупки, аренду, зарплаты подённых рабочих и по табелю, платежи, акты (форма 2), поступления и подотчётные авансы - и передавайте обратно, что ваша программа сделала с каждой записью. Создано в первую очередь для подключения бухгалтерской программы компании, чтобы никто не вносил один и тот же платёж дважды.

Начало работы

  1. Администратор компании открывает Компания → Интеграции в Unicraft, создаёт ключ и копирует его. Он отображается только один раз.
  2. Каждый вызов отправляется на https://unicraft.ge/api/v1/… с ключом в заголовке Authorization.
  3. Читайте ленту изменений с самого начала (after=0): вы получите всю историю компании начиная с самых старых записей, а затем всё новое по мере появления.
curl https://unicraft.ge/api/v1/me \
  -H "Authorization: Bearer uck_your_key"
{
  "company": { "id": "cc39…", "name": "Your Construction LLC" },
  "key": { "id": "eddd…", "name": "ORIS connector" },
  "scopes": ["accounting:read", "accounting:write"]
}

Ключи

Ключ принадлежит одной компании и открывает записи только этой компании. Передавайте его как Authorization: Bearer uck_… (или X-Api-Key: uck_…). Храните его на своём сервере и никогда на веб-странице.

Область доступаЧто разрешено ключу
accounting:readЧтение проектов, ленты изменений и отдельных записей. Есть у каждого ключа.
accounting:writeТакже отметка записей как отправленных, с ошибкой или пропущенных (/v1/sync) и передача данных об оплате в вашей программе (/v1/paid). Требуется для коннектора.
people:readТакже чтение личных номеров рабочих (worker.personal_no объекта timesheet_month) для расчёта зарплаты. Без него они приходят как null.

Ключ может совершать до 600 вызовов в минуту. Администратор может отозвать ключ в любое время; после этого возвращается 401. У компании есть до 10 ключей - выделите каждой программе свой.

Лента изменений

Каждая добавленная, изменённая или удалённая закупка, аренда, месяц подённых рабочих, месяц табеля, платёж, акт, входящий платёж и подотчётный аванс получает следующий номер (seq) в ленте изменений компании. Вы сохраняете последний имеющийся у вас номер и запрашиваете то, что появилось после него.

Эндпоинты

GET/v1/me

Компания ключа, название ключа и его scopes. Быстрая проверка работоспособности ключа.

GET/v1/projects

Проекты компании - для сопоставления каждого со своими (например, центр затрат ORIS).

{ "projects": [ { "id": "bb2e…", "name": "Vake Residence", "name_ka": "ვაკე რეზიდენსი", "name_ru": null,
                  "currency": "GEL", "start_date": "2026-03-01", "end_date": null, "closed_on": null } ] }
GET/v1/changes?after=0&limit=100

after: последний seq, который у вас есть (0 для начала). limit: от 1 до 500, 100 если не указано.

{
  "changes": [
    { "seq": 19, "entity": "purchase", "id": "3d04…", "op": "upsert", "at": "2026-10-24T12:39:15Z",
      "project_id": "bb2e…",
      "data": { "entity": "purchase", "id": "3d04…", "date": "2026-10-24", "item": "Cement M400",
                "quantity": 12, "unit": "bag", "unit_price": 16.5, "amount": 198, "currency": "GEL",
                "supplier": { "name": "Beton Service LLC", "name_ka": "შპს ბეტონ სერვისი", "code": "205123456" },
                "vat": "included", "vat_rate": 18, "net": 167.8, "vat_amount": 30.2,
                "waybill_no": "0712345678", "paid_on": "2026-10-24", "due_on": null,
                "project": { "id": "bb2e…", "name": "Vake Residence", "currency": "GEL" }, … } }
  ],
  "next": 19,
  "more": false
}
GET/v1/records/{entity}/{id}

Одна запись в её текущем виде - та же структура, что и у data в изменении. 404, если она удалена или не принадлежит компании.

POST/v1/sync

Что ваша программа сделала с записями - см. Отметка об отправке. Требуется accounting:write.

Что было оплачено в вашей программе, отмеченное оплаченным в Unicraft - см. Оплачено в вашей программе. Требуется accounting:write.

Записи

Каждая запись содержит entity, id, project (id, name, name_ka, name_ru, currency) и currency. Даты - YYYY-MM-DD; суммы - числа в валюте проекта. Названия приводятся на английском, грузинском и русском языках там, где они были так введены.

сущностьЧто это такоеСобственные поля
projectПроект создан, переименован или удален. При удалении все содержимое удаляется вместе с ним - его собственные записи не приходят каждая как удаление.name, name_ka, name_ru, currency, start_date, end_date, closed_on
purchaseПозиция, закупленная для проекта: материалы, инструменты, услуги. Оплачена сразу, в кредит (due_on) или из подотчётного аванса.purchase_id (позиции, закупленные вместе), date, kind, item, quantity, unit, unit_price, amount, supplier (name, code: его идентификационный код), vat, vat_rate, net, vat_amount (см. НДС), waybill_no, due_on, paid_on (null: задолженность), paid_from (cash_advance или null), cash_advance_id, request_id, note
requestУтверждённая заявка на материалы, оплаченная поставщику выбранного предложения (товары по ней становятся закупками по мере поступления).number, status, date, supplier (name, code), paid_on, amount, vat, vat_rate, net, vat_amount, invoice_no, waybill_nos
site_paymentОплата подённым рабочим или охране за месяц, либо аренда техники.kind, month (YYYY-MM), paid_on, amount, rental (equipment, supplier), note
subcontractor_paymentПлатёж субподрядчику по одному из пунктов его графика работ с удержанием - или возврат удержания.kind (interim или retention_release), paid_on, amount (оплачено наличными), retention (удержано), gross, subcontractor, item, act_id (акт (форма 2), который оплачивается, если есть), note
actАкт (форма 2): заказчика (к получению) или субподрядчика (к выплате).party (client или subcontractor), number, period_from, period_to, date, total, retention, retention_pct, is_final, signed_on, paid_on (оплачено или получено), money_in_id, subcontractor
money_inДеньги, полученные по проекту: от заказчика, покупателя квартиры, кредит.kind, date, amount, from, certificate_no, retention (true: возврат удержания), note
rentalАренда техники: задолженность перед поставщиком по мере прохождения дней (после оплаты это site_payment).equipment, supplier, date (начало), daily_rate, counted (days: фиксированное количество дней от начала; timesheet: дни нахождения машины в табеле, полдня как половина), days, months ([{ month, days, amount }] по сегодняшний день), cost_to_date, note
labour_monthМесяц подённых рабочих (kind: labour) или охраны (guard) проекта: начисленная задолженность, рассчитанная так же, как на странице Бухгалтерия - количество людей из ежедневных отчётов, умноженное на их дневную ставку, либо по табелю, если он ведётся на объекте. После оплаты это site_payment того же типа и месяца. Это заработная плата к начислению.kind, month (YYYY-MM), days (человеко-дни), amount (начислено по сегодняшний день), paid
timesheet_monthОдин месяц рабочего в табеле: кто сколько заработал, для начисления зарплаты и подоходного налога. Это расшифровка labour_month - не проводите её в расходах повторно. Её id остаётся неизменным для этого рабочего и месяца; запись передаётся снова при любом изменении дня.month (YYYY-MM), worker (name, personal_no, trade, day_rate), days (полдня считаются как 0.5), amount
cash_advanceПодотчётный аванс (საქვეანგარიშო). Купленное на эти деньги оформляется как закупки с paid_from: "cash_advance".date, amount, purpose, report_by, holder (name), spent, settled_on, settled_amount (+ возврат, − возмещение подотчётному лицу), note

НДС. vat принимает значение included (сумма включает 18% НДС: net - без НДС, vat_amount - НДС к вычету), none (продавец не начисляет НДС) или null (не указано - net и vat_amount также null). Сумма всегда равна фактически оплаченной.

У закупки с amount 0 пока нет цены - офис оценит её позже, и тогда она снова поступит через ленту изменений. Бухгалтерский коннектор должен пропускать её до этого момента.

Отметка об отправке

После того как ваша программа обработает записи, сообщите Unicraft. Бухгалтер компании видит это рядом с каждой строкой на странице Бухгалтерия: Отправлено в ORIS, либо ошибку полностью, чтобы ничто не потерялось незаметно.

curl -X POST https://unicraft.ge/api/v1/sync \
  -H "Authorization: Bearer uck_your_key" -H "Content-Type: application/json" \
  -d '{ "system": "oris",
        "items": [
          { "entity": "purchase", "id": "3d04…", "status": "sent", "external_id": "31" },
          { "entity": "act", "id": "9a1c…", "status": "error", "message": "Account [3110 7] is closed" }
        ] }'
{ "marked": 2, "of": 2 }

system указывает имя вашей программы (oris, fina, balance или вашей собственной). status - это sent, error или skipped (намеренно пропущено - например, закупка, у которой ещё нет цены, или тип, который ваша программа не ведёт; бухгалтер видит запись как пропущенную, а не как отправленную). Сохраняйте собственный id в external_id - например, транзакцию ORIS - чтобы обновить или удалить её при изменении записи. Повторная отметка записи заменяет предыдущую. До 500 элементов за вызов; записи, не принадлежащие компании, исключаются из marked.

Когда платёж проведён в бухгалтерской программе, сообщите Unicraft, и там он тоже будет отмечен как оплаченный - на странице Бухгалтерия его повторно отмечать не придётся.

curl -X POST https://unicraft.ge/api/v1/paid \
  -H "Authorization: Bearer uck_your_key" -H "Content-Type: application/json" \
  -d '{ "system": "oris",
        "items": [
          { "entity": "purchase", "id": "3d04…", "paid_on": "2026-10-25", "external_id": "PAY-118" },
          { "entity": "labour_month", "id": "71be…", "paid_on": "2026-10-25", "amount": 2400, "external_id": "PAY-119" }
        ] }'
{ "results": [ { "entity": "purchase", "id": "3d04…", "result": "paid" },
               { "entity": "labour_month", "id": "71be…", "result": "paid" } ] }
сущностьЧто происходит
purchaseВся закупка (каждая строка с тем же purchase_id) отмечается оплаченной на paid_on, если оставалась задолженность.
requestОтмечается оплаченным так, как это сделал бы бухгалтер: по amount или на сумму выбранного предложения. Уже полученные по нему товары отмечаются оплаченными вместе с ним; отдел закупок уведомляется.
labour_month, rentalЗаписывается платёж на сумму amount (или на весь остаток долга). Укажите external_id (номер вашего платежа): платёж с тем же номером, отправленный повторно, дважды проведён не будет.

paid_on - сегодня, если не указано; amount не обязательно. По каждому элементу возвращается result: paid, already_paid, not_approved (заявка ещё не утверждена), not_found (не принадлежит компании), future_date или bad_amount. Платёж возвращается к вам в ленте изменений (запись изменилась или появился новый site_payment) - платёж проведён вашей программой, поэтому пометьте его как skipped.

Ошибки

Ошибка возвращается в виде JSON: { "error": { "code": "bad_key", "message": "…" } }.

СтатускодЗначение
400bad_after, bad_id, bad_json, bad_body, bad_item, too_long, refusedЗапрос неверен - в сообщении указано, что нужно изменить.
401no_key, bad_keyКлюч отсутствует, недействителен или был отозван.
403scopeУ ключа нет прав на это действие.
404no_route, no_entity, not_foundТакой адрес, тип записи или запись не существуют.
429too_manyБолее 600 вызовов в минуту - подождите и повторите попытку.
500serverЧто-то пошло не так с нашей стороны - попробуйте снова.

Коннектор, вкратце

Что делает коннектор бухгалтерской программы каждые несколько минут:

let after = loadLastSeq();                      // 0 the first time
for (;;) {
  const r = await get(`/v1/changes?after=${after}&limit=200`);
  const marks = [];
  for (const c of r.changes) {
    try {
      if (!c.data) removeEntry(c.entity, c.id);   // deleted in Unicraft
      else if (c.data.amount === 0) { marks.push({ entity: c.entity, id: c.id, status: 'skipped' }); continue; }
      else {
        const own = upsertEntry(c.data);           // e.g. an ORIS transaction, by c.id
        marks.push({ entity: c.entity, id: c.id, status: 'sent', external_id: String(own) });
      }
    } catch (e) {
      marks.push({ entity: c.entity, id: c.id, status: 'error', message: e.message });
    }
  }
  if (marks.length) await post('/v1/sync', { system: 'oris', items: marks });
  saveLastSeq(after = r.next);
  if (!r.more) break;
}

На какие счета относится запись - поставщики, банк, касса, материалы - это собственный выбор компании, который настраивается в коннекторе один раз. Закупка, уже внесенная в вашу программу по накладной rs.ge, является той же закупкой: сопоставьте ее по waybill_no и code поставщика вместо повторного проведения. Вопросы или разработка коннектора для вашей программы: [email protected].