Ресурси¶
Усі шляхи відносні до https://crm.h-profit.com/bapi-v2. Кожен ендпоінт потребує заголовка
Authorization та відповідного scope.
Багато списків підтримують ?include= для вбудовування пов'язаних об'єктів — див.
таблицю зв'язків. Щоб отримати кілька ресурсів за раз, використайте
composite /query.
Reference (довідник)¶
Усе, що потрібно інтегратору для побудови пов'язаних об'єктів (рахунки, валюти, категорії, бренди, склади, канали, служби доставки) одним викликом.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/reference |
reference:read |
?types=accounts,currencies,warehouses звужує відповідь до конкретних секцій: accounts,
currencies, product_categories, expense_categories, brands, warehouses,
sales_channels, carrier_accounts, write_off_categories.
carrier_accounts — підключені служби доставки акаунта; id — це account_id для пошуку в
Delivery:
carrier — nova_poshta, ukrposhta або meest. Акаунт Нової Пошти також містить senders —
відправників, для яких у HugeProfit налаштовані місто й відділення; id — це sender_id для
створення ТТН:
{ "id": 431, "carrier": "nova_poshta", "name": "Магазин",
"senders": [ { "id": "3f6c1a20-…_3f71b5c8-…", "name": "Іван Петренко",
"warehouse_name": "Київ, Відділення №1" } ] }
Warehouses (склади)¶
| Метод | Шлях | Scope |
|---|---|---|
GET |
/warehouses |
warehouses:read |
{ "id": 8549, "name": "Основний", "type": "main", "position": 0,
"created_at": "2024-11-24T15:59:10" }
type — одне з main, dropshipping, negative_stock.
Suppliers (постачальники)¶
| Метод | Шлях | Scope |
|---|---|---|
GET |
/suppliers |
suppliers:read |
POST |
/suppliers |
suppliers:write |
Тіло POST: { "name", "phone"?, "address"?, "comment"? } (створення постачальника з наявним
іменем повертає існуючого). unpaid — заборгованість перед постачальником.
{ "id": 30, "name": "Acme Ltd", "phone": "380...", "address": "…",
"comment": null, "unpaid": "69665.00", "created_at": "2023-09-11T10:45:23" }
Products (товари)¶
| Метод | Шлях | Scope | Примітки |
|---|---|---|---|
GET |
/products |
products:read |
список |
GET |
/products/{id} |
products:read |
один (завжди з images) |
GET |
/products/{id}/similar |
products:read |
id схожих товарів |
POST |
/products |
products:write |
масове створення, до 500 |
PUT |
/products |
products:write |
масова часткова зміна, до 500: { "products": [{ "id": 1, ... }] } |
PUT |
/products/{id} |
products:write |
часткова зміна одного товару |
DELETE |
/products |
products:write |
тіло { "ids": [...] } |
DELETE |
/products/{id} |
products:write |
один |
POST |
/product_stock |
products:write |
швидке оновлення залишку/ціни/собівартості |
Фільтри GET: product_id, pids (csv), sku (csv), barcode (csv), category_id, warehouse_id,
modify_start/modify_end (unix). ?count=1 повертає лише total. ?include=images
вбудовує URL зображень. URL зображення закінчується на ?c=<версія>, яка змінюється, коли фото
замінюють, — не відкидайте її, щоб кеш підхопив нове зображення.
Пошук за артикулом або штрихкодом: ?sku=TS-001 і ?barcode=4820000000017 знаходять товари за
вашими кодами — точний збіг, без урахування регістру. До 500 значень через кому за раз (більше —
422), тож каталог можна зіставляти пачками. Разом одне з одним або з pids/product_id вони звужують
результат; нічого не знайдено — порожній список. У /query: "filter": { "sku": ["TS-001", "TS-002"] }.
У stock по кожному складу: in_stock — скільки доступно для продажу (без зарезервованого),
quantity — скільки є фізично.
Акції: stock[].promotion — акція, яку HugeProfit підставить у формі продажу для цього товару на
цьому складі, або null: з найвищим пріоритетом серед акцій на основну ціну, а якщо таких немає — серед
акцій на додаткові ціни. Акція на додаткову ціну рахується від її значення в товарі; якщо в товару цієї
ціни немає, акції теж немає. Акція потрапляє сюди, лише якщо знижує ціну; зміни акцій видно із затримкою
до хвилини. Щоб продаж зарахувався до акції, передайте її id у продаж — див. Продаж за акцією.
| Поле | Опис |
|---|---|
id, name |
Акція |
discount_type, discount_value |
percent — знижка у відсотках, fixed — на суму, new_price — нова ціна |
price_type |
Від якої ціни акція: null — основна ціна, інакше назва додаткової ціни ("Опт") |
price_before |
Ціна без акції: основна або ця додаткова ціна товару |
price |
Ціна за акцією: її показуйте покупцеві й передавайте в продаж |
ends_at |
Кінець акції (UTC); null — безстрокова |
sale_price — ціна зі знижкою: окремо задана ціна продажу, а якщо її немає — ціна акції на основну
ціну; null — знижки немає.
type — simple, variation (один рядок варіативного товару — групуйте їх за parent_id),
bundle або service. У комплекту також є bundle_items — склад по складах: для комплекту на
складі bundle_warehouse_id береться quantity товару product_id зі складу warehouse_id.
GET /products/{id}/similar повертає { "product_ids": [...] } — інші товари з тієї ж групи
«схожих товарів», налаштованої в HugeProfit; порожній список, якщо товар не в групі.
Об'єкт товару
{
"id": 111237, "name": "Футболка", "sku": "TS-001", "barcode": "7836...",
"unit": "units", "type": "simple", "parent_id": null,
"brand": null, "category_id": 18726,
"category_path": [ { "id": 18726, "name": "Одяг" } ],
"attributes": [], "dimensions": null, "min_stock": 0, "uktzed": null,
"extra": {},
"stock": [
{ "warehouse_id": 8645, "warehouse_name": "Основний", "in_stock": 4,
"quantity": 4, "cost_price": "5.00", "price": "6.00", "sale_price": "5.40",
"promotion": { "id": 12, "name": "Осінній розпродаж", "discount_type": "percent",
"discount_value": 10, "price_type": null, "price_before": "6.00", "price": "5.40",
"ends_at": "2026-10-31T21:59:59" },
"sku": "TS-001" }
]
}
Створення товарів¶
POST /products з { "products": [...] } лише створює. Передайте name (щонайменше 2 символи) і за
потреби sku, barcode, description, category (назва або шлях ["Одяг", "Футболки"]), brand,
unit, images (URL), extra (див. нижче) і stock — [{ "warehouse_id", "quantity", "price", "cost_price" }].
Без stock або без warehouse_id у рядку товар створюється на першому складі зі списку GET /warehouses.
idу тілі —422: наявний товар змінюють черезPUT.- Товар із таким самим
skuабоbarcodeуже є (безsku— також із такою самою назвоюname) —409зdetails.product_id. Той самий товар двічі в одному запиті —422. - Помилка вказує товар за його позицією:
details.index. Тоді не створюється нічого.
Відповідь — 201 зі створеними товарами. Якщо частину зберегти не вдалося, meta.failed — їхня кількість.
Зміна товарів¶
PUT /products/{id} (або PUT /products з { "products": [{ "id": 1, ... }] }) змінює лише передані
поля, решта лишається як є. Змінити тільки опис:
| Поле | Опис |
|---|---|
name |
Щонайменше 2 символи |
description, unit |
Як в об'єкті товару |
category |
Назва або шлях ["Одяг", "Футболки"]; відсутні категорії створюються |
brand |
Назва бренду; null або "" прибирає бренд |
barcode |
До 30 символів; якщо він в іншого товару — 409 з details.product_id |
extra |
Додаткові поля, зливаються з полями товару, див. нижче |
stock |
[{ "warehouse_id", "quantity", "price", "cost_price", "comment" }] — не передане значення не змінюється |
extra — { "Матеріал": "бавовна" }: ключ збігається з наявним додатковим полем без урахування
регістру, новий ключ додає поле, null або "" видаляє його; не передані поля лишаються. Додаткові ціни —
в extra.custom_price: { "custom_price": { "Опт": 120 } }, лише числа.
stock — { "warehouse_id": 8645, "price": 199 } змінює там лише ціну: кількість і собівартість
лишаються. comment — примітка для історії залишків. Склад, де товару ще немає, додається.
cost_price має бути більше 0, і його не можна задати, поки HugeProfit рахує собівартість із поставок
або складових собівартості (422).
Для варіації name, description, category і brand змінюються для всієї групи; ключ extra, що
збігається з назвою атрибута варіації, — 422. sku, attributes і images через PUT не змінюються:
вони й будь-які інші поля — 422.
Запит перевіряється повністю до збереження: за будь-якої помилки не зберігається нічого, а details.id
вказує товар. Невідомий або видалений id — 404 з details.ids. Відповідь — змінені товари.
Швидке оновлення залишків¶
POST /product_stock приймає масив { product_id, warehouse_id, quantity?, price?, cost_price?,
comment? } — ті самі значення, що й stock у PUT, і не передане значення теж не змінюється:
[{ "product_id": 111237, "warehouse_id": 8645, "price": 199 }] змінює лише ціну. Кожен елемент
застосовується окремо; відповідь — { "updated": [id], "errors": [{ "product_id", "error" }] }.
Зв'язок товар ↔ маркетплейс¶
Прив'язує локальний product_id до remote_id маркетплейса в межах інтеграції, щоб синк
залишків/цін знав, якому лістингу відповідає товар.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/product_sync |
product_sync:read |
POST |
/product_sync |
product_sync:write |
DELETE |
/product_sync |
product_sync:write |
Фільтри GET: integration_id, product_id (кожен застосовується лише якщо переданий).
Тіло POST/DELETE: { "bulk": [ ... ] } — елементи POST потребують
product_id+remote_id+integration_id; DELETE — integration_id+remote_id. POST повертає
результати по елементах та статистику.
{ "product_id": 111230, "integration_id": 359, "remote_id": "SKU-1",
"created_at": "2026-07-08T08:20:10" }
Categories (категорії)¶
| Метод | Шлях | Scope |
|---|---|---|
GET |
/categories |
categories:read |
GET |
/categories/{id} |
categories:read |
POST |
/categories |
categories:write |
DELETE |
/categories |
categories:write |
DELETE |
/categories/{id} |
categories:write |
?category_id= фільтрує до однієї; ?tree=1 вкладає дочірні. Тіло POST:
{ "categories": [ { "name", "parent_id"?, "id"? } ] } (id оновлює замість створення).
Назва унікальна серед дочірніх однієї категорії без урахування регістру («Худі» може бути і в «Чоловіче», і в «Жіноче»):
створення вже зайнятої назви повертає id наявної, а оновлення в зайняту назву чи у власну підкатегорію — 400.
Clients (клієнти)¶
| Метод | Шлях | Scope |
|---|---|---|
GET |
/clients |
clients:read |
GET |
/clients/{id} |
clients:read |
POST |
/clients |
clients:write |
DELETE |
/clients |
clients:write |
DELETE |
/clients/{id} |
clients:write |
GET/POST/PUT/DELETE |
/clients/tags |
clients:read/clients:write |
Фільтри GET: id, ids (csv), phone, phone_contains, updated_at (unix — клієнти,
змінені після цього), with_debt=1 (вбудовує заборгованість), with_chats=telegram (вбудовує
чати в месенджерах). Тіло POST: { "clients": [ ... ] } (для створення потрібен телефон; id
оновлює). Теги повертаються вкладеним масивом tags.
Пошук за телефоном: phone знаходить клієнтів за повним номером у будь-якому записі —
380671234567, +380671234567, 0671234567 і +38 (067) 123-45-67 знаходять того самого
клієнта. phone_contains знаходить клієнтів, у номері яких є вказані цифри (останні цифри або
будь-яка інша частина, напр. ?phone_contains=4567); потрібно щонайменше 3 цифри, менше — 422.
Фільтри можна поєднувати. Один номер може бути в кількох клієнтів, тому результат — завжди
список. У /query передавайте "filter": { "phone": "0671234567" } або
"filter": { "phone_contains": "4567" }.
Чати в месенджерах (GET /clients і GET /clients/{id}): with_chats приймає типи
месенджерів через кому — поки що підтримується лише telegram, будь-що інше дає 422. Тоді
кожен клієнт отримує масив chats (порожній, якщо чатів немає), від нових до старих: type,
integration_id (підключений бот, якому належить чат) і chat_id (рядок; для Telegram —
chat_id для Bot API). Бот може написати клієнту, лише якщо той уже писав саме цьому боту,
тому використовуйте chat_id разом з його integration_id. У /query передавайте
"filter": { "with_chats": "telegram" } (або ["telegram"]).
Об'єкт клієнта
{
"id": 105424, "is_active": true, "type": "person",
"first_name": "Світлана", "last_name": "П.", "phone": "380...",
"email": null, "company": null, "company_code": null,
"discount": 0, "balance": "0.00", "total_amount": "0.00",
"birth_day": "1995-12-16T00:00:00", "city": null, "region": null,
"extra": {}, "tags": [ { "id": 5, "name": "VIP", "color": "#ff0000" } ],
"chats": [ { "type": "telegram", "integration_id": 512, "chat_id": "123456789" } ],
"created_at": "2023-06-17T05:59:19", "updated_at": "2026-04-23T10:21:58"
}
Теги (/clients/tags): GET — список тегів (або теги клієнта з ?client_id=);
POST { name, color } створює; PUT прив'язує { client_id, tag_id } або редагує
{ tag_id, name?, color? }; DELETE відв'язує { client_id, tag_id } або видаляє { tag_id }.
Sales (продажі)¶
Продажа — це один об'єкт із вкладеним масивом items. Записи проходять через справжній
рушій продажів (залишки, гроші, фіскальні чеки) — чек і новий баланс повертаються в meta.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/sales |
sales:read |
GET |
/sales/{id} |
sales:read |
POST |
/sales |
sales:write |
PUT |
/sales |
sales:write |
DELETE |
/sales або /sales/{id} |
sales:write |
POST |
/sales/{id}/waybill |
delivery:write + sales:write |
GET |
/sales/{id}/waybill/label |
delivery:read + sales:read |
Фільтри GET: date_from/date_to (unix; дефолт — останні 90 днів), client_id,
warehouse_id, status, refund=1 (лише повернення), external_id (ваш номер замовлення,
див. нижче), updated_from/updated_to (unix, за
останньою зміною), after_id (разом з updated_from, див. нижче). ?include=client вбудовує клієнта.
Опитування змін: ?updated_from=<unix> повертає продажі, змінені відтоді, — нові, відредаговані
й ті, у яких змінився статус (зокрема від відстеження доставки), від найстарішої зміни. Запам'ятайте
updated_at (як unix) і id останнього отриманого продажу й передайте їх наступного разу як
updated_from і after_id: список продовжиться одразу після цього продажу, навіть якщо багато
продажів змінилися в ту саму секунду. Без after_id межа включна.
З updated_from або external_id і без date_from вікно 90 днів не діє.
Видалений продаж зі списку зникає — для таких є вебхук order_delete.
Об'єкт продажі
{
"id": 4605, "external_id": "site-1001", "order_number": "20072602", "status": "saled",
"sold_at": "2026-07-20T08:28:59", "amount": "100.00", "sale_amount": "100.00",
"prepaid": "20.00", "discount": "0.00", "currency": "2", "fee": "5.00",
"account_id": 2, "client_id": null, "channel_ids": [867],
"expense_ids": [],
"items": [
{ "id": 5436, "product_id": 107720, "warehouse_id": 8562,
"sku": null, "barcode": "7739...", "product_name": "Товар",
"quantity": 1, "price": "100.00", "cost_price": "1.00",
"amount": "100.00", "profit": "94.00", "is_refund": false }
]
}
Тіло створення/оновлення містить заголовок продажу та масив items. Обов'язкові: account_id
(рахунок, на який надходять гроші) і для кожної позиції product_id, warehouse_id, quantity (> 0),
price. meta відповіді може містити фіскальний чек і новий баланс рахунку.
{ "external_id": "site-1001", "account_id": 2, "channel_ids": [867], "discount": 10,
"items": [{ "product_id": 107720, "warehouse_id": 8562, "quantity": 2, "price": "100.00" }] }
PUT приймає те саме тіло плюс id продажу й замінює продаж повністю, як збереження форми продажу:
непередане поле скидається (без status продаж стає saled). Лишаються тільки external_id, order_number
і витрати, що вже є в продажу.
Усі поля запиту
| Поле | Тип | Обов'язкове | Опис |
|---|---|---|---|
id |
int | лише PUT |
Продаж, що редагується (приймається й oid) |
items |
array | так | Позиції продажу, див. items[] нижче |
account_id |
int | так | Рахунок, на який надходять гроші (accounts у довіднику); валюта продажу — валюта цього рахунку. На нього надходить sale_amount мінус передоплата й комісія рахунку, незалежно від статусу |
external_id |
string | ні | Ваш номер замовлення, до 100 символів; лише POST — див. Безпечний повтор запиту |
status |
string | ні | Статус продажу, до 20 символів, див. статуси нижче. Дефолт — saled |
custom_status |
string | ні | Лише з status: "delivery": продаж отримує цей статус замість delivery |
client_id |
int | ні | Клієнт (Clients). Не передано — продаж без клієнта |
channel_ids |
int[] | ні | Канали продажу (sales_channels у довіднику); приймається й один channel_id: 867. Не передано — технічний канал 1 |
amount |
number | ні | Сума quantity × price позицій; рахується сама, див. нижче |
discount |
number | ні | Знижка на продаж. Дефолт 0 |
discount_type |
string | ні | % (дефолт) — відсоток, stable — фіксована сума у валюті продажу |
sale_amount |
number | ні | Скільки сплачує клієнт. Дефолт — amount мінус знижка |
prepaid |
number | ні | Передоплата. Дефолт 0 |
prepaid_account_id |
int | з prepaid |
Рахунок, на який надходить передоплата. Без нього передоплата лише записується в продаж, а весь sale_amount іде на account_id |
fee |
number | ні | Комісія маркетплейсу / каналу за цей продаж у валюті продажу; зменшує прибуток. З налаштувань каналу не рахується — передавайте суму самі |
cash_from_client |
number | ні | Готівка, отримана від покупця; з неї рахується решта у фіскальному чеку |
comment |
string | ні | Коментар, до 300 символів |
extra |
object | ні | Додаткові поля продажу: { "Джерело": "Instagram" }. Ключі — назви додаткових полів продажу з ваших налаштувань |
delivery |
object | ні | Адреса Нової Пошти клієнта — відділення або адреса для кур'єра, див. поля доставки нижче. Потрібен client_id |
client_delivery_id |
int | ні | Уже збережена адреса клієнта замість delivery; невідомий id ігнорується |
delivery_info |
string | ні | Служба доставки, до 200 символів: 1 — Нова Пошта, 3 — Укрпошта, 6 — Rozetka Delivery, 24 — Meest, justin, delivery_auto, pickup, city-delivery, outcity-delivery, international; поза Україною — UPS, DHL, post office, other. Після двокрапки можна додати примітку: "1: Відділення 5" |
tracking_number |
string | ні | ТТН, створена поза HugeProfit, до 20 символів. Прив'язується до перевізника, лише якщо в delivery_info тільки код ("1"), без примітки |
expenses |
array | ні | Витрати, що створюються разом із продажем, див. expenses[] нижче |
items[]
| Поле | Тип | Обов'язкове | Опис |
|---|---|---|---|
product_id |
int | так | Товар |
warehouse_id |
int | так | Склад, з якого списується товар (warehouses у довіднику). Один товар із двох складів — дві позиції |
quantity |
number | так | Кількість, більше 0, можна дробову (0.5) |
price |
number | так, крім позиції з promotion_id |
Ціна за одиницю, за якою продається позиція |
promotion_id |
int | ні | Акція, за якою продається позиція, див. Продаж за акцією |
discount |
number | ні | Знижка позиції у відсотках, для відображення: позиція все одно продається за price. Знижка продажу % на таку позицію не діє |
default_price |
number | ні | Ціна за одиницю до знижки позиції, показується поруч із discount. Дефолт — price |
price_type |
string | ні | Підпис ціни, наприклад назва додаткової ціни ("Опт"), до 255 символів. З promotion_id за замовчуванням — назва акції |
uktzed |
string | ні | Код УКТ ЗЕД товару для фіскального чека |
expenses[] — кожна витрата зменшує прибуток продажу. У PUT передавайте лише нові витрати.
| Поле | Тип | Обов'язкове | Опис |
|---|---|---|---|
amount |
number | так | Сума витрати |
category |
int | ні | Категорія витрат (expense_categories у довіднику) |
account_id |
int | ні | Рахунок, з якого сплачується витрата. Дефолт — account_id продажу |
expense_name |
string | ні | Назва витрати |
mid |
int | ні | Склад, до якого належить витрата |
Статуси
status |
Що відбувається |
|---|---|
saled (дефолт) |
Завершений продаж: товар списується зі складу |
reserve_sale |
Резерв: in_stock зменшується, quantity лишається. Залишок не перевіряється |
delivery |
Продаж у доставці; з custom_status продаж отримує цей статус |
| будь-який інший рядок | Зберігається як є: delivering, cod, arrived або ваш власний статус |
Суми рахуються так само, як у формі продажу HugeProfit:
| Поле | Опис |
|---|---|
amount |
Сума продажу — сума quantity × price позицій. Не передано — порахуємо самі; якщо передаєте, вона має збігатися з цією сумою до копійки, інакше 422 з правильною сумою в details.expected |
discount, discount_type |
Знижка на продаж: % (дефолт) або stable — фіксована сума. Позиції зі своєю discount до бази % не входять |
sale_amount |
Скільки сплачує клієнт. Дефолт — amount мінус знижка |
Гроші й кількості можна передавати числом або рядком ("100.50", "100,50"); будь-що інше, від'ємне
число, nan чи inf — 422.
Якщо позиції не вистачає на складі, де не дозволено мінус, продаж не створюється, а відповідь —
422 з тим, чого бракує, як і для запуску рецепта:
{ "success": false, "error": { "code": "validation_error", "message": "not enough stock",
"details": { "shortages": [ { "product_id": 107720, "warehouse_id": 8562,
"required": 2, "in_stock": 1 } ] } } }
Після редагування продаж отримує новий id
PUT /sales (і редагування продажу в HugeProfit) створює його заново під новим id; відповідь
містить новий, а GET /sales/{старий id} відтоді — 404. Знаходьте продаж за external_id або
беріть новий id з вебхука order_update — у ньому є previous_id.
items[].warehouse_id — склад, з якого списується товар. Поля доставки (усі необов'язкові):
| Поле | Опис |
|---|---|
status |
Статус продажу: saled (дефолт), reserve_sale, delivery, delivering, cod, arrived або ваш власний статус |
delivery |
Адреса Нової Пошти клієнта — відділення { "carrier": "nova_poshta", "warehouse_ref": "…" } (ref з /delivery/warehouses) або адреса для кур'єра { "carrier": "nova_poshta", "settlement_ref": "…", "street": "Київська", "house": "14", "flat": "285" } (flat необов'язковий; settlement_ref і street — з /delivery/settlements і /delivery/streets). Потрібен client_id; адреса зберігається клієнту (наявна використовується повторно), а продаж отримує delivery_info: "1" |
client_delivery_id |
Уже збережена адреса клієнта замість delivery |
delivery_info |
Код служби доставки: 1 — Нова Пошта, 3 — Укрпошта, 24 — Meest, … |
tracking_number |
ТТН, створена поза HugeProfit. Поки продаж у статусі доставки (delivery, delivering, arrived), статус посилки відстежується автоматично й переводить продаж далі |
Продаж за акцією¶
Щоб продаж зарахувався до акції — її лімітів, бюджету й статистики в HugeProfit, — передайте в позиції
promotion_id зі stock[].promotion.id товару або іншої акції, що діє на цей товар
на цьому складі (як у списку цін форми продажу). Ціну рахує HugeProfit — від основної ціни або, для акції
на додаткову ціну, від неї:
priceможна не передавати — підставимоpromotion.price;- переданий
priceмає збігатися з ціною акції до копійки, інакше422 promotion_price_mismatchз правильною ціною вdetails.expected; amount(якщо передаєте) рахуйте з ціни акції.
{ "account_id": 2, "items": [{ "product_id": 107720, "warehouse_id": 8562, "quantity": 2, "promotion_id": 12 }] }
Без promotion_id позиція продається за price, і акція її не враховує, навіть якщо ціна збігається
з акційною. Відмова — 422 з одним із кодів нижче; якщо помилку можна прив'язати до позиції, в
details є її product_id, warehouse_id і promotion_id.
code |
Причина | Що робити |
|---|---|---|
promotion_inactive |
Акцію вимкнули, вона закінчилась або ще не почалась | Перечитайте товар і покажіть покупцеві актуальну ціну |
promotion_not_applicable |
Акція не діє на цей товар на цьому складі, у товару немає її додаткової ціни або вона не знижує ціну | Те саме |
promotion_price_mismatch |
price не збігається з ціною акції |
Візьміть ціну з details.expected |
promotion_limit_usage |
Вичерпано ліміт використань акції | Продайте без акції |
promotion_limit_client |
Клієнт client_id вичерпав свій ліміт за акцією |
Продайте без акції |
PUT /sales перевіряє акцію так само: якщо вона вже закінчилась, передайте позицію без promotion_id —
ціна збережеться, але продаж вийде з обліку акції.
Безпечний повтор запиту (external_id)¶
Якщо відповідь на POST /sales загубилася (таймаут, обрив з'єднання), невідомо, чи створився
продаж, а повтор наосліп створить другий продаж і вдруге спише залишок. Передавайте свій номер
замовлення в external_id (рядок до 100 символів):
- перший запит створює продаж, і
external_idповертається в ньому; - повтор із тим самим
external_idнічого не створює й відповідає409з продажем, який уже є, — заберіть його черезGET /sales/{details.sale_id}і працюйте далі:
{ "success": false, "error": { "code": "conflict", "message": "a sale with this external_id already exists",
"details": { "sale_id": 4605, "external_id": "site-1001" } } }
external_id унікальний у межах API-ключа: два ключі (наприклад, два сайти) можуть кожен надіслати
свій 1001. Він лишається за продажем після редагування, приходить в об'єкті продажу й у вебхуках
order_*, а GET /sales?external_id=site-1001 знаходить продаж за ним. Після видалення продажу
номер знову вільний. Задається лише під час створення — PUT його не змінює.
ТТН Нової Пошти¶
POST /sales/{id}/waybill створює ТТН Нової Пошти для продажу через підключений акаунт Нової
Пошти — те саме, що Створити ТТН у картці продажу. Номер ТТН зберігається в продажі, продаж
переходить у delivering, а далі HugeProfit відстежує статус посилки. Продажу потрібні
client_id (з ім'ям, прізвищем і телефоном) та адреса Нової Пошти (delivery під час створення
продажу): відділення або адреса для кур'єра — тоді посилка йде з відділення відправника до дверей
отримувача.
| Поле | Обов'язкове | Опис |
|---|---|---|
carrier_account_id |
так | Акаунт Нової Пошти: id з carrier_accounts у Reference |
sender_id |
якщо в акаунта кілька відправників | senders[].id цього акаунта |
cod_amount |
ні | Накладений платіж, який сплачує отримувач. Не передано — без накладеного платежу |
cod_type |
ні | cash_on_delivery (дефолт) або payment_control («Контроль оплати» Нової Пошти, потрібен договір з Новою Поштою) |
declared_value |
ні | Оголошена вартість. Дефолт — sale_amount |
payer |
ні | Хто платить за доставку: recipient (дефолт) або sender |
payment_method |
ні | cash (дефолт) або non_cash |
weight, length, width, height |
ні | Вага посилки в кг і розміри в см. Дефолт — 1 кг, 10×10×10 |
seats |
ні | Кілька місць: [{ "weight", "length", "width", "height" }, …] замість полів вище |
description |
ні | Опис відправлення, до 120 символів. Дефолт — назви товарів продажу |
additional_info |
ні | Додаткова інформація, до 100 символів |
Відповідь 201:
{ "tracking_number": "20450000000001", "sale_id": 4605, "carrier": "nova_poshta",
"carrier_account_id": 431, "sender_id": "3f6c1a20-…_3f71b5c8-…",
"cost": "70", "estimated_delivery_date": "2026-10-18" }
cost — вартість доставки, розрахована Новою Поштою. Помилки:
404— продажу немає або це чек повернення.409— у продажу вже є ТТН, він повернений або ТТН для нього саме створюється: повтор запиту не створить другу ТТН.422validation_error— у продажу немає клієнта чи адреси Нової Пошти, акаунт або відправника не знайдено чи не налаштовано, некоректне поле.422carrier_error— Нова Пошта відхилила ТТН; уmessageїї текст.500зdetails.tracking_number— ТТН створено в Новій Пошті, але не збережено в продажу. Не повторюйте запит (це створить ще одну ТТН) — зверніться до підтримки.
Наклейка ТТН¶
GET /sales/{id}/waybill/label повертає наклейку ТТН продажу (маркування 100×100) у PDF
(Content-Type: application/pdf) — те саме, що Друк у HugeProfit. Працює для будь-якої ТТН
продажу, створеної через підключений акаунт доставки, а не лише через API. Помилки — у звичайному
JSON-конверті:
404— продажу немає або в нього немає ТТН;422carrier_error— служба доставки не віддала наклейку: ТТН не з підключеного акаунта.
curl https://crm.h-profit.com/bapi-v2/sales/4605/waybill/label \
-H "Authorization: hp_live_your_key_here" -o label.pdf
Orders (замовлення з маркетплейсів)¶
Вхідні замовлення із зовнішніх каналів (remote_orders) до перетворення на продаж. sale_id
з'являється після створення продажі (is_linked).
| Метод | Шлях | Scope |
|---|---|---|
GET |
/orders |
orders:read |
GET |
/orders/{id} |
orders:read |
POST |
/orders |
orders:write |
PUT |
/orders/{id} |
orders:write |
Фільтри GET: order_id, integration_id, status, local_status, start/end
(unix), linked (unlinked [дефолт] | linked | all). ?include=client,sale вбудовує
клієнта і, якщо пов'язана, продаж. POST приймає зовнішнє замовлення і резервує залишки.
GET /orders/{id} також повертає tracking_number і sale_status — номер ТТН і статус продажу,
на який перетворилося замовлення (null, поки воно не пов'язане).
PUT /orders/{id} змінює замовлення, створене цим самим ключем (будь-яке інше — 404):
{ "status": "cancelled" }скасовує його і знімає резерв залишків. Повторний виклик безпечний — залишок двічі не повертається. Продаж, уже створений із замовлення, не змінюється.{ "order_text": "1024" }задає номер замовлення, який показується в списку замовлень HugeProfit (зберігається вinfo.order_text).
Обидва повертають оновлене замовлення; інший status або порожнє тіло — 422.
Delivery (доставка)¶
Пошук міст і відділень Нової Пошти та Meest — наприклад, щоб вибрати місто й відділення для адреси доставки, — а також населених пунктів і вулиць Нової Пошти для адреси кур'єра.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/delivery/cities |
delivery:read |
GET |
/delivery/warehouses |
delivery:read |
GET |
/delivery/settlements |
delivery:read |
GET |
/delivery/streets |
delivery:read |
GET /delivery/cities?carrier=nova_poshta&q=Київ— до 20 міст{ ref, name }, у назві яких єq; безq— перші 20 за абеткою. В однойменних населених пунктів область або район уже є в назві:Олександрівка (Миколаївська обл.).GET /delivery/warehouses?carrier=nova_poshta&city_ref=…— відділення міста{ ref, number, name }за зростанням номера:number=5знаходить саме №5 (а не №50),qфільтрує за частиною назви,limit— до 500 (дефолт 50).- Meest — ті самі два виклики з
carrier=meestіaccount_idпідключеного акаунта Meest (зcarrier_accountsу Reference); пошук іде наживо через цей акаунт.GET /delivery/cities?carrier=meest&account_id=…&q=Київповертає{ ref, name },GET /delivery/warehouses?carrier=meest&account_id=…&city_ref=…—{ ref, number: null, name }.account_id, що не є вашим акаунтом Meest, дає порожній список.
Невідомий carrier, відсутній city_ref або account_id для Meest — 422.
{ "ref": "8d5a980d-391c-11dd-90d9-001a92567626", "name": "Київ" }
{ "ref": "1ec09d88-e1c2-11e3-8c4a-0050568002cf", "number": 1,
"name": "Відділення №1: вул. Пирогівський шлях, 135" }
Адреса для кур'єра (лише Нова Пошта, пошук наживо в Новій Пошті, limit — до 500, дефолт 20):
GET /delivery/settlements?carrier=nova_poshta&q=Кременчук— населені пункти{ ref, name, city_ref, address_delivery }, зокрема села без відділення.refпередається вdelivery.settlement_refпродажу;address_delivery: false— Нова Пошта не доставляє туди на адресу;city_refпідходить для/delivery/warehouses.GET /delivery/streets?carrier=nova_poshta&settlement_ref=…&q=Київ— вулиці{ name, street }: уdelivery.streetпередайтеstreet,name(з типом вулиці) — для показу.
Відсутній q чи settlement_ref або невідомий settlement_ref — 422; Нова Пошта не відповіла —
502 carrier_error, повторіть пізніше.
{ "ref": "e71a26ea-4b33-11e4-ab6d-005056801329", "name": "м. Кременчук, Кременчуцький р-н, Полтавська обл.",
"city_ref": "8d5a9813-391c-11dd-90d9-001a92567626", "address_delivery": true }
{ "name": "вул. Київська", "street": "Київська" }
Media (хостинг зображень)¶
Завантажуйте зображення в HugeProfit і отримуйте публічні посилання, щоб використовувати їх будь-де.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/media |
media:read |
POST |
/media |
media:write |
POST /media приймає multipart/form-data, до 5 файлів; лише PNG, JPEG, WebP і GIF (тип
перевіряється за вмістом, а не за розширенням; SVG не приймається). Повертає 201 і масив
завантажених файлів. Інший тип файлу, понад 5 файлів або жодного — 422. Файли враховуються в
ліміті сховища акаунта.
GET /media повертає файли акаунта (зокрема завантажені в HugeProfit), від найновіших;
limit/offset, загальна кількість — у meta.total.
{ "id": 5121, "url": "https://…/bfiles/public/…", "name": "banner", "ext": "png",
"size": 48213, "created_at": "2026-10-06 12:00:00" }
Об'єкт замовлення
{
"id": 3510949, "order_id": "9231", "integration_id": 621,
"status": "completed", "name": "Order ID: 9231", "price": "3101.00",
"currency": "UAH", "created_at": "2026-07-07T10:19:55",
"first_name": "Ліна", "phone": "+380...", "email": "...",
"address": { "city": "…", "address_1": "…" },
"items": [ { "id": 7759, "name": "…", "quantity": 1, "price": 518 } ],
"client_id": 36247, "sale_id": null, "is_linked": false
}
Shipments (поставки)¶
Лише читання. Поставка/приймання — один об'єкт із вкладеним масивом items.
| Метод | Шлях | Scope |
|---|---|---|
GET |
/shipments |
shipments:read |
GET |
/shipments/{id} |
shipments:read |
Фільтри GET: date_from/date_to (unix, за датою доставки), status, warehouse_id.
?include=supplier,expenses вбудовує постачальника та пов'язані витрати.
payments — усі оплати за товар, від найстарішої, зокрема відкладені та часткові (оплата доставки
сюди не входить, див. delivery_expense_id). expense_id веде до Expenses;
усі вони також доступні через GET /expenses?shipment_id=….
Об'єкт поставки
{
"id": 11191, "name": "Поставка №…", "status": "complete",
"warehouse_id": 8549, "warehouse_name": "Основний", "supplier_id": null,
"amount": "100.00", "quantity": 10, "currency": "2",
"delivered_date": "2026-05-21T07:42:00", "expense_id": 1115,
"payments": [
{ "expense_id": 1115, "date": "2026-06-16T09:10:00", "amount": "100.00",
"account_id": 14459, "category_id": 11, "name": "Оплата поставки" }
],
"items": [
{ "id": 5020, "product_id": 104641, "product_name": "…", "sku": "c2b-6i3",
"quantity_shipped": 10, "quantity_received": 10, "amount": "100.00",
"cost_price": "10.00" }
]
}
Expenses (витрати)¶
| Метод | Шлях | Scope |
|---|---|---|
GET |
/expenses |
expenses:read |
GET |
/expenses/{id} |
expenses:read |
POST |
/expenses |
expenses:write |
Фільтри GET: date_from/date_to (unix; дефолт — останній 31 день), category_id, shipment_id
(оплати поставки; без дат — усі, незалежно від дати).
?include=warehouse вбудовує склад. Тіло POST:
{ account_id, category_id, amount, name, comment?, warehouse_id?, product_id?, shipment_id?, order_id?, type?, date? };
новий баланс рахунку повертається в meta.
{ "id": 1115, "account_id": 14459, "category_id": 2, "category_name": "Доставка",
"warehouse_id": 8549, "name": "…", "amount": "30.00", "balance": "116721.08",
"type": "onetime", "created_at": "2026-06-29T08:32:56" }
Productions (виробництво)¶
Виробництво — це рецепт: components (спожиті товари) + expenses → results
(вироблені товари).
| Метод | Шлях | Scope |
|---|---|---|
GET |
/productions |
productions:read |
GET |
/productions/{id} |
productions:read |
POST / PUT |
/productions |
productions:write |
DELETE |
/productions або /productions/{id} |
productions:write |
POST |
/productions/{id}/run |
productions:write |
GET |
/productions/history |
productions:read |
GET/POST/DELETE |
/productions/categories |
productions:read/productions:write |
Фільтри GET: start/end (unix), category_id, is_deleted. ?include=category
вбудовує категорію.
Об'єкт виробництва
{
"id": 49, "name": "Рецепт 787", "status": "created", "category_id": null,
"amount": "0.00", "quantity": 50, "result_product_id": 107511,
"result_warehouse_id": 8614, "use_real_cost": true,
"components": [ { "id": 115, "product_id": 107513, "warehouse_id": 8614,
"name": "Сировина", "quantity": 1, "cost": "0.00" } ],
"results": [], "expenses": []
}
Запуск рецепта¶
POST /productions/{id}/run з { "quantity": 2.5, "account_id": 14459 } запускає рецепт
quantity разів — так само, як кнопка Виробити в HugeProfit: списує компоненти зі складів,
оприбутковує результати й записує витрати рецепта.
quantity— скільки разів запустити рецепт (можна дробове, > 0).account_id— рахунок, з якого сплачуються витрати рецепта (зaccountsу Reference); потрібен, лише якщо в рецепті є витрати.
Повертає 201 із запуском (той самий об'єкт, що в /productions/history):
{ "id": 812, "production_id": 49, "product_id": 107511, "warehouse_id": 8614, "category_id": null,
"quantity": 2.5, "net_price": "20.00", "products_prices": "50.00", "expenses_amount": "0.00",
"total": "50.00", "type": "production", "created_at": "2026-10-06T12:00:00" }
Якщо компонента не вистачає на складі, де мінус заборонений, нічого не запускається, а
відповідь — 422 з тим, чого бракує:
{ "success": false, "error": { "code": "validation_error", "message": "not enough stock",
"details": { "shortages": [ { "product_id": 107513, "warehouse_id": 8614,
"required": 120, "in_stock": 100 } ] } } }
Інші 422: quantity відсутня або не додатна, немає account_id для рецепта з витратами,
рецепт без результатів. Невідомий або видалений рецепт — 404.
Write-offs (списання)¶
Списання товару зі складу (брак, втрати, власні потреби) — як документ Списання в HugeProfit, створюється й проводиться одним викликом.
| Метод | Шлях | Scope |
|---|---|---|
POST |
/write_offs |
write_offs:write |
{ "warehouse_id": 8614, "category_id": 2, "comment": "Пошкоджено при доставці",
"items": [ { "product_id": 107513, "quantity": 3 } ] }
category_id — категорія списання (write_off_categories у Reference); кожен
товар — один раз. Сума рахується за собівартістю на складі. Повертає 201:
{ "id": 77, "warehouse_id": 8614, "category_id": 2, "status": "completed", "amount": "30.00",
"quantity": 3, "comment": "Пошкоджено при доставці", "created_at": "2026-10-06T12:00:00",
"items": [ { "product_id": 107513, "quantity": 3, "quantity_was": 100, "quantity_became": 97 } ] }
Залишку не вистачає (на складі без мінуса) — 422 з details.shortages, як у запуску
виробництва, і нічого не списується. Порожній items, повтор товару або не додатна кількість —
422; невідома категорія — 404.