Маленький публичный API пекарских расчётов
Read-only, без авторизации, на тех же формулах, что и инструменты.
Сначала я сделал это для себя. У меня есть простой бот в Телеграме, который напоминает, когда доставать тесто из холодильника и когда греть духовку, — и ему надо было откуда-то брать таймлайны и пересчёты. Логику я вынес в пару эндпоинтов на этом же домене, а потом подумал: чего ей простаивать. Так что вот, пользуйтесь. Может пригодиться, если делаете свой бот в Телеграме, плагин для умной колонки («сколько воды на полкило муки при 75%?») или маленький виджет на сайт.
Это домашний side-project, а не сервис: работает стабильно, но делаю на
коленке. Если что-то отвалилось или считает ерунду — напишите на
api@hlebushekhub.online, поправлю.
База
- Базовый URL:
https://hlebushekhub.online/api/v1/ - Авторизации нет, ключи не нужны.
- Все ответы —
application/json; charset=utf-8. - Список всех путей живьём:
GET /api/v1/index(discovery).
Пожалуйста, не злоупотребляйте. Лимит «по-доброму» — порядка
60 запросов в минуту с одного IP. Если делаете бота —
кэшируйте ответы на стороне клиента (GET-ответы и так кэшируются на 5 минут),
не дёргайте /recipes в цикле. Это домашний сервер, а не облако.
Discovery
GET /api/v1/index
Список всех доступных эндпоинтов — удобно, чтобы не лезть в эту страницу из кода.
curl https://hlebushekhub.online/api/v1/index
{
"name": "hlebushekhub bake API",
"version": "1.2",
"base": "/api/v1/",
"endpoints": [
{ "method": "GET", "path": "/api/v1/health" },
{ "method": "GET", "path": "/api/v1/version" },
{ "method": "GET", "path": "/api/v1/recipes" },
{ "method": "GET", "path": "/api/v1/recipes/{id}" },
{ "method": "POST", "path": "/api/v1/scale" },
{ "method": "POST", "path": "/api/v1/hydration" },
{ "method": "POST", "path": "/api/v1/timeline" },
{ "method": "POST", "path": "/api/v1/percentage" },
{ "method": "GET", "path": "/api/v1/flours" }
]
}
Служебные
GET /api/v1/health
Проверка, что всё живо. Для пингов из бота.
curl https://hlebushekhub.online/api/v1/health
{ "status": "ok", "version": "1.2" }
GET /api/v1/version
Версия и дата последнего обновления данных.
curl https://hlebushekhub.online/api/v1/version
{ "version": "1.2", "updated": "2026-03-15" }
Рецепты
GET /api/v1/recipes
Короткий список базовых рецептов с id, по которым берутся детали.
curl https://hlebushekhub.online/api/v1/recipes
{
"count": 3,
"recipes": [
{ "id": "tartine-basic", "name": "Базовый тартин (пшеничный бул)", "type": "wheat", "hydration": 72 },
{ "id": "rye-ruisleipa", "name": "Финский ржаной ruisleipä", "type": "rye", "hydration": 82 },
{ "id": "buckwheat-gf", "name": "Гречневый хлеб без глютена", "type": "gluten_free", "hydration": 95 }
]
}
GET /api/v1/recipes/{id}
Детали рецепта: ингредиенты в граммах и пекарских процентах, температуры, время. Доступные id: tartine-basic, rye-ruisleipa, buckwheat-gf.
curl https://hlebushekhub.online/api/v1/recipes/tartine-basic
{
"id": "tartine-basic",
"name": "Базовый тартин (пшеничный бул на закваске)",
"type": "wheat",
"yield_loaves": 1,
"total_flour_g": 500,
"hydration": 72,
"ingredients": [
{ "name": "мука пшеничная (Myllyn Paras erikoisvehnäjauho)", "grams": 450, "baker_percent": 90 },
{ "name": "мука цельнозерновая", "grams": 50, "baker_percent": 10 },
{ "name": "вода", "grams": 360, "baker_percent": 72 },
{ "name": "закваска (100%)", "grams": 100, "baker_percent": 20 },
{ "name": "соль", "grams": 10, "baker_percent": 2 }
],
"process": {
"dough_temp_c": 24,
"bulk_hours": 3.5,
"cold_proof_hours": 24,
"bake": [
{ "phase": "под крышкой", "temp_c": 250, "minutes": 20 },
{ "phase": "без крышки", "temp_c": 220, "minutes": 22 }
],
"crumb_done_c": 98
}
}
Расчёты
POST /api/v1/hydration
Считает воду по муке и проценту (или процент по муке и воде, если прислать water вместо hydration).
curl -X POST https://hlebushekhub.online/api/v1/hydration \
-H "Content-Type: application/json" \
-d '{ "flour": 500, "hydration": 75 }'
{
"flour": 500,
"hydration": 75,
"water": 375,
"total_dough_g": 885,
"note": "плюс соль и закваска в общий вес"
}
POST /api/v1/scale
Масштабирует рецепт по id на множитель. factor может быть дробным.
curl -X POST https://hlebushekhub.online/api/v1/scale \
-H "Content-Type: application/json" \
-d '{ "recipe_id": "tartine-basic", "factor": 2 }'
{
"recipe_id": "tartine-basic",
"factor": 2,
"yield_loaves": 2,
"ingredients": [
{ "name": "мука пшеничная (Myllyn Paras erikoisvehnäjauho)", "grams": 900 },
{ "name": "мука цельнозерновая", "grams": 100 },
{ "name": "вода", "grams": 720 },
{ "name": "закваска (100%)", "grams": 200 },
{ "name": "соль", "grams": 20 }
]
}
POST /api/v1/percentage
Пекарские проценты: мука = 100%, остальное от веса муки. Принимает массив ингредиентов.
curl -X POST https://hlebushekhub.online/api/v1/percentage \
-H "Content-Type: application/json" \
-d '{ "ingredients": [
{ "name": "мука", "grams": 500, "is_flour": true },
{ "name": "вода", "grams": 360 },
{ "name": "соль", "grams": 10 }
] }'
{
"total_flour_g": 500,
"result": [
{ "name": "мука", "grams": 500, "baker_percent": 100 },
{ "name": "вода", "grams": 360, "baker_percent": 72 },
{ "name": "соль", "grams": 10, "baker_percent": 2 }
],
"sum_percent": 174
}
POST /api/v1/timeline
Строит таймлайн выпечки от стартового времени по типу хлеба. type: tartine, rye, gluten_free. start_time — в ISO или HH:MM.
curl -X POST https://hlebushekhub.online/api/v1/timeline \
-H "Content-Type: application/json" \
-d '{ "type": "tartine", "start_time": "09:00" }'
{
"type": "tartine",
"start_time": "09:00",
"steps": [
{ "at": "09:00", "step": "освежить закваску" },
{ "at": "13:00", "step": "замес, автолиз 30 мин", "dough_temp_c": 24 },
{ "at": "13:30", "step": "складывания, начало брожения" },
{ "at": "17:00", "step": "предформовка и формовка" },
{ "at": "17:30", "step": "в холодильник на 24 ч", "temp_c": 4 },
{ "at": "next-day 18:00", "step": "выпечка", "temp_c": 250 }
]
}
Справочники
GET /api/v1/flours
Справочник местных мук с типом, белком и заметками — то, чем сам пользуюсь при пересчёте рецептов.
curl https://hlebushekhub.online/api/v1/flours
{
"count": 6,
"flours": [
{ "brand": "Myllyn Paras", "name": "vehnäjauho", "type": "wheat", "protein_pct": 11.0, "note": "светлая пшеничная, рабочая лошадка" },
{ "brand": "Myllyn Paras", "name": "erikoisvehnäjauho", "type": "wheat_strong", "protein_pct": 12.5, "note": "хлебопекарная, держит воду и форму" },
{ "brand": "Myllyn Paras", "name": "ruisjauho (обдирная)", "type": "rye", "protein_pct": 8.0, "note": "для ruisleipä" }
]
}
В ответе список длиннее — здесь сокращён для примера.
Ошибки
Ошибки приходят с соответствующим HTTP-кодом и телом одинакового вида:
{ "error": "описание понятным языком", "code": "MACHINE_CODE" }
| HTTP | code | Когда |
|---|---|---|
| 400 | BAD_REQUEST | кривой JSON или не хватает поля (например, нет flour) |
| 404 | NOT_FOUND | нет такого рецепта/пути (например, /recipes/borodinsky) |
| 429 | RATE_LIMITED | превышен лимит запросов, притормозите |
Пример 404:
{ "error": "рецепт не найден", "code": "NOT_FOUND" }
Лимиты
- Около 60 запросов в минуту на IP. Сверху —
429. - Тело POST — до 16 КБ, больше не нужно для пекарских задач.
- Кэшируйте на своей стороне: GET-ответы отдаются с
Cache-Control: public, max-age=300.
CORS и заголовки
Чтобы можно было дёргать из браузерного виджета, ответы отдаются с открытым CORS:
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=300 # на GET
Если делаете фронтовый виджет и упираетесь в preflight — пишите, добавлю
нужные методы в Access-Control-Allow-Methods.
Стабильность
API в бете, но версия v1 не сломается без объявления — минимум за
месяц повешу заметку здесь и в ленте, прежде чем менять формат
ответов или убирать эндпоинт. Новое поведение поедет в v2, старое
v1 поживёт параллельно. Поломки и пожелания — на
api@hlebushekhub.online.
Исходники инструмента пока в личной репке — может, выложу позже, если кому-то будет интересно. Там нечем особо гордиться, обычные формулы и немного клея.