Списки, поля, одиниці
Спільні правила для всіх маршрутів: параметри списків, типи даних у JSON, як закодовані гроші й кількість, як працює оновлення.
Параметри списків
| Параметр | За замовчуванням | Що робить |
|---|---|---|
page | 1 | Номер сторінки з 1. Значення менше 1 вважається за 1. |
per-page | 20 | Розмір сторінки, максимум 100 (більше значення обрізається до 100). Пишеться через дефіс: per_page у запиті ігнорується. |
order | id | Сортування: order=updated_at сортує за зростанням, order=-updated_at за спаданням. Одне поле. |
fields | усі | Які колонки читати з бази, через кому. |
expand | немає | Підтягнути пов’язані записи, через кому. |
filter[...] | немає | Див. розділ Фільтри. |
is_archived=true | немає | Сховати архівні записи. |
Відповідь списку
{
"items": [ ... ],
"total": 318, // скільки записів за фільтрами всього
"page": 2,
"per_page": 100 // у відповіді — з підкресленням
}- ●Сторінка за межами повертає порожній
itemsз правильнимtotal, а не помилку. - ●Сторінок:
ceil(total / per_page). - ●Деякі довідники (
/lookup,/extra-fields,/account/our,/balance) віддають увесь перелік безtotal.
order, fields чи filter, невідомий оператор або зв’язка фільтра повертають 400 bad_request з поясненням, напр. «Некоректний фільтр "filter[first_name;bogus]": невідомий оператор». Список без фільтра у відповідь на одруківку не повернеться.id і беріть filter[id;gt]=<останній id> замість збільшення page.fields: лише потрібні колонки
GET /api/v1/contact?fields=id,first_name,last_name,updated_at&per-page=100
- ●Працює для списків. Картка (
GET /contact/42)fieldsігнорує й повертає все. - ●Структура відповіді не скорочується: невибрані поля приходять порожніми значеннями свого типу (
"",0,null). Не сприймайте їх як «порожні в базі». - ●Назви такі самі, як у JSON (snake_case). На невідому назву буде 400.
expand: пов’язані записи
Назви зв’язків пишуться з великої літери, як у списку «Пов’язані об’єкти для ?expand=» на сторінці кожної сутності. Через кому; вкладеність через крапку, не глибше 2 рівнів.
GET /api/v1/order/85?expand=Contact,Account,Status GET /api/v1/contact?expand=Owner,Account.Owner,Channels,ContactExtraFields
- ●Без
expandпов’язані об’єкти дорівнюютьnull, є лише їхні*_id. - ●Канали (
Channels) і доп. поля (ContactExtraFieldsтощо) теж читаються лише з expand, і в картці, і в списку. - ●Невідома назва (
ownerз малої) або вкладеність глибше 2 рівнів дає 400 ще до запиту в базу. - ●Список з
expandкоштує 5 очок замість 2. - ●Права ролі діють і тут: зв’язок на сутність, закриту для перегляду (напр.
Accountприaccount.view = denied), приходитьnull; при «лише свої» підтягуються тільки записи, де користувач токена є відповідальним. Імена користувачів (Owner,CreatedBy) видно завжди.
Типи даних у JSON
| Тип у документації | У JSON | Приклад |
|---|---|---|
| id | ціле число або null | 42 |
| ціле | ціле число | 3 |
| рядок | рядок; «≤ N симв.» означає максимальну довжину | "Олена" |
| bool | true / false | true |
| дата-час | рядок RFC 3339 з поясом або null | "2026-10-01T14:32:01+03:00" |
| десяткове (рядок) | рядок з крапкою, щоб не втрачати точність | "41.250000" |
| число | число з дробовою частиною | 12.5 |
| ціле, копійки | сума в мінімальних одиницях валюти | 150000 |
| ціле, ×1000 | кількість з трьома знаками після коми | 2500 |
| масив / об’єкт | вкладені дані | Вкладені дані |
Позначка «лише читання» біля поля означає, що його рахує або ставить сервер (суми позицій, «сплачено», дати виграшу, номер при створенні тощо). У тілі POST/PUT такі поля ігноруються.
Гроші
150000 у гривнях = 1 500,00 грн.- ●Кількість знаків після коми у валюти показує поле
MinorUnitуGET /currency(для UAH, USD, EUR це 2). - ●
exchange_rateдокумента (замовлення, рахунку, угоди) означає курс його валюти до гривні, десяткове рядком. Фіксується на момент документа. У платежу курс інший, до валюти рахунку, див. Платежі. - ●
personal_discountконтакту чи контрагента задається відсотком, числом 0–100, а не копійками.
Перетворення
hryvnias = 150000 / 10 ** currency["MinorUnit"] # 1500.00 kopecks = round(1500.00 * 100) # 150000
Кількість і знижка в позиціях
| Поле | Кодування | Приклад |
|---|---|---|
quantity | ціле ×1000 | 1000 = 1 шт., 2500 = 2,5 кг |
discount | соті частки відсотка | 1000 = 10 % |
discount_amount | копійки | 5000 = 50,00 |
Товар без дробової кількості приймає лише кратне 1000, інакше поверне 422 «Для цього товару дозволена лише ціла кількість».
Дати
- ●У відповідях дати йдуть у RFC 3339 з поясом:
2026-10-01T14:32:01+03:00. - ●У тілі запиту теж RFC 3339 (
2026-10-01T10:00:00+03:00). - ●У фільтрах можна писати
2026-10-01,2026-10-01 14:32:01або RFC 3339 (час кабінету).
Створення й оновлення
POST
Тіло передається як JSON у UTF-8 із заголовком Content-Type: application/json. Відповідь 201 зі створеним записом. Поля «лише читання» ігноруються, так само як id, created_at, updated_at і deleted_at у тілі: ідентифікатор і дати ставить сервер.
PUT: часткове оновлення
- ●Змінюються лише передані поля, решта лишається як була.
- ●Вкладені масиви: якщо ключа немає, масив не змінюється;
channelsіtagsзамінюються повністю; доп. поля оновлюються заfield_id. Деталі в розділі Вкладені дані. - ●Щоб очистити рядкове поле, передайте
""; щоб прибрати посилання, передайтеnull(напр.{"account_id": null}). - ●Одночасні PUT одного запису виконуються по черзі: правки різних полів не губляться, а для одного й того самого поля перемагає останній запит. Поле
versionслужбове.
DELETE
Відповідь 204 без тіла. Після видалення картка (GET /.../{id}) віддає 404. Контакти, контрагенти, ліди, угоди, завдання, товари, замовлення й рахунки видаляються «м’яко» і з’являються в /.../deleted, а платежі видаляються остаточно.
Службові поля у відповідях
У відповідях трапляються поля з великої літери (OldContact, OldOrder, PrimaryBarcode тощо) і поле sub. Це службові дані інтерфейсу, вони не стабільні. Ігноруйте їх.