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

Послуги

Відкритий 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 або на сторінці підтримки.