Skip to content

Создать услугу

Request

Создает новую услугу текущего мастера или участника салона.

Для индивидуального мастера provider_id созданной услуги равен id текущего пользователя. Для роли SALON backend находит салон текущего пользователя, получает id владельца салона и записывает его в provider_id услуги. Это относится и к владельцу салона, и к админу салона.

Правила валидации:

  • name не должен быть пустым и не должен быть длиннее 120 символов
  • description не должен быть пустым и не должен быть длиннее 4000 символов
  • price должен быть в диапазоне от 1 до 100000
  • discount_percent, если передан в POST /api/service, должен быть в диапазоне от 0 до 100; 0 означает отсутствие скидки, 1..100 задает скидку услуги при создании
  • duration должен быть в диапазоне от 1 до 1440 минут
  • category_id должен быть положительным ID существующей конечной подкатегории
  • корневую категорию или категорию с дочерними категориями нельзя назначить услуге
  • images должен содержать от 1 до 10 уникальных положительных ID файлов в порядке клиента
  • для индивидуального мастера service_locations обязателен и должен содержать от 1 до 3 объектов с уникальными service_location: IN_SALON, AT_MASTER_PLACE, CLIENT_PLACE
  • в каждом объекте service_locations обязателен непустой address
  • в каждом объекте можно передать geolocation; координаты сохраняются напрямую без повторного геокодирования
  • если в объекте передан address без geolocation, backend геокодирует этот адрес; при ошибке возвращается 422 geocoding_failed
  • для IN_SALON обязателен непустой salon_name
  • для CLIENT_PLACE обязателен radius_km со значением 1, 5, 10 или 20
  • салонная услуга использует адрес и координаты самого салона; поля service_locations, address и geolocation для роли SALON запрещены и приводят к 400 invalid_body
  • advantages должен содержать не больше 5 уникальных непустых строк до 50 символов

Доступ:

  • только роли MASTER или SALON
  • файлы из images должны быть доступны текущему пользователю
  • файлы из images должны иметь purpose CARD
  • требуется JWT
Security
bearerAuth or jwtCookie
Bodyapplication/jsonrequired
namestring, [ 1 .. 120 ] characters.*\S.*required
Example:"Мужская стрижка"
priceinteger, (int32), [ 1 .. 100000 ]required

Базовая цена по умолчанию. Используется, если price_intervals отсутствуют или проверяемое время не попадает ни в один интервал.

Example:1500
price_intervalsArray of objects or null(ServicePriceInterval)

Необязательные интервалы динамической базовой цены. Интервалы не должны пересекаться. Если поле не передано или передан пустой массив, используется только price.

Example:
[ { "start_time": "10:00", "end_time": "12:00", "price": 2000 } ]
discount_percentinteger or null, (int32), [ 0 .. 100 ]

Процент скидки услуги, который можно задать сразу при создании через POST /api/service.

Правила:

  • 0 сохраняется как 0 и означает отсутствие скидки
  • 1..100 устанавливает скидку услуги в процентах
  • если поле не передано или передано null, услуга создается без скидки
Example:15
durationinteger, (int32), [ 1 .. 1440 ]required

Длительность услуги в минутах.

Example:60
descriptionstring, [ 1 .. 4000 ] characters.*\S.*required
Example:"Стрижка с мытьем головы и укладкой."
category_idinteger, (int64), >= 1required
Example:3
is_fix_pricebooleanrequired
Example:true
imagesArray of integers, [ 1 .. 10 ] items, uniquerequired

Ordered service image IDs. The first image is used as preview. All files must have purpose CARD.

Example:
[ 101, 102, 103 ]
service_locationsArray of objects or null, [ 1 .. 3 ] items, unique(ServiceLocationRequest)

Обязательно для индивидуального мастера. Содержит объекты с адресом и метаданными каждого места оказания. Для салонной услуги поле запрещено, потому что она использует местоположение салона.

advantagesArray of strings, <= 5 itemsrequired
Example:
[ "Стерильные инструменты", "Быстро" ]
curl -i -X POST \
  https://felmee.com/api/service \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Мужская стрижка",
    "price": 1500,
    "price_intervals": [
      {
        "start_time": "10:00",
        "end_time": "12:00",
        "price": 2000
      }
    ],
    "discount_percent": 15,
    "duration": 60,
    "description": "Стрижка с мытьем головы и укладкой.",
    "category_id": 3,
    "is_fix_price": true,
    "images": [
      101,
      102,
      103
    ],
    "service_locations": [
      {
        "service_location": "AT_MASTER_PLACE",
        "address": "Moscow, Tverskaya, 16",
        "geolocation": {
          "lat": 55.7618,
          "lon": 37.6095
        }
      }
    ],
    "advantages": [
      "Стерильные инструменты",
      "Быстро"
    ]
  }'

Responses

Услуга успешно создана

Bodyapplication/json
codeErrorstring or nullrequired

Устаревший camelCase-alias поля error_code; при ошибке оба поля содержат одинаковое значение.

successbooleanrequired

Флаг успешного выполнения запроса

messagestringrequired

Человекочитаемое описание результата

error_codestring or null(ERROR_CODE)required

Код ошибки. Для успешных ответов всегда null.

Enum:"invalid_body""unauthorized""not_found""conflict""object_modified_by_another_thread""action_too_late""too_many_request""code_is_gone""forbidden""user_blocked"
dataobject or null(ServiceResponse)required

Полезная нагрузка. Может быть объектом, массивом или null.

Response
{ "success": true, "message": "Service created successfully", "error_code": null, "data": { "id": 20, "images": [], "name": "Мужская стрижка", "price": 1500, "price_intervals": [], "base_price": 1500, "final_price": 1275, "discount_percent": 15, "duration": 60, "description": "Стрижка с мытьем головы и укладкой.", "category_id": 3, "parent_category_id": 1, "provider_id": 5, "is_fix_price": true, "service_locations": [], "address": "г. Москва, ул. Тверская, д.16", "advantages": [], "geo": {} } }