Послуги
Відкритий API/services/api/v1/
Клієнти, записи, вільні слоти, статуси та історія клієнта. Те саме, що робить кабінет, але для сайту, телеграм-бота чи рецепції.
Доступ
Токен у заголовку. Створюється в налаштуваннях модуля «Послуги» → «API для інтеграцій». На платному тарифі токен робочий, на безкоштовному sandbox (усі методи працюють, дані живуть 24 години).
Authorization: Bearer <token>
X-API-Key: <token>
Обидва заголовки рівнозначні, достатньо одного.
Ліміти й режими
- Час і дати
- date, time, starts_at і ends_at: місцевий час бізнесу без зсуву: саме так календар і зберігає години, і саме їх бачить клієнт. created_at, updated_at і expires_at: повний ISO 8601 зі зсувом.
- Ліміт запитів
- 60 на годину на кожен токен платного тарифу, 30 для sandbox. Ліміт налаштовується окремо для кожного токена: якщо інтеграції треба більше, напишіть у підтримку.
- Заголовки залишку
- X-RateLimit-Limit, X-RateLimit-Remaining і X-RateLimit-Reset приходять у кожній відповіді, а при 429 ще й Retry-After у секундах до скидання вікна.
- Sandbox
- Токен безкоштовного тарифу працює в окремому просторі: він бачить лише створене ним і не може змінити справжні дані кабінету. Створені обʼєкти видаляються через 24 години (поле expires_at у кожній відповіді), не займають час у публічному календарі й не створюють доходів і списань.
- Кілька токенів
- До 5 токенів на платному тарифі, окремий на кожну інтеграцію, щоб відкликати один, не ламаючи решту. На безкоштовному один sandbox-токен.
Ендпоінти
-
GET
/services/api/v1/clients/Список клієнтів
Клієнти акаунта з пагінацією й пошуком.
Параметри й приклади
Параметри запиту
Параметр Обовʼязковий Опис qні Пошук за імʼям, прізвищем, телефоном або email. is_activeні true або false: лише активні чи лише архівні. limitні Скільки повернути, 1-100. За замовчуванням 50. offsetні Зсув для наступної сторінки. За замовчуванням 0. Відповідь 200
{ "count": 128, "limit": 50, "offset": 0, "results": [ { "id": 41, "first_name": "Оксана", "last_name": "Мельник", "full_name": "Оксана Мельник", "email": "[email protected]", "phone": "+380671234567", "telegram": "@oksana", "notes": "Алергія на аміак", "is_active": true, "sandbox": false, "expires_at": null, "created_at": "2026-08-14T11:02:37+03:00", "updated_at": "2026-09-01T09:15:00+03:00" } ] }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_parameter{"error": {"code": "invalid_parameter", "message": "Query parameter is invalid."}}
-
-
POST
/services/api/v1/clients/Створити клієнта
Обовʼязкове лише імʼя, решта полів за наявності.
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис first_nameтак Імʼя, до 100 символів. last_nameні Прізвище, до 100 символів. emailні Перевіряється на формат. null, щоб прибрати. phoneні До 30 символів, у будь-якому форматі. telegramні До 100 символів. notesні Внутрішня примітка, будь-яка довжина. is_activeні true за замовчуванням. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "first_name": "Оксана", "last_name": "Мельник", "phone": "+380671234567", "email": "[email protected]", "notes": "Прийшла з Instagram" }Відповідь 201
{ "id": 42, "first_name": "Оксана", "last_name": "Мельник", "full_name": "Оксана Мельник", "email": "[email protected]", "phone": "+380671234567", "telegram": null, "notes": "Прийшла з Instagram", "is_active": true, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T12:41:09+03:00", "updated_at": "2026-09-08T12:41:09+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "first_name": "This field is required and must not be empty.", "email": "Not a valid email address." } } }
-
-
GET
/services/api/v1/clients/<id>/Один клієнт
Той самий обʼєкт, що у списку, за внутрішнім id.
Параметри й приклади
Відповідь 200
{ "id": 42, "first_name": "Оксана", "last_name": "Мельник", "full_name": "Оксана Мельник", "email": "[email protected]", "phone": "+380671234567", "telegram": null, "notes": "Прийшла з Instagram", "is_active": true, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T12:41:09+03:00", "updated_at": "2026-09-08T12:41:09+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}}
-
-
PATCH
/services/api/v1/clients/<id>/Редагувати клієнта
Часткове оновлення: надсилайте лише ті поля, які змінюються. Порожнє тіло: це 400, а не «нічого не робити».
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис first_nameні Імʼя, до 100 символів. Порожнім бути не може. last_nameні Прізвище. emailні Формат перевіряється, null прибирає значення. phoneні Телефон, null прибирає значення. telegramні Telegram, null прибирає значення. notesні Примітка. is_activeні Активність клієнта. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "phone": "+380509998877", "notes": "Просила писати в Telegram" }Відповідь 200
{ "id": 42, "first_name": "Оксана", "last_name": "Мельник", "full_name": "Оксана Мельник", "email": "[email protected]", "phone": "+380509998877", "telegram": null, "notes": "Просила писати в Telegram", "is_active": true, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T12:41:09+03:00", "updated_at": "2026-09-08T13:02:44+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "body": "Provide at least one of: first_name, last_name, email, phone, telegram, notes, is_active." } } }
-
-
POST
/services/api/v1/clients/<id>/status/Змінити статус клієнта
Активний або архівний. Окремий ендпоінт, бо це найчастіша зміна, і плутати її з редагуванням полів не варто.
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис is_activeтак true: активний, false: в архіві. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "is_active": false }Відповідь 200
{ "id": 42, "first_name": "Оксана", "last_name": "Мельник", "full_name": "Оксана Мельник", "email": "[email protected]", "phone": "+380509998877", "telegram": null, "notes": "Просила писати в Telegram", "is_active": false, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T12:41:09+03:00", "updated_at": "2026-09-08T13:20:10+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "is_active": "This field is required and must be a boolean." } } }
-
-
GET
/services/api/v1/clients/<id>/history/Історія клієнта
Усі записи клієнта, підсумки й оплати. Оплати беруться з модуля «Облік доходів», вони створюються з виконаних записів. Немає модуля, тоді список порожній, і це не помилка.
Параметри й приклади
Відповідь 200
{ "client": { "id": 42, "full_name": "Оксана Мельник", "...": "решта полів як у GET клієнта" }, "stats": { "bookings_total": 7, "bookings_completed": 5, "bookings_cancelled": 1, "bookings_upcoming": 1, "revenue_completed": "3400.00", "first_visit": "2026-04-12", "last_visit": "2026-08-30" }, "bookings": [ { "id": 913, "status": "completed", "date": "2026-08-30", "time": "14:00", "starts_at": "2026-08-30T14:00:00", "ends_at": "2026-08-30T15:30:00", "duration_minutes": 90, "notes": null, "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-08-20T10:00:00+03:00", "updated_at": "2026-08-30T15:31:02+03:00" } ], "payments": [ { "id": 55, "booking_id": 913, "date": "2026-08-30", "amount": "700.00", "currency": "UAH", "source": "booking_completed" } ] }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}}
-
-
GET
/services/api/v1/services/Список послуг
Потрібен, щоб знати service_id і тривалість: від неї залежить сітка слотів.
Параметри й приклади
Параметри запиту
Параметр Обовʼязковий Опис is_activeні true або false. limitні 1-100, за замовчуванням 50. offsetні Зсув, за замовчуванням 0. Відповідь 200
{ "count": 4, "limit": 50, "offset": 0, "results": [ { "id": 3, "name": "Стрижка", "short_description": "Чоловіча або жіноча", "price": "700.00", "duration_minutes": 90, "is_active": true } ] }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_parameter{"error": {"code": "invalid_parameter", "message": "Query parameter is invalid."}}
-
-
GET
/services/api/v1/slots/Вільні часові слоти
Сітка дорівнює тривалості послуги, зайняте виключається за реальним перетином часу, минулі години не показуються. Це та сама функція, що малює пікер у кабінеті, тож API не покаже вільним те, чого не приймає створення запису.
Параметри й приклади
Параметри запиту
Параметр Обовʼязковий Опис service_idтак Послуга, під тривалість якої рахується сітка. dateні YYYY-MM-DD. За замовчуванням сьогодні. daysні Скільки днів підряд повернути, 1-14. За замовчуванням 1. Відповідь 200
{ "service_id": 3, "duration_minutes": 90, "count": 3, "results": [ { "date": "2026-09-10", "is_working_day": true, "slots": [ { "time": "09:00", "starts_at": "2026-09-10T09:00:00", "ends_at": "2026-09-10T10:30:00" }, { "time": "10:30", "starts_at": "2026-09-10T10:30:00", "ends_at": "2026-09-10T12:00:00" } ] }, { "date": "2026-09-11", "is_working_day": false, "slots": [] } ] }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_parameter{"error": {"code": "invalid_parameter", "message": "Query parameter is invalid."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}}
-
-
GET
/services/api/v1/bookings/Список записів
Записи з фільтрами за датою, статусом, клієнтом і послугою.
Параметри й приклади
Параметри запиту
Параметр Обовʼязковий Опис date_fromні YYYY-MM-DD, включно. date_toні YYYY-MM-DD, включно. statusні pending, confirmed, cancelled або completed. client_idні Лише записи цього клієнта. service_idні Лише записи на цю послугу. limitні 1-100, за замовчуванням 50. offsetні Зсув, за замовчуванням 0. Відповідь 200
{ "count": 12, "limit": 50, "offset": 0, "results": [ { "id": 913, "status": "confirmed", "date": "2026-09-10", "time": "09:00", "starts_at": "2026-09-10T09:00:00", "ends_at": "2026-09-10T10:30:00", "duration_minutes": 90, "notes": "Просила майстра Ірину", "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T12:50:00+03:00", "updated_at": "2026-09-08T12:50:00+03:00" } ] }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_parameter{"error": {"code": "invalid_parameter", "message": "Query parameter is invalid."}}
-
-
POST
/services/api/v1/bookings/Створити запис
Час перевіряється так само, як у кабінеті: перетин із наявними записами за тривалістю послуги, робочий розклад і «час уже минув». Не пройшло: 409 із людським текстом причини в message.
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис client_idтак Наявний клієнт цього акаунта. service_idтак Активна послуга цього акаунта. dateтак YYYY-MM-DD. timeтак HH:MM (приймається і HH:MM:SS). notesні Примітка до запису. statusні pending (за замовчуванням), confirmed, cancelled, completed. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "client_id": 42, "service_id": 3, "date": "2026-09-10", "time": "09:00", "notes": "Просила майстра Ірину", "status": "confirmed" }Відповідь 201
{ "id": 914, "status": "confirmed", "date": "2026-09-10", "time": "09:00", "starts_at": "2026-09-10T09:00:00", "ends_at": "2026-09-10T10:30:00", "duration_minutes": 90, "notes": "Просила майстра Ірину", "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T13:40:00+03:00", "updated_at": "2026-09-08T13:40:00+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "client_id": "Client with this id does not exist in this account.", "date": "Required, format YYYY-MM-DD." } } } -
409
slot_taken{ "error": { "code": "slot_taken", "message": "Requested time slot is not available.", "details": { "reason": "overlaps_existing_booking" } } }
-
-
GET
/services/api/v1/bookings/<id>/Один запис
Той самий обʼєкт, що у списку, за внутрішнім id.
Параметри й приклади
Відповідь 200
{ "id": 914, "status": "confirmed", "date": "2026-09-10", "time": "09:00", "starts_at": "2026-09-10T09:00:00", "ends_at": "2026-09-10T10:30:00", "duration_minutes": 90, "notes": "Просила майстра Ірину", "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T13:40:00+03:00", "updated_at": "2026-09-08T13:40:00+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}}
-
-
PATCH
/services/api/v1/bookings/<id>/Редагувати запис
Перенести на інший час, змінити послугу, клієнта чи примітку. Якщо змінюються дата, час або послуга, час перевіряється заново, але вже без урахування самого цього запису (інакше він конфліктував би сам із собою).
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис client_idні Інший клієнт цього акаунта. service_idні Інша активна послуга. dateні YYYY-MM-DD. timeні HH:MM. notesні Примітка, null, щоб прибрати. statusні pending, confirmed, cancelled, completed. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "date": "2026-09-11", "time": "11:00" }Відповідь 200
{ "id": 914, "status": "confirmed", "date": "2026-09-11", "time": "11:00", "starts_at": "2026-09-11T11:00:00", "ends_at": "2026-09-11T12:30:00", "duration_minutes": 90, "notes": "Просила майстра Ірину", "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T13:40:00+03:00", "updated_at": "2026-09-08T14:05:12+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "body": "Provide at least one of: client_id, service_id, date, time, notes, status." } } } -
409
slot_taken{ "error": { "code": "slot_taken", "message": "Requested time slot is not available.", "details": { "reason": "time_in_the_past" } } }
-
-
POST
/services/api/v1/bookings/<id>/status/Змінити статус запису
Переведення в completed тягне за собою те саме, що й у кабінеті: автоматичний дохід у модулі «Облік доходів» і списання матеріалів в ERP, якщо вони налаштовані. Для sandbox-токена ці наслідки не виконуються: тестовий запис не має рухати справжні гроші й склад.
Параметри й приклади
Поля тіла запиту
Поле Обовʼязкове Опис statusтак pending, confirmed, cancelled або completed. Зірочка означає «одне з двох»: достатньо будь-якого.
Запит
{ "status": "completed" }Відповідь 200
{ "id": 914, "status": "completed", "date": "2026-09-11", "time": "11:00", "starts_at": "2026-09-11T11:00:00", "ends_at": "2026-09-11T12:30:00", "duration_minutes": 90, "notes": "Просила майстра Ірину", "client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null }, "service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 }, "sandbox": false, "expires_at": null, "created_at": "2026-09-08T13:40:00+03:00", "updated_at": "2026-09-11T12:31:00+03:00" }Помилки й тіла відповідей
-
401
missing_token{"error": {"code": "missing_token", "message": "Authorization header is missing."}} -
401
invalid_token{"error": {"code": "invalid_token", "message": "Token is invalid or revoked."}} -
403
module_required{"error": {"code": "module_required", "message": "Module is not enabled for this account."}} -
403
plan_required{"error": {"code": "plan_required", "message": "Paid plan required for this token."}} -
429
rate_limit_exceeded{"error": {"code": "rate_limit_exceeded", "message": "Hourly request limit exceeded."}} -
405
method_not_allowed{"error": {"code": "method_not_allowed", "message": "HTTP method is not allowed for this endpoint."}} -
404
not_found{"error": {"code": "not_found", "message": "Object does not exist."}} -
400
invalid_json{"error": {"code": "invalid_json", "message": "Request body is not a valid JSON object."}} -
400
validation_error{ "error": { "code": "validation_error", "message": "Some fields failed validation.", "details": { "status": "This field is required and must be one of: pending, confirmed, cancelled, completed." } } }
-
Усі помилки
Формат один на всі модулі. code стабільний, на нього
і варто перевіряти; message англійською й може бути
уточнений. У details є конкретні поля, якщо помилка
про них. Тіло кожної помилки показане в самому ендпоінті, ось
загальний вигляд:
{
"error": {
"code": "validation_error",
"message": "Some fields failed validation.",
"details": {
"field_name": "What exactly is wrong with this field."
}
}
}
| code | HTTP | message | Коли |
|---|---|---|---|
missing_token |
401 | Authorization header is missing. | Немає ні Authorization: Bearer, ні X-API-Key. |
invalid_token |
401 | Token is invalid or revoked. | Токена не існує або його відкликали в налаштуваннях модуля. |
module_required |
403 | Module is not enabled for this account. | До акаунта не підключено модуль «Послуги». |
plan_required |
403 | Paid plan required for this token. | Токен видано на платному тарифі, а тариф уже не платний. Дані не зникають, але щоб API знову працював, треба або поновити підписку, або створити sandbox-токен. |
rate_limit_exceeded |
429 | Hourly request limit exceeded. | Вичерпано ліміт запитів на годину. Коли вікно скинеться — у заголовках X-RateLimit-Reset і Retry-After. |
method_not_allowed |
405 | HTTP method is not allowed for this endpoint. | Не той HTTP-метод. Дозволені перелічені в заголовку Allow. |
invalid_json |
400 | Request body is not a valid JSON object. | Тіло запиту не розібралось як JSON. |
validation_error |
400 | Some fields failed validation. | Поля не пройшли перевірку. Які саме й що з ними — у details. |
invalid_parameter |
400 | Query parameter is invalid. | Некоректний параметр у query string (дата, id, limit). |
not_found |
404 | Object does not exist. | Обʼєкта немає або він належить іншому акаунту — назовні це одне й те саме, щоб чужі id не можна було перебрати. |
slot_taken |
409 | Requested time slot is not available. | Час зайнятий іншим записом, поза робочим розкладом або вже минув. Причина — у details.reason: time_in_the_past, non_working_day, outside_working_hours або overlaps_existing_booking. |
Вебхуки
Вебхук це API навпаки: не ви питаєте нас, а ми надсилаємо POST на вашу адресу, коли щось стається. Опитувати /bookings/ раз на хвилину не потрібно.
Куди вставити адресу: Налаштування модуля «Послуги» → «Вебхуки». Там же є секрет для перевірки підпису, кнопка тестової доставки й журнал останніх спроб.
Події
| event | Коли | data |
|---|---|---|
client.created |
Новий клієнт — з кабінету, публічної форми запису або через API. | client |
client.updated |
Змінились дані клієнта або його статус (активний / в архіві). | client |
booking.created |
Новий запис на послугу — з кабінету, публічної сторінки запису або через API. | booking |
booking.updated |
Перенесення на інший час, зміна послуги, клієнта або примітки. | booking |
booking.status_changed |
Окрема подія, бо саме на неї вішають нагадування, відгуки й підрахунок виручки. У changes — старий і новий статус. | booking |
Тіло запиту
{
"event": "booking.status_changed",
"delivery_id": "0f3c1d2e-6f5a-4a1b-9c77-1b2f4e5d6a70",
"created_at": "2026-09-11T12:31:00+03:00",
"sandbox": false,
"changes": {
"status": { "from": "confirmed", "to": "completed" }
},
"data": {
"id": 914,
"status": "completed",
"date": "2026-09-11",
"time": "11:00",
"starts_at": "2026-09-11T11:00:00",
"ends_at": "2026-09-11T12:30:00",
"duration_minutes": 90,
"notes": "Просила майстра Ірину",
"client": { "id": 42, "full_name": "Оксана Мельник", "phone": "+380509998877", "email": null },
"service": { "id": 3, "name": "Стрижка", "price": "700.00", "duration_minutes": 90 },
"sandbox": false,
"expires_at": null,
"created_at": "2026-09-08T13:40:00+03:00",
"updated_at": "2026-09-11T12:31:00+03:00"
}
}
data: той самий обʼєкт, що віддає відповідний ендпоінт API. Другий парсер на ті самі поля писати не треба. changes приходить лише в booking.status_changed.
Заголовки
| Заголовок | Що в ньому |
|---|---|
X-ClearMoney-Event |
Код події, те саме, що в полі event. |
X-ClearMoney-Delivery |
UUID доставки. За ним відсіюйте повтори. |
X-ClearMoney-Timestamp |
Час відправлення, ISO 8601. |
X-ClearMoney-Signature |
sha256=<HMAC-SHA256 сирого тіла запиту з вашим секретом>. |
Перевірка підпису
Підпис рахується від сирого тіла запиту, до будь-якого розбору JSON. Якщо спершу розібрати й серіалізувати назад, підпис не збіжиться через порядок ключів і пробіли.
import hashlib
import hmac
def is_from_clearmoney(request_body: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), request_body, hashlib.sha256
).hexdigest()
# compare_digest, а не ==: побайтове порівняння дає можливість
# підібрати підпис за часом відповіді.
return hmac.compare_digest(expected, signature)
<?php
function is_from_clearmoney($body, $signature, $secret) {
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
return hash_equals($expected, $signature);
}
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_CLEARMONEY_SIGNATURE'] ?? '';
if (!is_from_clearmoney($body, $signature, CLEARMONEY_WEBHOOK_SECRET)) {
http_response_code(401);
exit;
}
http_response_code(200);
Вимоги до вашого боку
- Тільки https
- Ми надсилаємо дані клієнтів: імена, телефони. Посилання на http не приймається, як і адреса у внутрішній мережі.
- Відповідайте 2xx
- Будь-який код 2xx означає «прийняв». Таймаут 10 секунд, тож складну обробку робіть після відповіді, а не до неї.
- Ідемпотентність
- Одна подія може прийти двічі, мережа є мережа. Тримайтеся X-ClearMoney-Delivery: той самий UUID означає ту саму подію.
Повтори й відмови
- Коли повторюємо
- Таймаут, обрив зʼєднання, 429 і 5xx. До 5 спроб із наростаючою паузою: хвилина, потім довше, до двох годин.
- Коли не повторюємо
- Решта 4xx означає «надсилаєш не те або не туди». Повтори тут лише марно стукають у ваш сервер.
- Мертва адреса
- 20 невдач підряд, і вебхук вимикається, а в налаштуваннях зʼявляється причина. Інакше інтеграція місяцями «працює», а події нікуди не доходять.
- Sandbox
- Вебхук безкоштовного тарифу отримує лише події sandbox-обʼєктів. У платного в конверті є поле sandbox, за ним тестові події можна відсіяти.
Наявні ендпоінти кабінету
Ці адреси лишились для сторінок кабінету й працюють лише з сесією браузера. Для інтеграцій вони не потрібні: усе те саме є вище під токеном.
-
GET
/services/api/clients/Список клієнтів -
POST
/services/api/clients/create/Створити клієнта -
GET
/services/api/clients/<id>/Один клієнт -
POST
/services/api/clients/<id>/delete/Видалити клієнта
Спільні правила
Гроші рядками, дати ISO 8601, ізоляція даних за токеном, ідемпотентність ingest: однакові для всіх модулів і описані на головній документації.
Інші модулі
- Товари та замовлення Відкритий API
- Облік доходів У планах
Питання по інтеграції пишіть у Telegram або на сторінці підтримки.