# Формат

Скучная страница, которую читают один раз и потом сверяются. Здесь всё, что
одинаково у всех операций.

## Базовый адрес

```
https://{домен-школы}/api/v1
```

Общего адреса нет и не будет: это коробка, у каждой школы свой домен. Адрес своей
установки видно на экране создания ключа — там же рядом готовый пример запроса
с подставленным ключом.

Одно исключение: **публичная проверка сертификата** живёт в корне школы,
а не под `/api/v1`, и не требует авторизации.

## Транспорт и тело

**Только HTTPS.** HTTP отвечает `400` без перенаправления.

**Тело — `application/json; charset=utf-8`.** Никакого base64 внутри
form-urlencoded, как в классическом API GetCourse.

## Именование

Ресурсы во множественном числе, поля в `snake_case`, идентификаторы в пути.

**Вложенность не глубже двух уровней.** `/v1/courses/{id}/modules` — да,
`/v1/courses/{id}/modules/{id}/lessons/{id}/assignments` — нет: вместо этого
`/v1/assignments?lesson_id=…`. Глубокая вложенность выглядит логично и перестаёт
работать, как только объект понадобится получить не через родителя.

## Идентификаторы

Префиксные, типизированные, устойчивые к перебору:

```
usr_01HQZX3M8K4N2P      пользователь
crs_01HQZX41B7RC9S      курс
lsn_01HQZX4G2XVD5T      урок
enr_01HQZX52NAQF7V      обучение на курсе
sub_01HQZX5PDMWG3W      ответ на задание
ord_01HQZX68HKYJ1X      заказ
pay_01HQZX6TSCZL8Y      платёж
prd_01HQZX7B4FMN2Z      продукт
off_01HQZX7QGVPR6A      тариф
seg_01HQZX8D9JTS4B      сегмент
scn_01HQZX8XKQWU7C      сценарий
web_01HQZX9F5NZV1D      вебинар
```

Префикс сразу говорит, что за объект, и делает ошибку «передал идентификатор заказа
туда, где ждали платёж» видимой мгновенно — а не через три часа отладки, когда
`404` наконец покажется странным.

Числовых идентификаторов нет намеренно: по ним перебирается вся база.

## Даты

ISO 8601 **с таймзоной, всегда**:

```
2026-08-03T14:30:00+03:00
```

Никаких `"2026-08-03 14:30:00"` — строка без пояса требует догадки о том, чей это
пояс, и догадка однажды окажется неверной. Сервер работает в UTC, а показывается
всё в поясе школы.

## Деньги

Целое число в минорных единицах **и код валюты — всегда парой**:

```json
{ "amount": 1490000, "currency": "RUB" }
```

Это 14 900 рублей.

Целое — потому что дробные числа не складываются точно, и на сотой операции копейка
разъезжается. Парой с валютой — потому что у валют разный порядок: у иены нулевой,
у динара три знака, и число без кода валюты бессмысленно.

## Булевы — булевы

`true`, а не `"true"` и не `1`. Числа — числа. Пустое значение — `null`,
а не пустая строка.

## Конверт ответа

**Объект отдаётся напрямую, без обёртки:**

```json
{
  "id": "usr_01HQZX3M8K4N2P",
  "email": "student@example.com",
  "first_name": "Мария",
  "created_at": "2026-08-01T10:15:00+03:00"
}
```

**Список — с курсором:**

```json
{
  "data": [ { "id": "usr_01HQZX3M8K4N2P", "email": "student@example.com" } ],
  "has_more": true,
  "next_cursor": "eyJpZCI6InVzcl8wMUhRWlgzTThLNE4yUCJ9"
}
```

Обходить список до тех пор, пока `has_more` равно `true`, подставляя `next_cursor`
в следующий запрос. Разбирать сам курсор не нужно и не следует: это закодированная
позиция, и её устройство может измениться.

Подробнее про обход, фильтры и сортировку — [Пагинация](/api/pagination/).

## Служебные заголовки в каждом ответе

| Заголовок | Что это |
|---|---|
| `X-Request-Id` | Идентификатор запроса. Логируйте его у себя — см. [Ошибки](/api/errors/) |
| `X-RateLimit-Limit` | Лимит для этого класса операций |
| `X-RateLimit-Remaining` | Сколько осталось |
| `X-RateLimit-Reset` | Когда счётчик обнулится |

## Состав полей

**Чего на этой странице нет: состава полей у объектов.** Формат конверта, дат,
денег и идентификаторов решён и не изменится, а какие именно поля у заказа — это
то, что выводится из валидаторов, а их пока нет. См.
[Чего в справочнике ещё нет](/api/reference/#chego-v-spravochnike-eshhe-net).
