{
  "components": {
    "responses": {
      "Forbidden": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        },
        "description": "Отказ: у ключа нет права (`scope_missing`), запрос по http (`https_required` — ключ отозван), не с разрешённого адреса (`ip_not_allowed`), контакты семьи скрыты (`contacts_hidden`) или иное правило доступа"
      },
      "RateLimited": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        },
        "description": "Превышен лимит (`rate_limited`): повторите через `Retry-After` секунд",
        "headers": {
          "Retry-After": {
            "description": "Через сколько секунд повторить запрос",
            "schema": {
              "minimum": 0,
              "type": "integer"
            }
          }
        }
      },
      "Unauthorized": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        },
        "description": "Нет ключа или ключ недействителен (`unauthorized`)"
      },
      "Unavailable": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        },
        "description": "Сервер не ответил за 30 секунд (`timeout`) или часть сервиса временно недоступна. Повторите запрос с тем же `Idempotency-Key`"
      }
    },
    "schemas": {
      "AgeGroup": {
        "properties": {
          "age_max": {
            "format": "int32",
            "type": "integer"
          },
          "age_min": {
            "format": "int32",
            "type": "integer"
          },
          "squad": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "squad",
          "age_min",
          "age_max"
        ],
        "type": "object"
      },
      "BatchRequest": {
        "additionalProperties": false,
        "description": "Несколько детей одной семьи.",
        "properties": {
          "children": {
            "description": "От 1 до 10 детей",
            "items": {
              "$ref": "#/components/schemas/FamilyChild"
            },
            "type": "array"
          },
          "invoice": {
            "description": "Счёт каждому ребёнку: min | full | none (как у одной брони)",
            "type": [
              "string",
              "null"
            ]
          },
          "parent": {
            "$ref": "#/components/schemas/ParentIn"
          },
          "payer_phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "together": {
            "description": "Поселить вместе детей семьи, попавших на одну смену",
            "type": "boolean"
          }
        },
        "required": [
          "parent",
          "children"
        ],
        "type": "object"
      },
      "BatchResponse": {
        "properties": {
          "items": {
            "description": "Брони в порядке детей запроса",
            "items": {
              "$ref": "#/components/schemas/Booking"
            },
            "type": "array"
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Booking": {
        "description": "Бронь, как её видит ваш отдел.",
        "properties": {
          "cancelled_reason": {
            "description": "Причина отмены",
            "type": [
              "string",
              "null"
            ]
          },
          "checkin": {
            "$ref": "#/components/schemas/Checkin"
          },
          "child": {
            "$ref": "#/components/schemas/BookingChild"
          },
          "comment": {
            "type": "string"
          },
          "contacts_hidden": {
            "description": "Ребёнка теперь ведёт другой отдел: бронь остаётся в ваших списках\n(это ваша продажа), но телефоны родителя и плательщика скрыты",
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "debt": {
            "$ref": "#/components/schemas/Money",
            "description": "Остаток: total − paid. Отрицательный — переплата"
          },
          "discount": {
            "$ref": "#/components/schemas/Discount"
          },
          "external_id": {
            "description": "Номер записи в вашей CRM. Уникален внутри отдела",
            "type": [
              "string",
              "null"
            ]
          },
          "full_payment_due": {
            "description": "До какой даты внести всю сумму",
            "format": "date",
            "type": "string"
          },
          "hold_until": {
            "description": "До какого момента держится место без минимального платежа",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "example": "15230",
            "type": "string"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata",
            "description": "Ваши метки: до 20 пар «ключ — значение»"
          },
          "paid": {
            "$ref": "#/components/schemas/Money",
            "description": "Оплачено: все платежи брони, включая ещё не сверенные бухгалтерией"
          },
          "parent": {
            "$ref": "#/components/schemas/BookingParent"
          },
          "partner_manager": {
            "description": "Кто продал бронь в вашей CRM — как вы его прислали",
            "type": [
              "string",
              "null"
            ]
          },
          "payer_phone": {
            "description": "Телефон плательщика, если платит не родитель: на него уходят счета\nKaspi. Нет — платит родитель (или контакты скрыты, см. `contacts_hidden`)",
            "type": [
              "string",
              "null"
            ]
          },
          "payment_state": {
            "description": "awaiting — место придержано и ждёт минимальный платёж;\nsecured — минимум внесён, место закреплено; unpaid — не оплачена\nв срок, место вернулось в квоту. Список может пополняться",
            "example": "awaiting",
            "type": "string"
          },
          "price": {
            "$ref": "#/components/schemas/Money",
            "description": "Цена путёвки"
          },
          "shift": {
            "$ref": "#/components/schemas/BookingShift"
          },
          "squad_number": {
            "description": "Номер отряда; нет — ещё не назначен",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "description": "active — действует, cancelled — отменена. Список может пополняться",
            "example": "active",
            "type": "string"
          },
          "total": {
            "$ref": "#/components/schemas/Money",
            "description": "К оплате всего: цена + трансфер − скидка"
          },
          "transfer": {
            "$ref": "#/components/schemas/Transfer"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "version": {
            "description": "Версия записи. Передайте её в `If-Match` правки или отмены:\nесли бронь успели изменить, ответ будет `412`",
            "example": "2027-05-14T09:31:07.123456Z",
            "type": "string"
          },
          "voucher": {
            "$ref": "#/components/schemas/BookingVoucher"
          },
          "voucher_number": {
            "description": "Номер путёвки: смена-порядковый номер",
            "example": "05-012",
            "type": "string"
          }
        },
        "required": [
          "id",
          "version",
          "status",
          "payment_state",
          "shift",
          "voucher_number",
          "child",
          "parent",
          "transfer",
          "price",
          "discount",
          "total",
          "paid",
          "debt",
          "full_payment_due",
          "voucher",
          "checkin",
          "comment",
          "metadata",
          "created_at",
          "updated_at",
          "contacts_hidden"
        ],
        "type": "object"
      },
      "BookingChild": {
        "properties": {
          "birth_date": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "$ref": "#/components/schemas/City"
          },
          "full_name": {
            "type": "string"
          },
          "id": {
            "description": "Карточка ребёнка; нет — бронь не привязана к семье",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "full_name",
          "city"
        ],
        "type": "object"
      },
      "BookingChildPatch": {
        "additionalProperties": false,
        "description": "Правка ребёнка в брони.",
        "properties": {
          "birth_date": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "city_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "BookingParent": {
        "properties": {
          "full_name": {
            "type": "string"
          },
          "id": {
            "description": "Карточка семьи; нет — бронь не привязана к семье",
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "Телефон родителя; нет — контакты скрыты (`contacts_hidden`)",
            "example": "+77011234567",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "full_name"
        ],
        "type": "object"
      },
      "BookingShift": {
        "properties": {
          "date_end": {
            "format": "date",
            "type": "string"
          },
          "date_start": {
            "format": "date",
            "type": "string"
          },
          "id": {
            "example": "12",
            "type": "string"
          },
          "number": {
            "description": "Номер смены в сезоне",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "number",
          "date_start",
          "date_end"
        ],
        "type": "object"
      },
      "BookingSummary": {
        "properties": {
          "child_id": {
            "description": "Нет — бронь без карточки ребёнка (старые записи)",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "shift": {
            "$ref": "#/components/schemas/ShiftRef"
          },
          "status": {
            "description": "active — действует, cancelled — отменена. Список может пополняться",
            "example": "active",
            "type": "string"
          },
          "voucher_number": {
            "example": "05-012",
            "type": "string"
          }
        },
        "required": [
          "id",
          "shift",
          "status",
          "voucher_number"
        ],
        "type": "object"
      },
      "BookingVersion": {
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "description": "active или cancelled",
            "example": "active",
            "type": "string"
          },
          "version": {
            "description": "Версия брони — та же, что в её карточке. Не совпала с вашей —\nперечитайте бронь",
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "version"
        ],
        "type": "object"
      },
      "BookingVoucher": {
        "description": "Путёвка в карточке брони (кратко; полностью — `GET /bookings/{id}/voucher`).",
        "properties": {
          "status": {
            "description": "none — не сформирована, generated — сформирована, sent — отправлена.\nСписок может пополняться",
            "example": "none",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "type": "object"
      },
      "CancelRequest": {
        "additionalProperties": false,
        "properties": {
          "reason": {
            "description": "Причина отмены — обязательна",
            "example": "Семья передумала",
            "type": "string"
          }
        },
        "required": [
          "reason"
        ],
        "type": "object"
      },
      "CheckChild": {
        "additionalProperties": false,
        "properties": {
          "birth_date": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "city_id": {
            "description": "Не участвует в проверке. Принимается, чтобы в проверку можно было\nотправить тот же объект ребёнка, что потом уйдёт в оформление",
            "type": [
              "string",
              "null"
            ]
          },
          "full_name": {
            "type": "string"
          }
        },
        "required": [
          "full_name"
        ],
        "type": "object"
      },
      "CheckParent": {
        "additionalProperties": false,
        "properties": {
          "full_name": {
            "description": "Не участвует в проверке; принимается по той же причине, что city_id",
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "example": "+77011234567",
            "type": "string"
          }
        },
        "required": [
          "phone"
        ],
        "type": "object"
      },
      "CheckReason": {
        "properties": {
          "code": {
            "description": "Тот же код, что вернуло бы оформление: sales_closed, shift_not_open,\nquota_exhausted, no_quota, duplicate_child, blacklisted,\nbirth_date_implausible. Список может пополняться",
            "example": "quota_exhausted",
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "CheckRequest": {
        "additionalProperties": false,
        "properties": {
          "child": {
            "$ref": "#/components/schemas/CheckChild"
          },
          "parent": {
            "$ref": "#/components/schemas/CheckParent"
          },
          "payer_phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "shift_id": {
            "type": "string"
          }
        },
        "required": [
          "shift_id",
          "child",
          "parent"
        ],
        "type": "object"
      },
      "CheckResult": {
        "properties": {
          "can_book": {
            "description": "Оформление сейчас пройдёт (если за это время место не займут)",
            "type": "boolean"
          },
          "reasons": {
            "description": "Почему нельзя — все причины сразу",
            "items": {
              "$ref": "#/components/schemas/CheckReason"
            },
            "type": "array"
          }
        },
        "required": [
          "can_book",
          "reasons"
        ],
        "type": "object"
      },
      "Checkin": {
        "properties": {
          "checked_in_at": {
            "description": "Когда ребёнок приехал в лагерь",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "checked_out_at": {
            "description": "Когда уехал",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "Child": {
        "properties": {
          "birth_date": {
            "description": "Нет — дата рождения неизвестна",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "external_id": {
            "description": "Номер ребёнка в вашей CRM",
            "type": [
              "string",
              "null"
            ]
          },
          "family_id": {
            "description": "Семья ребёнка",
            "type": "string"
          },
          "full_name": {
            "type": "string"
          },
          "id": {
            "example": "1503",
            "type": "string"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "required": [
          "id",
          "family_id",
          "full_name",
          "metadata"
        ],
        "type": "object"
      },
      "ChildIn": {
        "additionalProperties": false,
        "properties": {
          "birth_date": {
            "description": "Дата рождения — обязательна (`birth_date_required`): по ней\nназначается отряд, узнаётся дубль и ребёнок в базе лагеря",
            "example": "2015-05-05",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "city_id": {
            "description": "Город — из справочника городов",
            "type": "string"
          },
          "full_name": {
            "description": "ФИО ребёнка",
            "example": "Иванов Иван Иванович",
            "type": "string"
          }
        },
        "required": [
          "full_name",
          "birth_date",
          "city_id"
        ],
        "type": "object"
      },
      "ChildPatch": {
        "additionalProperties": false,
        "description": "Свой номер и метки ребёнка. Отсутствующее поле — не менять.",
        "properties": {
          "external_id": {
            "description": "Номер ребёнка в вашей CRM. `null` — стереть номер, поле\nне передано — не менять",
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Metadata",
                "description": "Заменяет метки целиком"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object"
      },
      "City": {
        "description": "Город из справочника.",
        "properties": {
          "id": {
            "example": "3",
            "type": "string"
          },
          "name": {
            "example": "Астана",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "Client": {
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "CreateRequest": {
        "additionalProperties": false,
        "description": "Новая бронь.",
        "properties": {
          "child": {
            "$ref": "#/components/schemas/ChildIn"
          },
          "comment": {
            "type": [
              "string",
              "null"
            ]
          },
          "discount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DiscountIn"
              },
              {
                "type": "null"
              }
            ]
          },
          "external_id": {
            "description": "Номер записи в вашей CRM. Уникален внутри отдела",
            "type": [
              "string",
              "null"
            ]
          },
          "invoice": {
            "description": "Счёт Kaspi при оформлении: `min` — минимальный платёж (по умолчанию,\nесли он у смены задан), `full` — вся сумма, `none` — не выставлять",
            "example": "min",
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Metadata",
                "description": "Ваши метки: до 20 пар"
              },
              {
                "type": "null"
              }
            ]
          },
          "needs_transfer": {
            "description": "Нужен ли трансфер",
            "type": "boolean"
          },
          "parent": {
            "$ref": "#/components/schemas/ParentIn"
          },
          "partner_manager": {
            "description": "Кто продал в вашей CRM (до 200 знаков)",
            "type": [
              "string",
              "null"
            ]
          },
          "payer_phone": {
            "description": "Телефон плательщика, если платит не родитель: счета Kaspi уйдут\nна него",
            "type": [
              "string",
              "null"
            ]
          },
          "shift_id": {
            "type": "string"
          },
          "together_with": {
            "description": "«Поселить вместе» с этими бронями той же смены (ваши брони),\nне больше 50",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "transfer_point_id": {
            "description": "Точка посадки — обязательна, если трансфер нужен",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "shift_id",
          "child",
          "parent"
        ],
        "type": "object"
      },
      "CreateWebhook": {
        "additionalProperties": false,
        "properties": {
          "event_types": {
            "description": "Только эти типы событий: любые из `Event.type`, кроме `ping`\n(он приходит только на проверку). Незнакомый тип — отказ\n`bad_event_type`. Нет или пусто — все, включая будущие",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "url": {
            "description": "Только `https://`, публичный адрес, без логина и `#`",
            "example": "https://crm.example.kz/hooks/camp",
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "Debt": {
        "properties": {
          "booking_id": {
            "type": "string"
          },
          "child_full_name": {
            "type": "string"
          },
          "debt": {
            "$ref": "#/components/schemas/Money"
          },
          "full_payment_due": {
            "description": "До какой даты внести всю сумму",
            "format": "date",
            "type": "string"
          },
          "overdue": {
            "description": "Срок полной оплаты прошёл, а долг остался",
            "type": "boolean"
          },
          "paid": {
            "$ref": "#/components/schemas/Money"
          },
          "payment_state": {
            "description": "awaiting — место придержано до минимального платежа, secured —\nзакреплено. Список может пополняться",
            "example": "secured",
            "type": "string"
          },
          "shift_id": {
            "type": "string"
          },
          "total": {
            "$ref": "#/components/schemas/Money",
            "description": "К оплате по брони"
          }
        },
        "required": [
          "booking_id",
          "child_full_name",
          "shift_id",
          "total",
          "paid",
          "debt",
          "full_payment_due",
          "overdue",
          "payment_state"
        ],
        "type": "object"
      },
      "Delivery": {
        "properties": {
          "at": {
            "format": "date-time",
            "type": "string"
          },
          "duration_ms": {
            "format": "int32",
            "type": "integer"
          },
          "error": {
            "description": "Что пошло не так (начало ответа вашего сервера или причина сбоя)",
            "type": [
              "string",
              "null"
            ]
          },
          "event_id": {
            "description": "Номер события; нет — проверочный `ping`",
            "type": [
              "string",
              "null"
            ]
          },
          "event_type": {
            "example": "booking.created",
            "type": "string"
          },
          "id": {
            "example": "90211",
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "status": {
            "description": "Код ответа вашего сервера; нет — ответа не было",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "at",
          "event_type",
          "ok",
          "duration_ms"
        ],
        "type": "object"
      },
      "Department": {
        "properties": {
          "id": {
            "example": "4",
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "Discount": {
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "note": {
            "description": "За что скидка",
            "type": "string"
          }
        },
        "required": [
          "amount",
          "note"
        ],
        "type": "object"
      },
      "DiscountIn": {
        "additionalProperties": false,
        "properties": {
          "amount": {
            "description": "Сумма скидки в тенге строкой: целое или до двух знаков после точки.\nНе больше наибольшей скидки смены (`max_discount`)",
            "example": "5000.00",
            "pattern": "^[0-9]+(\\.[0-9]{1,2})?$",
            "type": "string"
          },
          "note": {
            "description": "За что скидка",
            "type": "string"
          }
        },
        "required": [
          "amount"
        ],
        "type": "object"
      },
      "ErrorBody": {
        "description": "Тело ошибки. `request_id` дописывает слой (layer.rs) — по нему\nмы находим запрос в журнале, когда партнёр пишет в поддержку.",
        "properties": {
          "code": {
            "description": "Машинный код. Не меняется никогда — по нему ветвится ваша CRM",
            "example": "quota_exhausted",
            "type": "string"
          },
          "message": {
            "description": "Текст для человека, по-русски",
            "type": "string"
          },
          "request_id": {
            "description": "Номер запроса для обращения в поддержку",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "Event": {
        "description": "Событие ленты.",
        "properties": {
          "data": {
            "description": "Подробности, которых нет в самой записи. Сейчас бывают:\n`booking.moved` — `{\"from_shift_id\": \"12\"}` (с какой смены);\n`client.merged` — `{\"into_id\": \"812\"}` (в какую семью слита);\n`kaspi.operations.synced` — `{\"date_from\": \"2026-06-14\",\n\"date_to\": \"2026-06-14\", \"count\": 37}` (за какие дни загружена\nвыписка и сколько в ней операций за эти дни);\n`ping` — `{\"message\": \"…\"}`. У остальных — `null`. Поля только\nдобавляются"
          },
          "entity": {
            "$ref": "#/components/schemas/EventEntity",
            "description": "Чего касается событие"
          },
          "id": {
            "description": "Номер события — он же место в ленте. Растёт, не повторяется.\nПовтор доставки узнаётся по нему",
            "example": "1042",
            "type": "string"
          },
          "object": {
            "description": "Текущий вид записи — тот же, что вернул бы GET по ней, по\n`entity.type`: `booking` — `Booking`, `invoice` — `Invoice`,\n`payment` — `Payment`, `refund_request` — `RefundRequest`,\n`child` — `Child`, `parent` — `Family`,\n`shift` — `Shift`. `null`, если запись вам больше не видна\n(ребёнок ушёл в другой отдел) или у сущности нет вида (`ping`)"
          },
          "occurred_at": {
            "format": "date-time",
            "type": "string"
          },
          "type": {
            "description": "Тип события. Сейчас бывают:\n`booking.created`, `booking.updated`, `booking.cancelled`,\n`booking.restored`, `booking.moved`, `booking.hold_expired`,\n`booking.secured`, `booking.removed`, `invoice.queued`,\n`invoice.issued`, `invoice.paid`, `invoice.cancelled`,\n`invoice.expired`, `invoice.error`, `invoice.mismatch`,\n`payment.received`, `payment.refunded`, `payment.verified`, `payment.updated`,\n`refund_request.created`, `refund_request.approved`, `refund_request.rejected`,\n`refund_request.cancelled`, `refund_request.done`, `refund_request.failed`,\n`voucher.ready`, `voucher.sent`, `child.checked_in`,\n`child.checked_out`, `child.added`, `child.removed`,\n`shift.seats_changed`, `shift.status_changed`, `client.merged`,\n`child.merged`, `kaspi.operations.synced` (только главному отделу);\n`ping` — только проверка вебхука (`POST /webhooks/{id}/test`).\nСписок открытый и пополняется: незнакомый тип пропустите, а не падайте",
            "example": "booking.created",
            "type": "string"
          }
        },
        "required": [
          "id",
          "type",
          "occurred_at",
          "entity"
        ],
        "type": "object"
      },
      "EventEntity": {
        "properties": {
          "id": {
            "example": "15230",
            "type": "string"
          },
          "type": {
            "description": "booking, invoice, payment, refund_request, child, parent, shift;\n`webhook` — у `ping`;\n`kaspi_sync` — у `kaspi.operations.synced` (номер загрузки выписки).\nСписок может пополняться",
            "example": "booking",
            "type": "string"
          }
        },
        "required": [
          "type",
          "id"
        ],
        "type": "object"
      },
      "EventPage": {
        "properties": {
          "has_more": {
            "description": "Есть ещё события после этой порции — запросите сразу, не дожидаясь",
            "type": "boolean"
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "next_after": {
            "description": "Передать в `after` следующего запроса. Совпадает с последним\nномером в `items`; если событий не было — с вашим `after`",
            "type": "string"
          }
        },
        "required": [
          "items",
          "next_after",
          "has_more"
        ],
        "type": "object"
      },
      "Family": {
        "description": "Семья: родитель, ваши дети и ваши брони.\n\nЕсли семью ведёт и другой отдел (`shared`), её общие данные вам\nне показываются: `full_name` — как вы записали родителя в своей\nброни, `extra_phones` пуст, `city` нет. Править ФИО, город, согласие\nи вторые номера такой семьи нельзя (`403 family_shared`); свои\n`external_id` и `metadata` — можно.",
        "properties": {
          "bookings": {
            "description": "Ваши брони детей этой семьи, свежие первыми",
            "items": {
              "$ref": "#/components/schemas/BookingSummary"
            },
            "type": "array"
          },
          "children": {
            "description": "Только ваши дети. Брат или сестра, которых ведёт другой отдел,\nздесь не показываются",
            "items": {
              "$ref": "#/components/schemas/Child"
            },
            "type": "array"
          },
          "city": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/City"
              },
              {
                "type": "null"
              }
            ]
          },
          "external_id": {
            "description": "Номер семьи в вашей CRM",
            "type": [
              "string",
              "null"
            ]
          },
          "extra_phones": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "full_name": {
            "type": "string"
          },
          "id": {
            "example": "812",
            "type": "string"
          },
          "marketing_opt_in": {
            "description": "Согласие на рассылки",
            "type": "boolean"
          },
          "merged_from": {
            "description": "Номера карточек, слитых в эту (дубли семьи). Запрос по старому\nномеру отвечает этой карточкой",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "phone": {
            "description": "Основной телефон, +7XXXXXXXXXX. Ключ узнавания семьи: через API\nне меняется, второй номер — в `extra_phones`",
            "example": "+77010000001",
            "type": "string"
          },
          "shared": {
            "description": "Семью ведёт и другой отдел: общие данные семьи скрыты и не правятся",
            "type": "boolean"
          },
          "version": {
            "description": "Версия записи для `If-Match` при правке",
            "example": "3",
            "type": "string"
          }
        },
        "required": [
          "id",
          "full_name",
          "phone",
          "extra_phones",
          "marketing_opt_in",
          "shared",
          "metadata",
          "version",
          "merged_from",
          "children",
          "bookings"
        ],
        "type": "object"
      },
      "FamilyChild": {
        "additionalProperties": false,
        "description": "Ребёнок в оформлении семьи.",
        "properties": {
          "child": {
            "$ref": "#/components/schemas/ChildIn"
          },
          "comment": {
            "type": [
              "string",
              "null"
            ]
          },
          "discount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DiscountIn"
              },
              {
                "type": "null"
              }
            ]
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "invoice": {
            "description": "Счёт этому ребёнку; нет — общий `invoice` запроса",
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Metadata"
              },
              {
                "type": "null"
              }
            ]
          },
          "needs_transfer": {
            "type": "boolean"
          },
          "partner_manager": {
            "type": [
              "string",
              "null"
            ]
          },
          "shift_id": {
            "type": "string"
          },
          "transfer_point_id": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "shift_id",
          "child"
        ],
        "type": "object"
      },
      "FamilyPatch": {
        "additionalProperties": false,
        "description": "Правка семьи. Отсутствующее поле — не менять.",
        "properties": {
          "city_id": {
            "description": "Город родителя; null — стереть",
            "type": [
              "string",
              "null"
            ]
          },
          "external_id": {
            "description": "Номер семьи в вашей CRM. `null` — стереть номер, поле\nне передано — не менять",
            "type": [
              "string",
              "null"
            ]
          },
          "extra_phones": {
            "description": "Вторые номера семьи — заменяют список целиком. Номер, записанный\nза другой семьёй, не принимается (`phone_taken`). ФИО, город,\nсогласие и вторые номера семьи, которую ведёт и другой отдел\n(`shared`), не правятся (`family_shared`)",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "marketing_opt_in": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "metadata": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Metadata",
                "description": "Заменяет метки целиком"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object"
      },
      "FamilyPayment": {
        "description": "Платёж по вашей брони этой семьи.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "booking_id": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "paid_on": {
            "description": "День оплаты по календарю лагеря (дата, без времени)",
            "format": "date",
            "type": "string"
          },
          "type": {
            "description": "prepayment, payment, refund. Список может пополняться",
            "example": "payment",
            "type": "string"
          },
          "verified": {
            "description": "Сверен бухгалтерией",
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "booking_id",
          "paid_on",
          "amount",
          "type",
          "verified"
        ],
        "type": "object"
      },
      "Handover": {
        "properties": {
          "job": {
            "example": "batch-7f3a",
            "type": "string"
          },
          "keys": {
            "description": "Строки, переданные этому заданию (сейчас или раньше). Проводите\nтолько их: остальные ведёт система лагеря или уже взяло другое\nзадание",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "job",
          "keys"
        ],
        "type": "object"
      },
      "HandoverRequest": {
        "additionalProperties": false,
        "description": "Передать строки заданию пачки.",
        "properties": {
          "job": {
            "description": "Номер задания пачки: латиница, цифры и `._:-`, до 100 знаков,\nначинается с буквы или цифры",
            "example": "batch-7f3a",
            "type": "string"
          },
          "keys": {
            "description": "Ключи строк, не больше 100",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "job",
          "keys"
        ],
        "type": "object"
      },
      "HistoryChange": {
        "properties": {
          "field": {
            "description": "Поле брони: `child.full_name`, `parent.phone`, `discount.amount`…\nСписок может пополняться",
            "type": "string"
          },
          "new": {
            "description": "Новое значение; `null` — стёрто. Вид — как у `old`"
          },
          "old": {
            "description": "Прежнее значение; `null` — не было. Вид — как у поля в брони:\nстрока, число, true/false, метки (объект); денежные поля\n(`price`, `transfer.fee`, `discount.amount`) — `Money`\n`{\"amount\": \"119000.00\", \"currency\": \"KZT\"}`"
          }
        },
        "required": [
          "field"
        ],
        "type": "object"
      },
      "HistoryEntry": {
        "properties": {
          "action": {
            "description": "create, update, cancel, restore, copy, ext_ref, voucher_sent…\nСписок может пополняться",
            "example": "update",
            "type": "string"
          },
          "actor": {
            "description": "Ваше подключение (по имени) или «Лагерь» — для всех сотрудников\nлагеря и фоновых задач",
            "type": "string"
          },
          "at": {
            "format": "date-time",
            "type": "string"
          },
          "changes": {
            "description": "Что изменилось",
            "items": {
              "$ref": "#/components/schemas/HistoryChange"
            },
            "type": "array"
          }
        },
        "required": [
          "action",
          "at",
          "actor",
          "changes"
        ],
        "type": "object"
      },
      "HistoryPage": {
        "description": "История брони порциями, от старых записей к новым.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/HistoryEntry"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию. Нет —\nдальше ничего нет",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Invoice": {
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "booking_id": {
            "type": "string"
          },
          "cancelling": {
            "description": "Отмену попросили, счёт ещё гасится в Kaspi. Пока это так, его\nвсё ещё можно оплатить",
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "error": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/InvoiceProblem",
                "description": "Что пошло не так или чего счёт ждёт. Нет — всё в порядке"
              },
              {
                "type": "null"
              }
            ]
          },
          "id": {
            "example": "731",
            "type": "string"
          },
          "issued_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "paid_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "payment_id": {
            "description": "Платёж, созданный оплатой этого счёта",
            "type": [
              "string",
              "null"
            ]
          },
          "payment_type": {
            "description": "Чем станет оплата: prepayment — предоплата, payment — оплата",
            "example": "prepayment",
            "type": "string"
          },
          "phone": {
            "description": "Телефон плательщика, на который ушёл счёт. Пусто, если ребёнок\nперешёл в другой отдел: контакты семьи вам больше не показываются",
            "type": [
              "string",
              "null"
            ]
          },
          "purpose": {
            "description": "Текст, который плательщик видит в Kaspi рядом с суммой",
            "type": "string"
          },
          "state": {
            "description": "queued — ждёт отправки в Kaspi, issued — у плательщика в Kaspi,\npaid — оплачен, expired — не оплачен в срок, cancelled — отменён,\nerror — не выставлен, mismatch — Kaspi сообщил о другой сумме,\nлагерь проверяет. Список может пополняться",
            "example": "issued",
            "type": "string"
          },
          "version": {
            "description": "Версия записи: меняется при каждом изменении счёта",
            "type": "string"
          }
        },
        "required": [
          "id",
          "booking_id",
          "amount",
          "state",
          "cancelling",
          "payment_type",
          "purpose",
          "created_at",
          "version"
        ],
        "type": "object"
      },
      "InvoiceProblem": {
        "properties": {
          "code": {
            "description": "Машинный код. Список может пополняться",
            "example": "rejected",
            "type": "string"
          },
          "message": {
            "description": "Текст для человека",
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "InvoiceReplacing": {
        "description": "Ответ на замену счёта: старый гасится, новый уйдёт сразу после этого.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money",
            "description": "Сумма нового счёта"
          },
          "replaces": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Invoice",
                "description": "Счёт, который гасится. Новый придёт событием `invoice.queued`"
              },
              {
                "type": "null"
              }
            ]
          },
          "state": {
            "description": "Всегда `replacing`",
            "example": "replacing",
            "type": "string"
          }
        },
        "required": [
          "state",
          "amount"
        ],
        "type": "object"
      },
      "KaspiOperation": {
        "description": "Операция выписки Kaspi Pay лагеря.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money",
            "description": "Сумма. Поступление — плюсом, возврат и прочий расход — минусом"
          },
          "booking_id": {
            "description": "Бронь этого счёта",
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "description": "День операции по календарю лагеря (Asia/Almaty)",
            "format": "date",
            "type": "string"
          },
          "fee": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money",
                "description": "Комиссия Kaspi, если Kaspi её назвал"
              },
              {
                "type": "null"
              }
            ]
          },
          "id": {
            "description": "Номер операции в Kaspi",
            "example": "880001",
            "type": "string"
          },
          "invoice_id": {
            "description": "Счёт Kaspi лагеря, оплатой которого стала операция",
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "description": "payment — поступление, refund — возврат, other — прочее\n(в том числе неудавшаяся операция). Список может пополняться",
            "example": "payment",
            "type": "string"
          },
          "legal_entity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/LegalEntity",
                "description": "Юрлицо кассы, в выписке которой операция (у лагеря несколько\nкасс Kaspi Pay — у каждой своё юрлицо и свой счёт зачисления).\nНет — операция загружена до появления касс"
              },
              {
                "type": "null"
              }
            ]
          },
          "method": {
            "description": "qr — оплата по QR, remote — счёт на телефон, unknown — не\nопределён. Список может пополняться",
            "example": "remote",
            "type": "string"
          },
          "occurred_at": {
            "description": "Время операции",
            "format": "date-time",
            "type": "string"
          },
          "payment_id": {
            "description": "Платёж, созданный оплатой счёта (только у `payment`)",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "occurred_at",
          "date",
          "amount",
          "kind",
          "method"
        ],
        "type": "object"
      },
      "KaspiOperationPage": {
        "description": "Порция выписки.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/KaspiOperation"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          },
          "synced_through": {
            "description": "До какого времени выписка загружена полностью. Операции позже\nмогут ещё дозагрузиться; `null` — выписка ещё ни разу не\nзагружалась целиком",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "LegalEntity": {
        "description": "Юрлицо лагеря, на которое пришли деньги",
        "properties": {
          "bin": {
            "description": "БИН (ТОО) или ИИН (ИП), если записан",
            "example": "123456789012",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "example": "2",
            "type": "string"
          },
          "iik": {
            "description": "ИИК (IBAN) счёта, на который зачислены деньги, если записан",
            "example": "KZ12722S000000000001",
            "type": [
              "string",
              "null"
            ]
          },
          "legal_name": {
            "description": "Полное юридическое название, если записано",
            "example": "ТОО «Эдельвейс»",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "description": "Короткое имя, как его видят в лагере",
            "example": "ТОО Эдельвейс",
            "type": "string"
          },
          "onec_organization": {
            "description": "Организация в 1С, куда проводить эти деньги (Ref_Key или БИН),\nесли записана в лагере",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "Limits": {
        "properties": {
          "bookings_per_minute": {
            "description": "Новых броней отделом в минуту",
            "format": "int32",
            "type": "integer"
          },
          "concurrent": {
            "description": "Одновременных запросов",
            "format": "int32",
            "type": "integer"
          },
          "invoices_per_booking_hour": {
            "description": "Счетов Kaspi на одну бронь в час",
            "format": "int32",
            "type": "integer"
          },
          "read_per_sec": {
            "description": "Чтений в секунду",
            "format": "int32",
            "type": "integer"
          },
          "write_per_sec": {
            "description": "Записей в секунду",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "read_per_sec",
          "write_per_sec",
          "concurrent",
          "bookings_per_minute",
          "invoices_per_booking_hour"
        ],
        "type": "object"
      },
      "Me": {
        "properties": {
          "client": {
            "$ref": "#/components/schemas/Client",
            "description": "Подключение, к которому выпущен ключ"
          },
          "department": {
            "$ref": "#/components/schemas/Department"
          },
          "limits": {
            "$ref": "#/components/schemas/Limits"
          },
          "scopes": {
            "description": "Права ключа: read, bookings, invoices, webhooks",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "department",
          "client",
          "scopes",
          "limits"
        ],
        "type": "object"
      },
      "Metadata": {
        "additionalProperties": {
          "maxLength": 500,
          "type": [
            "string",
            "number",
            "boolean",
            "null"
          ]
        },
        "description": "Ваши метки: до 20 пар «ключ — значение». Ключ — от 1 до 40 знаков, значение — строка (до 500 знаков), число, true/false или null. Мы их не разбираем: только храним и возвращаем",
        "examples": [
          {
            "deal_id": "D-1042",
            "priority": 2
          }
        ],
        "maxProperties": 20,
        "propertyNames": {
          "maxLength": 40,
          "minLength": 1,
          "type": "string"
        },
        "type": "object"
      },
      "Money": {
        "description": "Деньги: сумма строкой с двумя знаками и валютой. Строкой, а не\nчислом — дробные числа в чужих языках теряют копейки.",
        "properties": {
          "amount": {
            "description": "Сумма с двумя знаками после точки",
            "example": "119000.00",
            "type": "string"
          },
          "currency": {
            "description": "Валюта, ISO 4217. Сейчас всегда KZT",
            "example": "KZT",
            "type": "string"
          }
        },
        "required": [
          "amount",
          "currency"
        ],
        "type": "object"
      },
      "MoveRequest": {
        "additionalProperties": false,
        "properties": {
          "shift_id": {
            "description": "Смена, на которую переносится ребёнок",
            "type": "string"
          }
        },
        "required": [
          "shift_id"
        ],
        "type": "object"
      },
      "NewInvoice": {
        "additionalProperties": false,
        "properties": {
          "amount": {
            "description": "Сумма для `kind = amount`: тенге строкой, не больше остатка брони.\nТолько целые тенге: `\"50000\"` или `\"50000.00\"`; дробная часть —\nотказ `fractional_amount`",
            "example": "50000",
            "pattern": "^[0-9]+(\\.0{1,2})?$",
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "description": "На что выставить: `min` — минимальный платёж, которым закрепляется\nместо (сколько его ещё не внесено); `full` — весь остаток;\n`amount` — своя сумма из поля `amount`",
            "example": "min",
            "type": "string"
          },
          "replace": {
            "description": "Заменить незакрытый счёт брони новым (документ 17 §6: плательщик\nпросит счёт на другую сумму). Без этого при живом счёте — отказ\n`invoice_live`",
            "type": "boolean"
          }
        },
        "required": [
          "kind"
        ],
        "type": "object"
      },
      "NewRefundRequest": {
        "additionalProperties": false,
        "properties": {
          "amount": {
            "description": "Сколько вернуть: тенге строкой, только целые (`\"30000\"` или\n`\"30000.00\"`), не больше остатка оплаты за вычетом прежних\nи ждущих возвратов (`refund_exceeds_refundable`)",
            "example": "30000",
            "pattern": "^[0-9]+(\\.0{1,2})?$",
            "type": "string"
          },
          "payment_id": {
            "description": "Оплата брони по счёту Kaspi (`Payment.id`). Оплата другим\nспособом возвращается только лагерем — отказ `refund_not_kaspi_invoice`",
            "example": "9120",
            "type": "string"
          },
          "reason": {
            "description": "Почему возвращаем — увидит тот, кто решает. 1–500 знаков",
            "example": "Ребёнок заболел, смена отменена",
            "type": "string"
          }
        },
        "required": [
          "payment_id",
          "amount",
          "reason"
        ],
        "type": "object"
      },
      "Page_Booking": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Booking"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_BookingVersion": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/BookingVersion"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Child": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Child"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Debt": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Debt"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Delivery": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Delivery"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Family": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Family"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_FamilyPayment": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/FamilyPayment"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Invoice": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Invoice"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Payment": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Payment"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_RefundRequest": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/RefundRequest"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Shift": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Shift"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Unpaid": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Unpaid"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "Page_Webhook": {
        "description": "Порция списка. `next_cursor` пуст — дальше ничего нет.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Webhook"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Передать в `cursor`, чтобы получить следующую порцию",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "ParentIn": {
        "additionalProperties": false,
        "properties": {
          "full_name": {
            "description": "ФИО родителя",
            "type": "string"
          },
          "phone": {
            "description": "Телефон родителя, любой записью: «8 701…», «+7 701…»",
            "example": "+77011234567",
            "type": "string"
          }
        },
        "required": [
          "full_name",
          "phone"
        ],
        "type": "object"
      },
      "ParentPatch": {
        "additionalProperties": false,
        "properties": {
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PatchRequest": {
        "additionalProperties": false,
        "description": "Правка брони: только переданные поля.",
        "properties": {
          "child": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BookingChildPatch"
              },
              {
                "type": "null"
              }
            ]
          },
          "comment": {
            "type": [
              "string",
              "null"
            ]
          },
          "discount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DiscountIn"
              },
              {
                "type": "null"
              }
            ]
          },
          "external_id": {
            "description": "Номер записи в вашей CRM. `null` — стереть номер, поле\nне передано — не менять",
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Metadata",
                "description": "Заменяет метки целиком"
              },
              {
                "type": "null"
              }
            ]
          },
          "needs_transfer": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "parent": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ParentPatch"
              },
              {
                "type": "null"
              }
            ]
          },
          "partner_manager": {
            "description": "Пустая строка — снять",
            "type": [
              "string",
              "null"
            ]
          },
          "payer_phone": {
            "description": "Телефон плательщика; пустая строка — платит родитель",
            "type": [
              "string",
              "null"
            ]
          },
          "transfer_point_id": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PatchWebhook": {
        "additionalProperties": false,
        "properties": {
          "enabled": {
            "description": "false — отключить, true — включить (сбрасывает счёт неудач)",
            "type": [
              "boolean",
              "null"
            ]
          },
          "event_types": {
            "description": "Типы событий, как у `CreateWebhook.event_types`. Пустой список —\nвсе типы",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "Payment": {
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money",
            "description": "Сумма. Возврат — отрицательной суммой"
          },
          "bank": {
            "description": "Банк, как его записал лагерь",
            "example": "Kaspi",
            "type": "string"
          },
          "booking_id": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "example": "5120",
            "type": "string"
          },
          "invoice_id": {
            "description": "Счёт Kaspi, оплатой которого создан платёж",
            "type": [
              "string",
              "null"
            ]
          },
          "legal_entity": {
            "$ref": "#/components/schemas/LegalEntity",
            "description": "Юрлицо лагеря, на которое пришли деньги. У оплаты счёта Kaspi —\nюрлицо кассы, через которую счёт выставлен (у лагеря их\nнесколько, и касса переключается). Возврат делается с этого\nже юрлица"
          },
          "method": {
            "description": "Как заплатили: kaspi_transfer — перевод на Kaspi лагеря,\nbank_transfer — банковский перевод, cash — наличные, kaspi_invoice —\nсчёт Kaspi. `null` — не указано (записи до этого поля). Список\nможет пополняться",
            "example": "kaspi_transfer",
            "type": [
              "string",
              "null"
            ]
          },
          "paid_on": {
            "description": "День оплаты по календарю лагеря (дата, без времени)",
            "format": "date",
            "type": "string"
          },
          "source": {
            "description": "Откуда платёж: kaspi_invoice — оплата счёта Kaspi, manual — внесён\nлагерем. Список может пополняться",
            "example": "kaspi_invoice",
            "type": "string"
          },
          "statement_line": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/StatementLineRef",
                "description": "Строка выписки банка, с которой бухгалтерия лагеря сверила платёж.\nЕсть только у сверенного (`verified`) платежа"
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "description": "prepayment — предоплата, payment — оплата, refund — возврат.\nСписок может пополняться",
            "example": "prepayment",
            "type": "string"
          },
          "verified": {
            "description": "Сверен бухгалтерией лагеря с выпиской банка. Остаток по брони\nуменьшает и несверенный платёж",
            "type": "boolean"
          },
          "version": {
            "description": "Версия записи: меняется при каждом изменении платежа",
            "type": "string"
          }
        },
        "required": [
          "id",
          "booking_id",
          "amount",
          "type",
          "paid_on",
          "verified",
          "source",
          "bank",
          "legal_entity",
          "created_at",
          "version"
        ],
        "type": "object"
      },
      "Pdf": {
        "description": "Двоичный PDF.",
        "format": "binary",
        "type": "string"
      },
      "Quote": {
        "properties": {
          "discount": {
            "$ref": "#/components/schemas/Money"
          },
          "full_payment_due": {
            "description": "До какой даты внести всю сумму",
            "format": "date",
            "type": "string"
          },
          "hold_hours": {
            "description": "Сколько часов держится место без минимального платежа; нет —\nпредоплата не нужна",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "min_payment_now": {
            "$ref": "#/components/schemas/Money",
            "description": "Минимальный платёж: им бронируется место, на него уйдёт счёт при\nоформлении. Ноль — бронь без предоплаты"
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "$ref": "#/components/schemas/Money",
            "description": "К оплате всего"
          },
          "transfer_fee": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "price",
          "transfer_fee",
          "discount",
          "total",
          "min_payment_now",
          "full_payment_due"
        ],
        "type": "object"
      },
      "QuoteRequest": {
        "additionalProperties": false,
        "properties": {
          "discount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DiscountIn"
              },
              {
                "type": "null"
              }
            ]
          },
          "needs_transfer": {
            "type": "boolean"
          },
          "shift_id": {
            "type": "string"
          },
          "transfer_point_id": {
            "description": "Точка посадки: у сезона с ценами по городам цена трансфера своя\nу каждого города. При одной цене на всех можно не указывать",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "shift_id"
        ],
        "type": "object"
      },
      "Redeliver": {
        "additionalProperties": false,
        "properties": {
          "after": {
            "description": "Отправить заново всё ПОСЛЕ этого номера события. Номер меньше\nдоставленного — повтор, больше — пропуск",
            "example": "1000",
            "type": "string"
          }
        },
        "required": [
          "after"
        ],
        "type": "object"
      },
      "RefundRequest": {
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "booking_id": {
            "type": "string"
          },
          "by_api": {
            "description": "Подана вашим подключением (а не сотрудником лагеря)",
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "decided_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "finished_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "example": "41",
            "type": "string"
          },
          "invoice_id": {
            "description": "Счёт Kaspi этой оплаты",
            "type": "string"
          },
          "payment_id": {
            "description": "Оплата по счёту Kaspi, которую возвращают",
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "refund_payment_id": {
            "description": "Платёж-возврат, записанный по выполненному возврату (`done`)",
            "type": [
              "string",
              "null"
            ]
          },
          "reject_reason": {
            "description": "Причина отказа лагеря (только у `rejected`)",
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "description": "requested — ждёт решения лагеря; approved — одобрена, возврат\nвыполняется; sending — отправлен в Kaspi; needs_check — Kaspi\nне ответил, лагерь проверяет вручную; done — деньги возвращены\nплательщику; failed — Kaspi отказал, денег не ушло; rejected —\nлагерь отклонил (причина в `reject_reason`); cancelled — отозвана\nавтором. Список может пополняться",
            "example": "requested",
            "type": "string"
          },
          "version": {
            "description": "Версия записи: меняется при каждом изменении заявки",
            "type": "string"
          }
        },
        "required": [
          "id",
          "booking_id",
          "payment_id",
          "invoice_id",
          "amount",
          "reason",
          "state",
          "by_api",
          "created_at",
          "version"
        ],
        "type": "object"
      },
      "Season": {
        "properties": {
          "id": {
            "example": "3",
            "type": "string"
          },
          "name": {
            "example": "Лето 2027",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "Seats": {
        "properties": {
          "free": {
            "description": "Свободно",
            "format": "int64",
            "type": "integer"
          },
          "quota": {
            "description": "Квота отдела на смену; 0 — квоты нет, оформить нельзя",
            "format": "int32",
            "type": "integer"
          },
          "taken": {
            "description": "Занято активными бронями отдела (включая ждущие предоплату)",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "quota",
          "taken",
          "free"
        ],
        "type": "object"
      },
      "Shift": {
        "properties": {
          "age_groups": {
            "description": "Возрастные границы отрядов. Пусто — сетка ещё не задана",
            "items": {
              "$ref": "#/components/schemas/AgeGroup"
            },
            "type": "array"
          },
          "date_end": {
            "format": "date",
            "type": "string"
          },
          "date_start": {
            "format": "date",
            "type": "string"
          },
          "full_payment_due": {
            "description": "До какой даты внести всю сумму: автоматический счёт на остаток\nуходит в этот день",
            "format": "date",
            "type": "string"
          },
          "id": {
            "example": "12",
            "type": "string"
          },
          "max_discount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money",
                "description": "Наибольшая скидка без администратора; нет — без ограничения"
              },
              {
                "type": "null"
              }
            ]
          },
          "min_payment": {
            "$ref": "#/components/schemas/Money",
            "description": "Минимальный платёж, которым бронируется место. Ноль — бронь без\nпредоплаты"
          },
          "number": {
            "description": "Номер смены в сезоне",
            "format": "int32",
            "type": "integer"
          },
          "on_sale": {
            "description": "Можно ли сейчас оформить бронь: смена открыта и окно продаж не закрылось",
            "type": "boolean"
          },
          "price": {
            "$ref": "#/components/schemas/Money",
            "description": "Цена путёвки"
          },
          "sales_close_at": {
            "description": "Когда закрываются продажи",
            "format": "date-time",
            "type": "string"
          },
          "season": {
            "$ref": "#/components/schemas/Season"
          },
          "seats": {
            "$ref": "#/components/schemas/Seats",
            "description": "Места в квоте вашего отдела"
          },
          "status": {
            "description": "draft — готовится, open — продажи открыты, closed — продажи закрыты,\ndeparted — смена идёт, finished — завершена. Список может пополняться",
            "example": "open",
            "type": "string"
          },
          "transfer_price": {
            "$ref": "#/components/schemas/Money",
            "description": "Цена трансфера. При ценах по городам — самая низкая из них\n(цена «от»); сами цены — в `transfer_prices`"
          },
          "transfer_prices": {
            "description": "Цены трансфера по точкам посадки. Пусто — одна цена `transfer_price`\nна все точки. Точки, которой здесь нет, на смену не возят",
            "items": {
              "$ref": "#/components/schemas/TransferPrice"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "season",
          "number",
          "date_start",
          "date_end",
          "status",
          "on_sale",
          "sales_close_at",
          "price",
          "transfer_price",
          "transfer_prices",
          "min_payment",
          "full_payment_due",
          "seats",
          "age_groups"
        ],
        "type": "object"
      },
      "ShiftRef": {
        "properties": {
          "date_start": {
            "format": "date",
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "number": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "number",
          "date_start"
        ],
        "type": "object"
      },
      "ShiftSales": {
        "properties": {
          "bookings": {
            "description": "Активных обычных броней",
            "format": "int64",
            "type": "integer"
          },
          "date_end": {
            "format": "date",
            "type": "string"
          },
          "date_start": {
            "format": "date",
            "type": "string"
          },
          "debt": {
            "$ref": "#/components/schemas/Money",
            "description": "Долг: продано минус оплачено"
          },
          "free": {
            "format": "int64",
            "type": "integer"
          },
          "number": {
            "description": "Номер смены в сезоне",
            "format": "int32",
            "type": "integer"
          },
          "paid": {
            "$ref": "#/components/schemas/Money",
            "description": "Оплачено по ним (все платежи, и ещё не сверенные бухгалтерией)"
          },
          "quota": {
            "description": "Квота отдела на смену",
            "format": "int32",
            "type": "integer"
          },
          "season_id": {
            "type": "string"
          },
          "shift_id": {
            "type": "string"
          },
          "sold": {
            "$ref": "#/components/schemas/Money",
            "description": "Продано: сумма к оплате по активным броням"
          },
          "taken": {
            "description": "Занято активными бронями отдела (как в `GET /shifts`)",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "shift_id",
          "season_id",
          "number",
          "date_start",
          "date_end",
          "quota",
          "taken",
          "free",
          "bookings",
          "sold",
          "paid",
          "debt"
        ],
        "type": "object"
      },
      "ShiftSalesReport": {
        "description": "Отчёт по сменам — все смены одним ответом, без порций: их десятки.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/ShiftSales"
            },
            "type": "array"
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "StatementClaim": {
        "description": "Решение по одной строке.",
        "properties": {
          "handed_job": {
            "description": "Задание пачки, которому строка уже передана (`handover`)",
            "example": "batch-7f3a",
            "type": [
              "string",
              "null"
            ]
          },
          "key": {
            "description": "Ключ строки выписки (тот, что прислан в `keys`)",
            "example": "3f9a0c1d2b4e5f60",
            "type": "string"
          },
          "owner": {
            "description": "camp — строку ведёт система лагеря, accounting — бухгалтерия.\nСписок может пополняться: незнакомое значение не проводите",
            "example": "camp",
            "type": "string"
          },
          "payment_ids": {
            "description": "Платежи лагеря, с которыми сверена строка (у `linked`)",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "state": {
            "description": "pending — ждёт проверки; linked — сверена с платежами; organization —\nоплата организации; not_ours — не оплата путёвки; internal — перевод\nмежду своими счетами; outgoing — списание. Список может пополняться",
            "example": "linked",
            "type": "string"
          }
        },
        "required": [
          "key",
          "owner",
          "state",
          "payment_ids"
        ],
        "type": "object"
      },
      "StatementClaims": {
        "properties": {
          "accounts": {
            "description": "ИИК счетов лагеря (ТОО, ИП), без пробелов, верхним регистром.\nПоступление на такой счёт, которого CRM не видела, — выписку\nне загрузили в CRM",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "items": {
            "description": "Только строки, известные CRM; незнакомые ключи в ответ не попадают",
            "items": {
              "$ref": "#/components/schemas/StatementClaim"
            },
            "type": "array"
          }
        },
        "required": [
          "accounts",
          "items"
        ],
        "type": "object"
      },
      "StatementLineRef": {
        "description": "Строка выписки, с которой сверен платёж.",
        "properties": {
          "account_iik": {
            "description": "ИИК счёта лагеря, на который пришли деньги",
            "example": "KZ75125KZT1001300335",
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "description": "День строки в выписке банка",
            "format": "date",
            "type": "string"
          },
          "key": {
            "description": "Ключ строки выписки — тот же, что у разборщика выписок бухгалтерии",
            "example": "3f9a0c1d2b4e5f60",
            "type": "string"
          }
        },
        "required": [
          "key",
          "date"
        ],
        "type": "object"
      },
      "TestResult": {
        "properties": {
          "duration_ms": {
            "format": "int32",
            "type": "integer"
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "ok": {
            "description": "Адрес ответил 2xx",
            "type": "boolean"
          },
          "status": {
            "description": "Код ответа; нет — ответа не было (DNS, соединение, сертификат, время)",
            "format": "int32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "ok",
          "duration_ms"
        ],
        "type": "object"
      },
      "Together": {
        "properties": {
          "booking_ids": {
            "description": "Все брони связи, включая эту",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "description": "Номер связи «вместе»",
            "type": "string"
          }
        },
        "required": [
          "id",
          "booking_ids"
        ],
        "type": "object"
      },
      "TogetherRequest": {
        "additionalProperties": false,
        "properties": {
          "booking_ids": {
            "description": "С кем поселить: ваши брони той же смены, не больше 50",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "note": {
            "description": "Записка: «одна компания», «просила бабушка»",
            "type": "string"
          }
        },
        "required": [
          "booking_ids"
        ],
        "type": "object"
      },
      "Transfer": {
        "properties": {
          "fee": {
            "$ref": "#/components/schemas/Money",
            "description": "Цена трансфера в этой брони"
          },
          "needed": {
            "description": "Нужен ли трансфер",
            "type": "boolean"
          },
          "point": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/TransferPoint",
                "description": "Точка посадки"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "needed",
          "fee"
        ],
        "type": "object"
      },
      "TransferPoint": {
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "TransferPrice": {
        "properties": {
          "name": {
            "example": "Астана",
            "type": "string"
          },
          "price": {
            "$ref": "#/components/schemas/Money"
          },
          "transfer_point_id": {
            "example": "1",
            "type": "string"
          }
        },
        "required": [
          "transfer_point_id",
          "name",
          "price"
        ],
        "type": "object"
      },
      "Unpaid": {
        "properties": {
          "booking_id": {
            "type": "string"
          },
          "child_full_name": {
            "type": "string"
          },
          "hold_until": {
            "description": "До какого времени держалось место",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "min_payment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money",
                "description": "Сколько просили внести, чтобы закрепить место"
              },
              {
                "type": "null"
              }
            ]
          },
          "parent_full_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "parent_phone": {
            "description": "Телефоны — пока ребёнок в вашем отделе (docs: «Ваша база»)",
            "type": [
              "string",
              "null"
            ]
          },
          "payer_phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "shift_id": {
            "type": "string"
          }
        },
        "required": [
          "booking_id",
          "child_full_name",
          "shift_id"
        ],
        "type": "object"
      },
      "Voucher": {
        "properties": {
          "booking_id": {
            "type": "string"
          },
          "number": {
            "description": "Номер путёвки",
            "example": "05-012",
            "type": "string"
          },
          "pdf_available": {
            "description": "Файл можно скачать (`GET /bookings/{id}/voucher.pdf`)",
            "type": "boolean"
          },
          "pdf_url": {
            "description": "Ссылка на скачивание PDF без ключа, живёт 10 минут (`pdf_url_expires_at`).\nПриходит только в `GET /bookings/{id}/voucher`. `null` — ссылки нет\n(путёвка не выпущена или файл собирается для вашего отдела на лету) —\nтогда скачайте `GET /bookings/{id}/voucher.pdf`. Ссылку не храните:\nза новой — снова `GET /bookings/{id}/voucher`",
            "example": "https://hb.kz-ast.bizmrg.com/…/05-012.pdf?X-Amz-Signature=…",
            "type": [
              "string",
              "null"
            ]
          },
          "pdf_url_expires_at": {
            "description": "До какого момента действует `pdf_url`",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "none — не выпущена, generated — выпущена, sent — отмечена\nотправленной семье. Список может пополняться",
            "example": "generated",
            "type": "string"
          }
        },
        "required": [
          "booking_id",
          "number",
          "status",
          "pdf_available"
        ],
        "type": "object"
      },
      "Webhook": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "delivered_through": {
            "description": "Номер последнего доставленного события",
            "example": "1042",
            "type": "string"
          },
          "disabled_reason": {
            "description": "Почему отключён",
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "description": "false — отключён (вами или после трёх суток неудач)",
            "type": "boolean"
          },
          "event_types": {
            "description": "Какие типы событий слать (см. `Event.type`). Пусто — все",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "failed_attempts": {
            "description": "Неудачных попыток подряд",
            "format": "int32",
            "type": "integer"
          },
          "failing_since": {
            "description": "С какого момента адрес не принимает события подряд",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "example": "7",
            "type": "string"
          },
          "next_attempt_at": {
            "description": "Когда следующая попытка после неудачи",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "secret": {
            "description": "Секрет подписи `whsec_…`. Только в ответе на создание и смену\nсекрета — сохраните его сразу: больше его не покажут",
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "example": "https://crm.example.kz/hooks/camp",
            "type": "string"
          }
        },
        "required": [
          "id",
          "url",
          "event_types",
          "enabled",
          "failed_attempts",
          "delivered_through",
          "created_at"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "api_key": {
        "bearerFormat": "zb_live_…",
        "description": "Ключ подключения в заголовке `Authorization: Bearer zb_live_…`. В адресе ключ не передаётся: такой ключ отзывается автоматически.",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Все адреса внешнего API Bokling CRM: что отправить, что придёт в ответ и какие бывают ошибки. Слева — разделы и адреса, у каждого адреса — пример запроса на cURL, JavaScript, Python и PHP.\n\n| | |\n|---|---|\n| **Адрес** | `https://partners.zvezdnyy-burabai.edu.kz/ext/v1` — только HTTPS |\n| **Ключ** | заголовок `Authorization: Bearer zb_live_…` — выдаёт лагерь |\n| **Формат** | JSON в UTF-8; суммы — объект `{\"amount\": \"119000.00\", \"currency\": \"KZT\"}`, даты — `ГГГГ-ММ-ДД` |\n| **Повтор запроса** | заголовок `Idempotency-Key` на `POST` — второй раз бронь не создастся |\n| **Видно** | только брони, семьи и счета вашего отдела |\n\nВпервые здесь — начните с [первого запроса за 5 минут](/partners/quickstart). Пошагово бронь и оплата — в [руководстве](/partners/booking-and-payment), все коды ошибок — в разделе [Ошибки](/partners/errors).",
    "title": "Справочник API",
    "version": "1"
  },
  "openapi": "3.1.0",
  "paths": {
    "/bank-statement-lines/claims": {
      "get": {
        "description": "Для пачки выписки бухгалтерии: какие строки ведёт система лагеря (их\nне проводить — оплату путёвки проводит мост после сверки), какие она\nготова отдать. Только чтение: отдаёт строки `handover`. Только для\nключей главного отдела.",
        "operationId": "bank_statement_lines_claims",
        "parameters": [
          {
            "description": "Ключи строк через запятую, не больше 100",
            "in": "query",
            "name": "keys",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatementClaims"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Ключ не главного отдела (`main_department_only`) или без права read"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Чьи строки выписки",
        "tags": [
          "Выписка банка"
        ]
      }
    },
    "/bank-statement-lines/handover": {
      "post": {
        "description": "Под замком строк система ещё раз решает, чья строка, и отдаёт заданию\n`job` только поступления, которые ведёт бухгалтерия (`owner =\naccounting`) и которые ещё никому не отданы, — плюс отданные этому же\nзаданию раньше. Проводите только ключи из ответа. Отданную строку\nсистема лагеря больше не вернёт в сверку: отмена — через бухгалтера\nв 1С. Право `accounting`, только ключам главного отдела.",
        "operationId": "bank_statement_lines_handover",
        "parameters": [
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HandoverRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Handover"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Ключ не главного отдела (`main_department_only`) или без права accounting"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Передать строки выписки заданию пачки",
        "tags": [
          "Выписка банка"
        ]
      }
    },
    "/bookings": {
      "get": {
        "description": "Брони вашего отдела по возрастанию номера, порциями. Корпоративных\nброней в API нет.",
        "operationId": "bookings_list",
        "parameters": [
          {
            "description": "Только брони смены",
            "in": "query",
            "name": "shift_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "active | cancelled",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "awaiting | secured | unpaid",
            "in": "query",
            "name": "payment_state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "true — только с остатком к оплате, false — только без него",
            "in": "query",
            "name": "has_debt",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "description": "Изменённые с этого момента (RFC 3339): `2027-05-14T00:00:00Z`.\nПлатёж версию брони не меняет — о нём скажет событие `payment.received`",
            "in": "query",
            "name": "updated_since",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Брони ребёнка",
            "in": "query",
            "name": "child_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Брони детей семьи",
            "in": "query",
            "name": "parent_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный фильтр или курсор"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Брони",
        "tags": [
          "Брони"
        ]
      },
      "post": {
        "description": "Та же проверка, что и в CRM лагеря: окно продаж, квота отдела, дубль\nребёнка на смене, запрет, потолок скидки. Место придерживается на\nсутки, и при `invoice` = `min` (по умолчанию) или `full` счёт Kaspi\nуходит плательщику сразу. Нужен `Idempotency-Key`.",
        "operationId": "bookings_create",
        "parameters": [
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Бронь оформлена",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверные данные"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права bookings или оформить ребёнка нельзя (blacklisted)"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Смена не найдена"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Квота исчерпана, продажи закрыты, дубль ребёнка, external_id занят"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Idempotency-Key уже использован для другого запроса"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Лимит",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Оформить бронь",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/batch": {
      "post": {
        "description": "Все брони — одной транзакцией: если не прошёл хотя бы один ребёнок\n(квота, дубль, запрет), не оформляется никто, а в ответе сказано,\nкакой ребёнок и почему. Счёт Kaspi — отдельный на каждую бронь.\nНужен `Idempotency-Key`.",
        "operationId": "bookings_create_batch",
        "parameters": [
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            },
            "description": "Все брони оформлены",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Оформить детей одной семьи",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/by-external-id/{external_id}": {
      "get": {
        "operationId": "bookings_get_by_external_id",
        "parameters": [
          {
            "description": "Ваш external_id брони",
            "in": "path",
            "name": "external_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Бронь по номеру вашей CRM",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/check": {
      "post": {
        "description": "Те же проверки, что при оформлении, но без брони: продажи открыты,\nесть место в квоте отдела, ребёнок ещё не записан на смену, нет\nзапрета. Ничего не создаёт; `Idempotency-Key` не нужен.\n\nНужно право `bookings`: ответ говорит, записан ли ребёнок с такими\nФИО и телефоном, — это часть оформления, а не чтение своей базы.\nСчитается как запись (2 в секунду) и не больше 300 проверок в час\nна отдел.",
        "operationId": "bookings_check",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права bookings"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Смена не найдена"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Лимит",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Можно ли оформить",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}": {
      "get": {
        "operationId": "bookings_get",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Бронь",
        "tags": [
          "Брони"
        ]
      },
      "patch": {
        "description": "Передайте только то, что меняется. С `If-Match: <version>` правка\nне ляжет поверх чужой: если бронь успели изменить, ответ `412`.\nИзменение цены, скидки или трансфера пересоставляет живой счёт Kaspi.",
        "operationId": "bookings_patch",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "version брони",
            "in": "header",
            "name": "If-Match",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Бронь отменена, external_id занят"
          },
          "412": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "version не совпала"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Изменить бронь",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/cancel": {
      "post": {
        "description": "Место возвращается в квоту, живой счёт Kaspi гасится. Деньги отмена\nне возвращает: оплату по счёту Kaspi вернёт заявка на возврат\n(`POST /bookings/{id}/refund-requests`), прочее — бухгалтерия лагеря.\nБронь заехавшего ребёнка не отменяется. Принимает `If-Match`.\nНужен `Idempotency-Key`.",
        "operationId": "bookings_cancel",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "version брони",
            "in": "header",
            "name": "If-Match",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Уже отменена, ребёнок уже заехал"
          },
          "412": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Запись изменили после вашего чтения: version не совпала"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Отменить бронь",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/history": {
      "get": {
        "description": "Создание, правки, отмена, восстановление — по порядку записи,\nпорциями. Кто: ваше подключение или «Лагерь».",
        "operationId": "bookings_history",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryPage"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный курсор или limit"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "История брони",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/invoices": {
      "get": {
        "operationId": "invoices_list_for_booking",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Invoice"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Счета брони",
        "tags": [
          "Счета"
        ]
      },
      "post": {
        "description": "Счёт уходит с Kaspi лагеря на телефон плательщика из брони. Ответ\nприходит сразу, счёт в Kaspi выставляется очередью за секунды —\nследите за событиями `invoice.issued`, `invoice.paid`.\n\nПо брони живёт один незакрытый счёт: второй — отказ `invoice_live`,\nлибо `replace: true`, и старый счёт заменяется новым (ответ 202).\nСумма не больше остатка (`amount_over_debt`), целыми тенге\n(`fractional_amount`). Не больше 5 счетов в час по одной брони.",
        "operationId": "invoices_create",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewInvoice"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            },
            "description": "Счёт поставлен в очередь",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceReplacing"
                }
              }
            },
            "description": "Старый счёт заменяется новым",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Выставить счёт Kaspi",
        "tags": [
          "Счета"
        ]
      }
    },
    "/bookings/{id}/move": {
      "post": {
        "description": "Как кнопка лагеря «Остаётся на следующую смену»: оформляется НОВАЯ\nбронь того же ребёнка на указанную смену — по цене этой смены, без\nпрежней скидки, с удержанием места и счётом на минимальный платёж.\nПрежняя бронь остаётся как есть, её платежи не переезжают. Если\nпрежнее место больше не нужно — отмените прежнюю бронь отдельно.\nОтвет — новая бронь (событие `booking.created`). Нужен `Idempotency-Key`.",
        "operationId": "bookings_move",
        "parameters": [
          {
            "description": "Номер прежней брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Новая бронь",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Квота, продажи закрыты, дубль на новой смене"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Перенести на другую смену",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/payments": {
      "get": {
        "description": "Все платежи брони, включая возвраты. «Оплачено» по брони — их сумма.",
        "operationId": "payments_list_for_booking",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Payment"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Платежи брони",
        "tags": [
          "Платежи"
        ]
      }
    },
    "/bookings/{id}/refund-requests": {
      "get": {
        "operationId": "refund_requests_list_for_booking",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_RefundRequest"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Заявки на возврат по брони",
        "tags": [
          "Возвраты"
        ]
      },
      "post": {
        "description": "Просит лагерь вернуть плательщику деньги, пришедшие по счёту Kaspi\nэтой брони. Деньги не двигаются, пока заявку не одобрит сотрудник\nлагеря; одобрить через API нельзя. Дальше — события\n`refund_request.approved` / `rejected`, затем `done` (деньги ушли\nплательщику, рядом приходит `payment.refunded`) или `failed`.\nВозврат уходит через тот же Kaspi лагеря, который принял оплату.",
        "operationId": "refund_requests_create",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewRefundRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundRequest"
                }
              }
            },
            "description": "Заявка подана",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Подать заявку на возврат",
        "tags": [
          "Возвраты"
        ]
      }
    },
    "/bookings/{id}/restore": {
      "post": {
        "description": "Снова занимает место в квоте — если оно ещё есть — и снова держит его\nсутки до минимального платежа, со счётом Kaspi. Нужен `Idempotency-Key`.",
        "operationId": "bookings_restore",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Не отменена, квота заполнена, продажи закрыты, дубль"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Восстановить отменённую бронь",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/together": {
      "post": {
        "description": "Просьба поселить детей в один отряд — той же связью, что ставит\nпродажник лагеря. Все брони — ваши, действующие и на одной смене.\nНужен `Idempotency-Key`.",
        "operationId": "bookings_together",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Случайная строка, своя на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TogetherRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Together"
                }
              }
            },
            "description": "Создано",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Чужая, отменённая или с другой смены бронь"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Поселить вместе",
        "tags": [
          "Брони"
        ]
      }
    },
    "/bookings/{id}/voucher": {
      "get": {
        "operationId": "vouchers_get",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Путёвка брони",
        "tags": [
          "Путёвки"
        ]
      },
      "post": {
        "description": "Выпуск и перевыпуск путёвки (новый QR-код заезда, прежний перестаёт\nдействовать). Сейчас доступно руководителю отдела и лагерю, ключу\nс правами менеджера — нет (`voucher_head_only`).",
        "operationId": "vouchers_generate",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Выпустить путёвку",
        "tags": [
          "Путёвки"
        ]
      }
    },
    "/bookings/{id}/voucher.pdf": {
      "get": {
        "description": "Файл выпущенной путёвки — отправить семье. Тяжёлый запрос: проще\nвзять готовую ссылку `pdf_url` из `GET /bookings/{id}/voucher`.",
        "operationId": "vouchers_get_pdf",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/pdf": {
                "schema": {
                  "$ref": "#/components/schemas/Pdf"
                }
              }
            },
            "description": "PDF путёвки",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Путёвка не выпущена или бронь отменена"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "PDF путёвки",
        "tags": [
          "Путёвки"
        ]
      }
    },
    "/bookings/{id}/voucher/sent": {
      "post": {
        "description": "Путёвка передана семье. Сейчас доступно руководителю отдела и лагерю,\nключу с правами менеджера — нет (`voucher_head_only`).",
        "operationId": "vouchers_mark_sent",
        "parameters": [
          {
            "description": "Номер брони",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voucher"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Отметить путёвку отправленной",
        "tags": [
          "Путёвки"
        ]
      }
    },
    "/children": {
      "get": {
        "description": "Все ваши дети, включая прошлые сезоны. Ребёнок, ушедший в другой\nотдел, здесь больше не появляется.",
        "operationId": "children_list",
        "parameters": [
          {
            "description": "Были в сезоне: есть неотменённая обычная (не корпоративная) бронь\nна смену этого сезона",
            "in": "query",
            "name": "season_id_visited",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Не были в сезоне: ваши дети без неотменённой обычной брони\nв этом сезоне — «кого не было в этом году»",
            "in": "query",
            "name": "season_id_not_visited",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Год рождения от (включительно)",
            "in": "query",
            "name": "birth_year_from",
            "required": false,
            "schema": {
              "format": "int32",
              "type": "integer"
            }
          },
          {
            "description": "Год рождения до (включительно)",
            "in": "query",
            "name": "birth_year_to",
            "required": false,
            "schema": {
              "format": "int32",
              "type": "integer"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Child"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Дети вашей базы",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/children/{id}": {
      "get": {
        "operationId": "children_get",
        "parameters": [
          {
            "description": "Номер ребёнка",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Child"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Ребёнок",
        "tags": [
          "Семьи"
        ]
      },
      "patch": {
        "description": "Только ваш номер и метки: ФИО и дата рождения ребёнка — данные\nпутёвки и правятся в брони.",
        "operationId": "children_patch",
        "parameters": [
          {
            "description": "Номер ребёнка",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChildPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Child"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "external_id — у другой записи"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Правка ребёнка",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/events": {
      "get": {
        "description": "Опрос и догоняние после сбоя. Храните номер последнего\nобработанного события и передавайте его в `after`.",
        "operationId": "events_list",
        "parameters": [
          {
            "description": "Номер последнего обработанного события; 0 — с начала (90 дней)",
            "in": "query",
            "name": "after",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько событий вернуть, 1–500, по умолчанию 100. Больше 100 —\n«тяжёлый» запрос (1 в секунду)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "format": "int64",
              "maximum": 500,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPage"
                }
              }
            },
            "description": "Порция событий",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный номер"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Лента событий своего отдела",
        "tags": [
          "События"
        ]
      }
    },
    "/families": {
      "get": {
        "description": "Поиск по телефону и ФИО. Без фильтров — вся ваша база по возрастанию\nномера, порциями.",
        "operationId": "families_list",
        "parameters": [
          {
            "description": "Телефон в любом написании (8 701…, +7 701…): ищется по основному\nи вторым номерам семьи",
            "in": "query",
            "name": "phone",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Часть ФИО родителя или вашего ребёнка, от 2 символов",
            "in": "query",
            "name": "name",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только семьи, у которых родитель или ваш ребёнок изменились\nначиная с этого момента (RFC 3339)",
            "in": "query",
            "name": "updated_since",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Family"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный телефон или слишком короткое ФИО"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Семьи вашей базы",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/families/by-external-id/{external_id}": {
      "get": {
        "operationId": "families_get_by_external_id",
        "parameters": [
          {
            "description": "Ваш номер семьи",
            "in": "path",
            "name": "external_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Family"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Семья по номеру в вашей CRM",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/families/{id}": {
      "get": {
        "description": "Родитель, ваши дети и ваши брони. По номеру слитой карточки\nотвечает живой семьёй (её номер — в `id`, старый — в `merged_from`).",
        "operationId": "families_get",
        "parameters": [
          {
            "description": "Номер семьи",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Family"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Семья",
        "tags": [
          "Семьи"
        ]
      },
      "patch": {
        "description": "Контакты — те же поля и правила, что у менеджера в CRM; основной\nтелефон не меняется. С `If-Match: <version>` правка пройдёт, только\nесли запись не меняли после вашего чтения, иначе — `412`.",
        "operationId": "families_patch",
        "parameters": [
          {
            "description": "Номер семьи",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Версия записи (`version`)",
            "in": "header",
            "name": "If-Match",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilyPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Family"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Семью ведёт и другой отдел (family_shared)"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Номер занят другой семьёй или external_id — другой записью"
          },
          "412": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Запись изменили (version_mismatch)"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Правка семьи",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/families/{id}/payments": {
      "get": {
        "description": "Платежи по вашим броням детей этой семьи. Только чтение: платежи\nпринимает лагерь (счёт Kaspi), ввода платежей в API нет.",
        "operationId": "families_payments_list",
        "parameters": [
          {
            "description": "Номер семьи",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_FamilyPayment"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Платежи семьи",
        "tags": [
          "Семьи"
        ]
      }
    },
    "/invoices": {
      "get": {
        "description": "Все счета по броням вашего отдела, по возрастанию номера.",
        "operationId": "invoices_list",
        "parameters": [
          {
            "description": "Только в этом состоянии: queued, issued, paid, expired, cancelled,\nerror, mismatch",
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только изменённые не раньше этого времени (RFC 3339). Для\nдогоняния берите время с запасом в минуту: время изменения — это\nначало записывающей транзакции",
            "in": "query",
            "name": "updated_since",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Invoice"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Счета отдела",
        "tags": [
          "Счета"
        ]
      }
    },
    "/invoices/{id}": {
      "get": {
        "operationId": "invoices_get",
        "parameters": [
          {
            "description": "Номер счёта",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Счёт",
        "tags": [
          "Счета"
        ]
      }
    },
    "/invoices/{id}/cancel": {
      "post": {
        "description": "Гасит требование заплатить, по которому ещё не заплатили. Счёт,\nещё не ушедший в Kaspi, отменяется сразу; выставленный — гасится\nв Kaspi очередью (`cancelling: true`, потом событие\n`invoice.cancelled`). Пока счёт гасится, его можно оплатить —\nоплата будет принята как обычно. Оплаченный счёт не отменяется\n(`invoice_paid`): вернуть деньги — заявкой на возврат\n(`POST /bookings/{id}/refund-requests`). Расхождение суммы разбирает\nтолько лагерь.",
        "operationId": "invoices_cancel",
        "parameters": [
          {
            "description": "Номер счёта",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Ключ повтора",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            },
            "description": "Счёт после отмены",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Нет права на действие"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Конфликт с текущим состоянием записи"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Отменить счёт",
        "tags": [
          "Счета"
        ]
      }
    },
    "/kaspi/operations": {
      "get": {
        "description": "Операции кассы Kaspi лагеря по времени операции: поступления,\nвозвраты, комиссия. Только для ключей главного отдела. Выписка\nзагружается каждые полчаса и после полуночи — за вчерашний день\nцеликом; об обновлении говорит событие `kaspi.operations.synced`.\nОперация не удаляется никогда, но может уточниться (комиссия,\nссылка на счёт): за закрытый день перечитывайте выписку после\n`synced_through`, а не полагайтесь на курсор прошлого чтения.",
        "operationId": "kaspi_operations_list",
        "parameters": [
          {
            "description": "С этого дня включительно, по `date` (ГГГГ-ММ-ДД)",
            "in": "query",
            "name": "date_from",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "По этот день включительно, по `date` (ГГГГ-ММ-ДД)",
            "in": "query",
            "name": "date_to",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KaspiOperationPage"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Ключ не главного отдела (`main_department_only`) или без права read"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Выписка Kaspi Pay лагеря",
        "tags": [
          "Выписка Kaspi"
        ]
      }
    },
    "/me": {
      "get": {
        "description": "Отдел, подключение и права ключа. Удобно для проверки ключа.",
        "operationId": "me_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Кто я",
        "tags": [
          "Подключение"
        ]
      }
    },
    "/payments": {
      "get": {
        "description": "Все платежи по броням вашего отдела, по возрастанию номера.",
        "operationId": "payments_list",
        "parameters": [
          {
            "description": "Только оплаченные в этот день и позже, по `paid_on` (ГГГГ-ММ-ДД)",
            "in": "query",
            "name": "paid_from",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Только изменённые не раньше этого времени (RFC 3339), например\nсверенные бухгалтерией. Берите время с запасом в минуту",
            "in": "query",
            "name": "updated_since",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Payment"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Платежи отдела",
        "tags": [
          "Платежи"
        ]
      }
    },
    "/payments/{id}": {
      "get": {
        "operationId": "payments_get",
        "parameters": [
          {
            "description": "Номер платежа",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Платёж",
        "tags": [
          "Платежи"
        ]
      }
    },
    "/quote": {
      "post": {
        "description": "Что будет стоить бронь — тем же расчётом, что при оформлении, и с теми\nже отказами (скидка больше наибольшей для смены). Ничего не создаёт;\n`Idempotency-Key` не нужен.",
        "operationId": "bookings_quote",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверная скидка"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Смена не найдена"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Расчёт стоимости",
        "tags": [
          "Брони"
        ]
      }
    },
    "/reconcile/bookings": {
      "get": {
        "description": "Все брони вашего отдела (и отменённые) — номер, статус и версия,\nбольшими порциями. Раз в сутки сравните со своей базой: чего у вас\nнет или где версия другая — перечитайте. Так находится всё, что\nразошлось, даже если события потерялись. Тяжёлый запрос.",
        "operationId": "reports_reconcile_bookings",
        "parameters": [
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–5000, по умолчанию 1000",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 1000,
              "format": "int64",
              "maximum": 5000,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_BookingVersion"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Сверка броней",
        "tags": [
          "Отчёты"
        ]
      }
    },
    "/refund-requests/{id}": {
      "get": {
        "operationId": "refund_requests_get",
        "parameters": [
          {
            "description": "Номер заявки",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundRequest"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Заявка на возврат",
        "tags": [
          "Возвраты"
        ]
      }
    },
    "/reports/debts": {
      "get": {
        "description": "Активные брони отдела, по которым оплачено меньше суммы к оплате.\nТяжёлый запрос.",
        "operationId": "reports_debts",
        "parameters": [
          {
            "description": "Только смена",
            "in": "query",
            "name": "shift_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только просроченные",
            "in": "query",
            "name": "overdue",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Debt"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Долги",
        "tags": [
          "Отчёты"
        ]
      }
    },
    "/reports/shifts": {
      "get": {
        "description": "По каждой смене (кроме черновиков): квота отдела, занято, свободно,\nпродано, оплачено, долг. Тяжёлый запрос.",
        "operationId": "reports_shifts",
        "parameters": [
          {
            "description": "Сезон. Пусто — действующие сезоны",
            "in": "query",
            "name": "season_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShiftSalesReport"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Продажи и квоты по сменам",
        "tags": [
          "Отчёты"
        ]
      }
    },
    "/reports/unpaid": {
      "get": {
        "description": "Брони, отменённые автоматически: минимальный платёж не пришёл за\nсутки. Готовый список на обзвон — узнать, почему не оплатили.\nТяжёлый запрос.",
        "operationId": "reports_unpaid",
        "parameters": [
          {
            "description": "Только брони, чьё удержание места (`hold_until`) истекло не раньше\nэтого времени (RFC 3339)",
            "in": "query",
            "name": "hold_until_from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Unpaid"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Слишком много запросов",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Снятые по неоплате",
        "tags": [
          "Отчёты"
        ]
      }
    },
    "/shifts": {
      "get": {
        "description": "Все смены, кроме черновиков, со свободными местами в квоте вашего отдела.",
        "operationId": "shifts_list",
        "parameters": [
          {
            "description": "Только смены, на которые можно оформить бронь сейчас",
            "in": "query",
            "name": "on_sale",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "description": "Только смены сезона",
            "in": "query",
            "name": "season_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Shift"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Смены",
        "tags": [
          "Смены"
        ]
      }
    },
    "/shifts/{id}": {
      "get": {
        "operationId": "shifts_get",
        "parameters": [
          {
            "description": "Номер смены",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Shift"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Смена",
        "tags": [
          "Смены"
        ]
      }
    },
    "/stream": {
      "get": {
        "description": "События сразу, как случились, с догонянием пропущенного.\nАдрес `wss://…/ext/v1/stream`, ключ — в заголовке `Authorization`\nзапроса на соединение (как у остальных ручек). Право `read`.\nОдновременно — не больше 3 сокетов на подключение; четвёртый\nполучает `429` ещё до соединения.\n\nОбмен — текстовые кадры JSON:\n\n1. Сервер сразу шлёт `{\"type\":\"hello\",\"last_event_id\":\"1042\"}` —\n   номер последнего события вашего отдела.\n2. Клиент шлёт `{\"type\":\"subscribe\",\"after\":\"1000\",\"types\":[\"booking.created\"]}`.\n   `after` обязателен: номер последнего обработанного события\n   (`\"0\"` — с начала, 90 дней). `types` — по желанию, только эти типы.\n3. Сервер досылает всё после `after` порциями до 500, затем шлёт\n   новые события по мере появления:\n   `{\"type\":\"event\",\"event\":{…событие, как в GET /events…}}`.\n   Повторный `subscribe` начинает отдачу заново с нового `after`.\n   Каждая порция догоняния считается «тяжёлым» запросом (1 в секунду,\n   общий ковш с отчётами): кончились жетоны — отдача ждёт, а не рвётся.\n4. Неразборчивое сообщение — ответ\n   `{\"type\":\"error\",\"code\":\"bad_message\",\"message\":\"…\"}`, соединение\n   остаётся.\n\nСоединение:\n- сервер шлёт ping каждые 30 с; нет ответа 90 с — закрывает;\n- раз в минуту сервер перепроверяет ключ: отозван, истёк, подключение\n  отключено — `{\"type\":\"error\",\"code\":\"unauthorized\"}` и закрытие\n  с кодом 1008;\n- клиент, который не забирает данные 30 с, отключается — сервер\n  не копит для него события в памяти;\n- доставка «хотя бы один раз»: после переподключения события после\n  вашего `after` придут снова — узнавайте повтор по номеру.\n\nСхемы сообщений: `StreamHello`, `StreamSubscribe`, `StreamEvent`,\n`StreamError`.",
        "operationId": "stream_connect",
        "responses": {
          "101": {
            "description": "Соединение открыто, дальше — обмен сообщениями"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Запрос не на веб-сокет"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Уже открыто 3 сокета этого подключения",
            "headers": {
              "Retry-After": {
                "description": "Через сколько секунд повторить запрос",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Веб-сокет ленты событий",
        "tags": [
          "События"
        ]
      }
    },
    "/webhooks": {
      "get": {
        "description": "Все вебхуки подключения, включая отключённые.",
        "operationId": "webhooks_list",
        "parameters": [
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Webhook"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Список вебхуков",
        "tags": [
          "Вебхуки"
        ]
      },
      "post": {
        "description": "Мы будем отправлять события вашего отдела на этот адрес: `POST`,\nтело — событие в том же виде, что в `GET /events`, по одному\nза запрос, строго по порядку номеров. Следующее событие уходит,\nтолько когда вы ответили `2xx` на предыдущее.\n\nОтвет несёт `secret` — ключ подписи `whsec_…`. Он показывается\n**один раз**: сохраните его. Потеряли — смените (`rotate-secret`).\n\nАдрес: только `https://` с действующим сертификатом, публичный\n(внутренние и служебные адреса отклоняются), без логина и пароля\nв адресе. Переадресации не выполняются. Живых вебхуков — до 5.\n\nПроверка подписи — в разделе «Вебхуки» описания API.",
        "operationId": "webhooks_create",
        "parameters": [
          {
            "description": "Своя случайная строка на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhook"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Создан; `secret` — только в этом ответе",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный адрес или тип события"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Уже 5 живых вебхуков"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Вебхуки временно недоступны"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Создать вебхук",
        "tags": [
          "Вебхуки"
        ]
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "description": "Вебхук не удаляется: он остаётся в списке отключённым вместе\nс журналом доставок, и его можно включить снова (`PATCH`, `enabled`).",
        "operationId": "webhooks_disable",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Отключить вебхук",
        "tags": [
          "Вебхуки"
        ]
      },
      "get": {
        "operationId": "webhooks_get",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Вебхук",
        "tags": [
          "Вебхуки"
        ]
      },
      "patch": {
        "description": "Адрес, типы событий, включение. Включение снова сбрасывает счёт\nнеудач, и доставка продолжается с места, где остановилась.",
        "operationId": "webhooks_patch",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchWebhook"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Включение превысит 5 живых вебхуков"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Изменить вебхук",
        "tags": [
          "Вебхуки"
        ]
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "description": "Попытки отправки на этот вебхук, от новых к старым, за 30 дней.",
        "operationId": "webhooks_deliveries_list",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Курсор из `next_cursor` прошлого ответа",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Сколько записей вернуть, 1–200, по умолчанию 50",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "format": "int64",
              "maximum": 200,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page_Delivery"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Журнал доставок",
        "tags": [
          "Вебхуки"
        ]
      }
    },
    "/webhooks/{id}/redeliver": {
      "post": {
        "description": "Переставляет место доставки: всё ПОСЛЕ `after` будет отправлено\nзаново, по порядку, в ближайшие секунды. Счёт неудач не трогается,\nно пауза до следующей попытки снимается. События хранятся 90 дней.",
        "operationId": "webhooks_redeliver",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Своя случайная строка на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Redeliver"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Готово",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Тело не принято: незнакомое или неверное поле, либо Idempotency-Key с другим телом"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Отправить ещё раз",
        "tags": [
          "Вебхуки"
        ]
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "description": "Новый секрет — в ответе, один раз. Старый перестаёт действовать\n**сразу**: события, отправленные после ответа, подписаны новым.\nПоэтому на время смены принимайте подпись любым из двух секретов,\nа старый удалите, когда пришло первое событие с новой подписью.",
        "operationId": "webhooks_rotate_secret",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Своя случайная строка на каждое действие",
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            },
            "description": "Новый `secret` — только в этом ответе",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Сервис временно недоступен"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Сменить секрет подписи",
        "tags": [
          "Вебхуки"
        ]
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "description": "Сразу отправляет на адрес вебхука событие `ping` (номер `0`,\nсущность `webhook`) с настоящей подписью и возвращает, что ответил\nваш сервер. Попытка попадает в журнал доставок. Работает и для\nотключённого вебхука — удобно проверить адрес перед включением.\nНичего не меняет, поэтому `Idempotency-Key` не нужен (если передан —\nне учитывается: каждый вызов отправляет новый ping).",
        "operationId": "webhooks_test",
        "parameters": [
          {
            "description": "Номер вебхука",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestResult"
                }
              }
            },
            "description": "Результат отправки (в том числе неудачной)",
            "headers": {
              "RateLimit-Limit": {
                "description": "Размер окна лимита для этого вида запросов",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Сколько запросов осталось в текущем окне",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Через сколько секунд окно восстановится",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "X-Request-Id": {
                "description": "Номер запроса: назовите его в обращении в поддержку",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Неверный запрос: параметр, курсор, поле тела или ключ в адресе (`key_in_url`)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Записи нет или она не вашего отдела"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "description": "Сервис временно недоступен"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ],
        "summary": "Проверить адрес",
        "tags": [
          "Вебхуки"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://partners.zvezdnyy-burabai.edu.kz/ext/v1"
    }
  ],
  "tags": [
    {
      "description": "Ключ, отдел, права",
      "name": "Подключение"
    },
    {
      "description": "Смены, цены и свободные места вашего отдела",
      "name": "Смены"
    },
    {
      "description": "Брони вашего отдела: оформление, правка, отмена, перенос, расчёт стоимости",
      "name": "Брони"
    },
    {
      "description": "Своя база отдела: семьи, дети, их брони и оплаты",
      "name": "Семьи"
    },
    {
      "description": "Лента изменений: опрос, веб-сокет, вебхуки",
      "name": "События"
    },
    {
      "description": "Счета Kaspi с Kaspi лагеря на телефон плательщика",
      "name": "Счета"
    },
    {
      "description": "Платежи по броням отдела, только чтение",
      "name": "Платежи"
    },
    {
      "description": "Заявки на возврат оплаты по счёту Kaspi: подать и следить; одобряет лагерь",
      "name": "Возвраты"
    },
    {
      "description": "Операции кассы Kaspi Pay лагеря — только главному отделу",
      "name": "Выписка Kaspi"
    },
    {
      "description": "Строки выписки банка, загруженной в систему лагеря: чьи они — только главному отделу",
      "name": "Выписка банка"
    },
    {
      "description": "Статус, выпуск, PDF и отметка «отправлена»",
      "name": "Путёвки"
    },
    {
      "description": "Продажи и квоты, долги, снятые по неоплате, сверка",
      "name": "Отчёты"
    },
    {
      "description": "Адреса, на которые мы сами отправляем события",
      "name": "Вебхуки"
    }
  ],
  "webhooks": {
    "event": {
      "post": {
        "description": "Мы отправляем `POST` на адрес вебхука: тело — событие в том же виде, что в `GET /events`, по одному за запрос и строго по порядку номеров. Ответьте `2xx` в пределах 10 секунд — иначе повтор через 30 с, 2 мин, 10 мин, 30 мин, 1 ч и дальше каждые 2 ч; трое суток неудач — вебхук отключается. Переадресации не выполняются.\n\nПроверьте подпись `Zb-Signature` до разбора тела: HMAC-SHA256 с ключом — секретом вебхука целиком (`whsec_…`) — от строки `<t>.<сырое тело>`; отбрасывайте `t` старше 5 минут. Повтор узнаётся по `Zb-Event-Id`.",
        "operationId": "webhooks_event_receive",
        "parameters": [
          {
            "description": "Подпись: время отправки (секунды Unix) и HMAC-SHA256",
            "in": "header",
            "name": "Zb-Signature",
            "required": true,
            "schema": {
              "examples": [
                "t=1760000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
              ],
              "type": "string"
            }
          },
          {
            "description": "Номер события",
            "in": "header",
            "name": "Zb-Event-Id",
            "required": true,
            "schema": {
              "examples": [
                "1042"
              ],
              "type": "string"
            }
          },
          {
            "description": "Тип события",
            "in": "header",
            "name": "Zb-Event-Type",
            "required": true,
            "schema": {
              "examples": [
                "booking.created"
              ],
              "type": "string"
            }
          },
          {
            "description": "Всегда этот",
            "in": "header",
            "name": "User-Agent",
            "required": true,
            "schema": {
              "examples": [
                "ZvezdnyyBurabai-Webhooks/1"
              ],
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Принято — дальше следующее событие"
          },
          "default": {
            "description": "Не принято — повтор по расписанию"
          }
        },
        "security": [
          {}
        ],
        "summary": "Событие на ваш адрес",
        "tags": [
          "Вебхуки"
        ]
      }
    }
  }
}
