Маленький публичный 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" }
HTTPcodeКогда
400BAD_REQUESTкривой JSON или не хватает поля (например, нет flour)
404NOT_FOUNDнет такого рецепта/пути (например, /recipes/borodinsky)
429RATE_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.

Исходники инструмента пока в личной репке — может, выложу позже, если кому-то будет интересно. Там нечем особо гордиться, обычные формулы и немного клея.