{"openapi":"3.1.0","info":{"title":"Программный интерфейс LOYRA (API)","version":"1.0.0","description":"Программный интерфейс (API) мультитенантной платформы лояльности. Все финансовые запросы POST идемпотентны, а ключ API ограничивается областями доступа (scope) и филиалами.","contact":{"name":"Поддержка интеграций LOYRA","email":"api@loyra.ru"}},"servers":[{"url":"https://api.loyra.ru/api/v1","description":"Рабочая среда"}],"tags":[{"name":"Клиенты","description":"Идентификация и подключение участников"},{"name":"Заказы","description":"Заказ, расчёт, резерв, оплата и возврат"},{"name":"Приложение клиента","description":"Методы клиентского приложения"},{"name":"Записи","description":"Записи и доступные интервалы"},{"name":"Акции","description":"Акции и их жизненный цикл"},{"name":"Отчёты","description":"Агрегированные показатели"},{"name":"Вебхуки","description":"Проверка доставки событий"},{"name":"Система","description":"Диагностика"}],"security":[{"bearerAuth":[]}],"paths":{"/health":{"get":{"tags":["Система"],"security":[],"summary":"Проверить доступность API","responses":{"200":{"description":"API и база данных доступны","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"ok"},"version":{"type":"string"}}}}}}}}},"/customers/identify":{"post":{"tags":["Клиенты"],"summary":"Найти участника","description":"Передайте телефон, идентификатор либо временный QR-токен. Подключение выполняет сам клиент по ссылке организации; сотрудник и этот метод не могут подтвердить согласие за него.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","examples":["+79061971100"]}}},{"type":"object","required":["qr_token"],"properties":{"qr_token":{"type":"string","description":"Подписанный токен без loyra://-обёртки"}}}]}}}},"responses":{"200":{"description":"Профиль и членство","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerMembership"}}}},"201":{"description":"Участник подключён"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/customers":{"get":{"tags":["Клиенты"],"summary":"Список и поиск участников","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Страница участников"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Клиенты"],"summary":"Создать участника с согласиями","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone","legal_basis","consent_evidence"],"properties":{"phone":{"type":"string"},"first_name":{"type":"string"},"email":{"type":"string","format":"email"},"birth_date":{"type":"string","format":"date"},"legal_basis":{"const":"consent"},"consent_evidence":{"type":"object","required":["method","document_version","accepted_at","external_evidence_id"],"properties":{"method":{"enum":["otp","electronic_signature","paper","api_assertion"]},"document_version":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(?:\\.\\d+)?$","description":"Действующая опубликованная версия согласия организации"},"accepted_at":{"type":"string","format":"date-time"},"external_evidence_id":{"type":"string"}}},"marketing_consents":{"type":"array","description":"Необязательные отдельные доказательства по каналам","items":{"type":"object","required":["channel","method","document_version","accepted_at","external_evidence_id"],"properties":{"channel":{"enum":["sms","email","telegram","vk","push","in_app"]},"method":{"enum":["otp","electronic_signature","paper","api_assertion"]},"document_version":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(?:\\.\\d+)?$","description":"Действующая опубликованная версия согласия на рекламу организации"},"accepted_at":{"type":"string","format":"date-time"},"external_evidence_id":{"type":"string"}}}}}}}}},"responses":{"201":{"description":"Участник создан"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/customers/{customer_id}":{"parameters":[{"name":"customer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Клиенты"],"summary":"Карточка участника","responses":{"200":{"description":"Профиль участника"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Клиенты"],"summary":"Изменить профиль организации или зарегистрировать отзыв рекламы","responses":{"200":{"description":"Профиль обновлён"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/customers/{customer_id}/history":{"parameters":[{"name":"customer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Клиенты"],"summary":"Заказы, записи и уведомления участника","responses":{"200":{"description":"История"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/customers/{customer_id}/loyalty":{"parameters":[{"name":"customer_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Клиенты"],"summary":"Баланс и транзакции лояльности","responses":{"200":{"description":"Лояльность"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders":{"post":{"tags":["Заказы"],"summary":"Создать заказ","description":"Scope orders:write. API-интеграция обязана передать external_order_id.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrder"}}}},"responses":{"201":{"description":"Черновик создан","content":{"application/json":{"schema":{"type":"object","required":["id","status","subtotal"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"const":"draft"},"subtotal":{"type":"number"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}/calculate":{"post":{"tags":["Заказы"],"summary":"Рассчитать скидки, акции и бонусы","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bonuses_to_redeem":{"type":"number","minimum":0,"default":0},"promo_code":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"Объяснимый расчёт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Calculation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}/reserve":{"post":{"tags":["Заказы"],"summary":"Зарезервировать бонусы","description":"Резерв защищает от двойного списания и автоматически истекает.","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bonuses"],"properties":{"bonuses":{"type":"number","exclusiveMinimum":0}}}}}},"responses":{"200":{"description":"Резерв создан","content":{"application/json":{"schema":{"type":"object","properties":{"reservation_id":{"type":"string","format":"uuid"},"expires_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}/complete":{"post":{"tags":["Заказы"],"summary":"Подтвердить оплату","description":"Scope orders:complete. Начисление происходит только после этого запроса.","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["payment"],"properties":{"payment":{"type":"object","required":["method","amount"],"properties":{"method":{"enum":["cash","card","sbp","external"]},"amount":{"type":"number","minimum":0},"external_payment_id":{"type":"string","maxLength":200}}}}}}}},"responses":{"200":{"description":"Оплата, баланс и уровень зафиксированы одной транзакцией","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Completion"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}/refund":{"post":{"tags":["Заказы"],"summary":"Оформить полный или частичный возврат","description":"Scope orders:refund. Можно передать сумму либо позиции. Бонусы, уровень и прогресс акций пересчитываются.","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason","external_refund_id"],"anyOf":[{"required":["amount"]},{"required":["items"]}],"properties":{"amount":{"type":"number","exclusiveMinimum":0},"items":{"type":"array","minItems":1,"items":{"type":"object","required":["order_item_id","quantity"],"properties":{"order_item_id":{"type":"string","format":"uuid"},"quantity":{"type":"number","exclusiveMinimum":0}}}},"reason":{"type":"string","minLength":3},"external_refund_id":{"type":"string","maxLength":200}}}}}},"responses":{"200":{"description":"Возврат и обратные проводки зафиксированы"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}":{"get":{"tags":["Заказы"],"summary":"Получить заказ и позиции","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Заказ"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Заказы"],"summary":"Изменить черновик заказа","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"200":{"description":"Черновик обновлён"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/orders/{order_id}/cancel":{"post":{"tags":["Заказы"],"summary":"Отменить заказ и освободить резерв","parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"200":{"description":"Заказ отменён"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments":{"get":{"tags":["Записи"],"summary":"Список записей","responses":{"200":{"description":"Записи"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Записи"],"summary":"Создать запись","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"201":{"description":"Запись создана"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments/slots":{"get":{"tags":["Записи"],"summary":"Доступные слоты специалиста","responses":{"200":{"description":"Слоты"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments/{appointment_id}":{"parameters":[{"name":"appointment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Записи"],"summary":"Карточка записи","responses":{"200":{"description":"Запись"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Записи"],"summary":"Перенести или изменить запись","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"200":{"description":"Запись обновлена"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/appointments/{appointment_id}/{action}":{"parameters":[{"name":"appointment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"action","in":"path","required":true,"schema":{"enum":["confirm","complete","cancel"]}}],"post":{"tags":["Записи"],"summary":"Подтвердить, завершить или отменить запись","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"200":{"description":"Статус изменён"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/promotions":{"get":{"tags":["Акции"],"summary":"Список акций","responses":{"200":{"description":"Акции"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Акции"],"summary":"Создать акцию","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"201":{"description":"Акция создана"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/promotions/{promotion_id}":{"parameters":[{"name":"promotion_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Акции"],"summary":"Карточка акции","responses":{"200":{"description":"Акция"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["Акции"],"summary":"Изменить акцию","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/RequestId"}],"responses":{"200":{"description":"Акция обновлена"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/reports":{"get":{"tags":["Отчёты"],"summary":"Выручка, лояльность, филиалы и акции","responses":{"200":{"description":"Отчёт"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{webhook_id}/test":{"parameters":[{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"tags":["Вебхуки"],"summary":"Отправить тестовое подписанное событие","responses":{"200":{"description":"Результат доставки"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/app/profile":{"patch":{"tags":["Приложение клиента"],"security":[{"customerSession":[]}],"summary":"Обновить единый профиль LOYRA","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string"},"email":{"type":["string","null"],"format":"email"},"birth_date":{"type":["string","null"],"format":"date"}}}}}},"responses":{"200":{"description":"Профиль обновлён"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/app/appointments":{"post":{"tags":["Приложение клиента"],"security":[{"customerSession":[]}],"summary":"Создать запись с доказательством принятия условий","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tenant_id","branch_id","item_id","starts_at","service_terms_document_id","returns_document_id","service_terms_accepted","returns_terms_acknowledged"],"properties":{"tenant_id":{"type":"string","format":"uuid"},"branch_id":{"type":"string","format":"uuid"},"employee_id":{"type":"string","format":"uuid"},"item_id":{"type":"string","format":"uuid"},"starts_at":{"type":"string","format":"date-time"},"service_terms_document_id":{"type":"string","description":"Идентификатор показанной версии условий услуги"},"returns_document_id":{"type":"string","description":"Идентификатор показанной версии правил отмены и возврата"},"service_terms_accepted":{"const":true},"returns_terms_acknowledged":{"const":true}}}}}},"responses":{"201":{"description":"Запись создана; версия условий и сведения об исполнителе сохранены"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"LOYRA API key"},"customerSession":{"type":"apiKey","in":"cookie","name":"loyra_customer_session"}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"description":"Уникальный ключ операции; повтор с тем же payload возвращает исходный ответ.","schema":{"type":"string","minLength":8,"maxLength":200}},"RequestId":{"name":"X-Request-Id","in":"header","required":false,"description":"ID для сквозной диагностики","schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Авторизация отсутствует или недействительна","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Недостаточный scope, роль или доступ к филиалу","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Конфликт состояния или идемпотентности","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Превышен лимит запросов","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string","format":"uuid"},"docs_url":{"type":"string","format":"uri"}}}}},"CustomerMembership":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"first_name":{"type":["string","null"]},"phone_masked":{"type":"string"}}},"membership":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"level":{"type":["string","null"]},"discount_percent":{"type":"number"},"bonus_balance":{"type":"number"},"total_spent":{"type":"number"}}}}},"CreateOrder":{"type":"object","required":["branch_id","customer_id","items"],"properties":{"branch_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"employee_id":{"type":"string","format":"uuid"},"external_order_id":{"type":"string","maxLength":200},"source":{"type":"string","default":"staff"},"order_type":{"enum":["dine_in","takeaway","delivery","service"]},"table_number":{"type":"string"},"guests_count":{"type":"integer","minimum":1},"waiter_id":{"type":"string","format":"uuid"},"tips":{"type":"number","minimum":0},"aggregator":{"type":"string"},"guests":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"item_indexes":{"type":"array","items":{"type":"integer"}}}}},"items":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","required":["name","quantity","price"],"properties":{"product_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"quantity":{"type":"number","exclusiveMinimum":0},"price":{"type":"number","minimum":0},"loyalty":{"type":"object","properties":{"discount_allowed":{"type":"boolean"},"bonus_earn_allowed":{"type":"boolean"},"bonus_redeem_allowed":{"type":"boolean"}}}}}}}},"Calculation":{"type":"object","properties":{"order_id":{"type":"string","format":"uuid"},"subtotal":{"type":"number"},"level_discount":{"type":"number"},"promotion_discount":{"type":"number"},"bonus_discount":{"type":"number"},"bonuses_redeemed":{"type":"number"},"bonuses_to_earn":{"type":"number"},"tips":{"type":"number"},"total":{"type":"number"},"balance_before":{"type":"number"},"balance_after":{"type":"number"},"promotions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"explanation":{"type":"string"},"discountAmount":{"type":"number"}}}}}},"Completion":{"type":"object","properties":{"order_id":{"type":"string","format":"uuid"},"status":{"const":"completed"},"new_bonus_balance":{"type":"number"},"bonuses_earned":{"type":"number"},"loyalty_level":{"type":"object","properties":{"previous":{"type":["string","null"]},"current":{"type":["string","null"]}}}}}}}}