Увійти Зареєструватися

Послуги

Відкритий 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."
    }
  }
}
codeHTTPmessageКоли
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: однакові для всіх модулів і описані на головній документації.

Інші модулі

Питання по інтеграції пишіть у Telegram або на сторінці підтримки.